24ways

Custom SQL query returning 101 rows (hide)

rowidtitlecontentsyearauthorauthor_slugpublishedurltopic
311 Designing Imaginative Style Guides (Living) style guides and (atomic) patterns libraries are “all the rage,” as my dear old Nana would’ve said. If articles and conference talks are to be believed, making and using them has become incredibly popular. I think there are plenty of ways we can improve how style guides look and make them better at communicating design information to creatives without it getting in the way of information that technical people need. Guides to libraries of patterns Most of my consulting work and a good deal of my creative projects now involve designing style guides. I’ve amassed a huge collection of brand guidelines and identity manuals as well as, more recently, guides to libraries of patterns intended to help designers and developers make digital products and websites. Two pages from one of my Purposeful style guide packs. Designs © Stuff & Nonsense. “Style guide” is an umbrella term for several types of design documentation. Sometimes we’re referring to static style or visual identity guides, other times voice and tone. We might mean front-end code guidelines or component/pattern libraries. These all offer something different but more often than not they have something in common. They look ugly enough to have been designed by someone who enjoys configuring a router. OK, that was mean, not everyone’s going to think an unimaginative style guide design is a problem. After all, as long as a style guide contains information people need, how it looks shouldn’t matter, should it? Inspiring not encyclopaedic Well here’s the thing. Not everyone needs to take the same information away from a style guide. If you’re looking for markup and styles to code a ‘media’ component, you’re probably going to be the technical type, whereas if you need to understand the balance of sizes across a typographic hierarchy, you’re more likely to be a creative. What you need from a style guide is different. Sure, some people1 need rules: “Do this (responsive pattern)” or “don’t do that (auto-playing video.)” Those people probably also want facts: “Use this (hexadecimal value)” and not that inaccessible colour combination.” Style guides need to do more than list facts and rules. They should demonstrate a design, not just document its parts. The best style guides are inspiring not encyclopaedic. I’ll explain by showing how many style guides currently present information about colour. Colours communicate I’m sure you’ll agree that alongside typography, colour’s one of the most important ingredients in a design. Colour communicates personality, creates mood and is vital to an easily understandable interactive vocabulary. So you’d think that an average style guide would describe all this in any number of imaginative ways. Well, you’d be disappointed, because the most inspiring you’ll find looks like a collection of chips from a paint chart. Lonely Planet’s Rizzo does a great job of separating its Design Elements from UI Components, and while its ‘Click to copy’ colour values are a thoughtful touch, you’ll struggle to get a feeling for Lonely Planet’s design by looking at their colour chips. Lonely Planet’s Rizzo style guide. Lonely Planet approach is a common way to display colour information and it’s one that you’ll also find at Greenpeace, Sky, The Times and on countless more style guides. Greenpeace, Sky and The Times style guides. GOV.UK—not a website known for its creative flair—varies this approach by using circles, which I find strange as circles don’t feature anywhere else in its branding or design. On the plus side though, their designers have provided some context by categorising colours by usage such as text, links, backgrounds and more. GOV.UK style guide. Google’s Material Design offers an embarrassment of colours but most helpfully it also advises how to combine its primary and accent colours into usable palettes. Google’s Material Design. While the ability to copy colour values from a reference might be all a technical person needs, designers need to understand why particular colours were chosen as well as how to use them. Inspiration not documentation Few style guides offer any explanation and even less by way of inspiring examples. Most are extremely vague when they describe colour: “Use colour as a presentation element for either decorative purposes or to convey information.” The Government of Canada’s Web Experience Toolkit states, rather obviously. “Certain colors have inherent meaning for a large majority of users, although we recognize that cultural differences are plentiful.” Salesforce tell us, without actually mentioning any of those plentiful differences. I’m also unsure what makes the Draft U.S. Web Design Standards colours a “distinctly American palette” but it will have to work extremely hard to achieve its goal of communicating “warmth and trustworthiness” now. In Canada, “bold and vibrant” colours reflect Alberta’s “diverse landscape.” Adding more colours to their palette has made Adobe “rich, dynamic, and multi-dimensional” and at Skype, colours are “bold, colourful (obviously) and confident” although their style guide doesn’t actually provide information on how to use them. The University of Oxford, on the other hand, is much more helpful by explaining how and why to use their colours: “The (dark) Oxford blue is used primarily in general page furniture such as the backgrounds on the header and footer. This makes for a strong brand presence throughout the site. Because it features so strongly in these areas, it is not recommended to use it in large areas elsewhere. However it is used more sparingly in smaller elements such as in event date icons and search/filtering bars.” OpenTable style guide. The designers at OpenTable have cleverly considered how to explain the hierarchy of their brand colours by presenting them and their supporting colours in various size chips. It’s also obvious from OpenTable’s design which colours are primary, supporting, accent or neutral without them having to say so. Art directing style guides For the style guides I design for my clients, I go beyond simply documenting their colour palette and type styles and describe visually what these mean for them and their brand. I work to find distinctive ways to present colour to better represent the brand and also to inspire designers. For example, on a recent project for SunLife, I described their palette of colours and how to use them across a series of art directed pages that reflect the lively personality of the SunLife brand. Information about HEX and RGB values, Sass variables and when to use their colours for branding, interaction and messaging is all there, but in a format that can appeal to both creative and technical people. SunLife style guide. Designs © Stuff & Nonsense. Purposeful style guides If you want to improve how you present colour information in your style guides, there’s plenty you can do. For a start, you needn’t confine colour information to the palette page in your style guide. Find imaginative ways to display colour across several pages to show it in context with other parts of your design. Here are two CSS gradient filled ‘cover’ pages from my Purposeful style sheets. Colour impacts other elements too, including typography, so make sure you include colour information on those pages, and vice-versa. Purposeful. Designs © Stuff & Nonsense. A visual hierarchy can be easier to understand than labelling colours as ‘primary,’ ‘supporting,’ or ‘accent,’ so find creative ways to present that hierarchy. You might use panels of different sizes or arrange boxes on a modular grid to fill a page with colour. Don’t limit yourself to rectangular colour chips, use circles or other shapes created using only CSS. If irregular shapes are a part of your brand, fill SVG silhouettes with CSS and then wrap text around them using CSS shapes. Purposeful. Designs © Stuff & Nonsense. Summing up In many ways I’m as frustrated with style guide design as I am with the general state of design on the web. Style guides and pattern libraries needn’t be dull in order to be functional. In fact, they’re the perfect place for you to try out new ideas and technologies. There’s nowhere better to experiment with new properties like CSS Grid than on your style guide. The best style guide designs showcase new approaches and possibilities, and don’t simply document the old ones. Be as creative with your style guide designs as you are with any public-facing part of your website. Purposeful are HTML and CSS style guides templates designed to help you develop creative style guides and pattern libraries for your business or clients. Save time while impressing your clients by using easily customisable HTML and CSS files that have been designed and coded to the highest standards. Twenty pages covering all common style guide components including colour, typography, buttons, form elements, and tables, plus popular pattern library components. Purposeful style guides will be available to buy online in January. Boring people ↩ 2016 Andy Clarke andyclarke 2016-12-13T00:00:00+00:00 https://24ways.org/2016/designing-imaginative-style-guides/ design
67 What I Learned about Product Design This Year 2015 was a humbling year for me. In September of 2014, I joined a tiny but established startup called SproutVideo as their third employee and first designer. The role interests me because it affords the opportunity to see how design can grow a solid product with a loyal user-base into something even better. The work I do now could also have a real impact on the brand and user experience of our product for years to come, which is a thrilling prospect in an industry where much of what I do feels small and temporary. I got in on the ground floor of something special: a small, dedicated, useful company that cares deeply about making video hosting effortless and rewarding for our users. I had (and still have) grand ideas for what thoughtful design can do for a product, and the smaller-scale product design work I’ve done or helped manage over the past few years gave me enough eager confidence to dive in head first. Readers who have experience redesigning complex existing products probably have a knowing smirk on their face right now. As I said, it’s been humbling. A year of focused product design, especially on the scale we are trying to achieve with our small team at SproutVideo, has taught me more than any projects in recent memory. I’d like to share a few of those lessons. Product design is very different from marketing design The majority of my recent work leading up to SproutVideo has been in marketing design. These projects are so fun because their aim is to communicate the value of the product in a compelling and memorable way. In order to achieve this goal, I spent a lot of time thinking about content strategy, responsive design, and how to create striking visuals that tell a story. These are all pursuits I love. Product design is a different beast. When designing a homepage, I can employ powerful imagery, wild gradients, and somewhat-quirky fonts. When I began redesigning the SproutVideo product, I wanted to draw on all the beautiful assets I’ve created for our marketing materials, but big gradients, textures, and display fonts made no sense in this new context. That’s because the product isn’t about us, and it isn’t about telling our story. Product design is about getting out of the way so people can do their job. The visual design is there to create a pleasant atmosphere for people to work in, and to help support the user experience. Learning to take “us” out of the equation took some work after years of creating gorgeous imagery and content for the sales-driven side of businesses. I’ve learned it’s very valuable to design both sides of the experience, because marketing and product design flex different muscles. If you’re currently in an environment where the two are separate, consider switching teams in 2016. Designing for product when you’ve mostly done marketing, or vice versa, will deepen your knowledge as a designer overall. You’ll face new unexpected challenges, which is the only way to grow. Product design can not start with what looks good on Dribbble I have an embarrassing confession: when I began the redesign, I had a secret goal of making something that would look gorgeous in my portfolio. I have a collection of product shots that I admire on Dribbble; examples of beautiful dashboards and widgets and UI elements that look good enough to frame. I wanted people to feel the same way about the final outcome of our redesign. Mistakenly, this was a factor in my initial work. I opened Photoshop and crafted pixel-perfect static buttons and form elements and color palettes that — when applied to our actual product — looked like a toddler beauty pageant. It added up to a lot of unusable shininess, noise, and silliness. I was disappointed; these elements seemed so lovely in isolation, but in context, they felt tacky and overblown. I realized: I’m not here to design the world’s most beautiful drop down menu. Good design has nothing to do with ego, but in my experience designers are, at least a little bit, secret divas. I’m no exception. I had to remind myself that I am not working in service of a bigger Dribbble following or to create the most Pinterest-ing work. My function is solely to serve the users — to make life a little better for the good people who keep my company in business. This meant letting go of pixel-level beauty to create something bigger and harder: a system of elements that work together in harmony in many contexts. The visual style exists to guide the users. When done well, it becomes a language that users understand, so when they encounter a new feature or have a new goal, they already feel comfortable navigating it. This meant stripping back my gorgeous animated menu into something that didn’t detract from important neighboring content, and could easily fit in other parts of the app. In order to know what visual style would support the users, I had to take a wider view of the product as a whole. Just accept that designing a great product – like many worthwhile pursuits – is initially laborious and messy Once I realized I couldn’t start by creating the most Dribbble-worthy thing, I knew I’d have to begin with the unglamorous, frustrating, but weirdly wonderful work of mapping out how the product’s content could better be structured. Since we’re redesigning an existing product, I assumed this would be fairly straightforward: the functionality was already in place, and my job was just to structure it in a more easily navigable way. I started by handing off a few wireframes of the key screens to the developer, and that’s when the questions began rolling in: “If we move this content into a modal, how will it affect this similar action here?” “What happens if they don’t add video tags, but they do add a description?” “What if the user has a title that is 500 characters long?” “What if they want their video to be private to some users, but accessible to others?”. How annoying (but really, fantastic) that people use our product in so many ways. Turns out, product design isn’t about laying out elements in the most ideal scenario for the user that’s most convenient for you. As product designers, we have to foresee every outcome, and anticipate every potential user need. Which brings me to another annoying epiphany: if you want to do it well, and account for every user, product design is so much more snarly and tangled than you’d expect going in. I began with a simple goal: to improve the experience on just one of our key product pages. However, every small change impacts every part of the product to some degree, and that impact has to be accounted for. Every decision is based on assumptions that have to be tested; I test my assumptions by observing users, talking to the team, wireframing, and prototyping. Many of my assumptions are wrong. There are days when it’s incredibly frustrating, because an elegant solution for users with one goal will complicate life for users with another goal. It’s vital to solve as many scenarios as possible, even though this is slow, sometimes mind-bending work. As a side bonus, wireframing and prototyping every potential state in a product is tedious, but your developers will thank you for it. It’s not their job to solve what happens when there’s an empty state, error, or edge case. Showing you’ve accounted for these scenarios will win a developer’s respect; failing to do so will frustrate them. When you’ve created and tested a system that supports user needs, it will be beautiful Remember what I said in the beginning about wanting to create a Dribbble-worthy product? When I stopped focusing on the visual details of the design (color, spacing, light and shadow, font choices) and focused instead on structuring the content to maximize usability and delight, a beautiful design began to emerge naturally. I began with grayscale, flat wireframes as a strategy to keep me from getting pulled into the visual style before the user experience was established. As I created a system of elements that worked in harmony, the visual style choices became obvious. Some buttons would need to be brighter and sit off the page to help the user spot important actions. Some elements would need line separators to create a hierarchy, where others could stand on their own as an emphasized piece of content. As the user experience took shape, the visual style emerged naturally to support it. The result is a product that feels beautiful to use, because I was thoughtful about the experience first. A big takeaway from this process has been that my assumptions will often be proven wrong. My assumptions about how to design a great product, and how users will interact with that product, have been tested and revised repeatedly. At SproutVideo we’re about to undertake the biggest test of our work; we’re going to launch a small part of the product redesign to our users. If I’ve learned anything, it’s that I will continue to be humbled by the ongoing effort of making the best product I can, which is a wonderful thing. Next year, I hope you all get to do work that takes you out of our comfort zone. Be regularly confounded and embarrassed by your wrong assumptions, learn from them, and come back and tell us what you learned in 2016. 2015 Meagan Fisher meaganfisher 2015-12-14T00:00:00+00:00 https://24ways.org/2015/what-i-learned-about-product-design-this-year/ design
46 Responsive Enhancement 24 ways has been going strong for ten years. That’s an aeon in internet timescales. Just think of all the changes we’ve seen in that time: the rise of Ajax, the explosion of mobile devices, the unrecognisably changed landscape of front-end tooling. Tools and technologies come and go, but one thing has remained constant for me over the past decade: progressive enhancement. Progressive enhancement isn’t a technology. It’s more like a way of thinking. Instead of thinking about the specifics of how a finished website might look, progressive enhancement encourages you to think about the fundamental meaning of what the website is providing. So instead of thinking of a website in terms of its ideal state in a modern browser on a nice widescreen device, progressive enhancement allows you to think about the core functionality in a more abstract way. Once you’ve figured out what the core functionality is – adding an item to a shopping cart, posting a message, sharing a photo – then you can enable that functionality in the simplest possible way. That usually means starting with good old-fashioned HTML. Links and forms are often all you need. Then, once you have the core functionality working in a basic way, you can start to enhance to make a progressively better experience for more modern browsers. The advantage of working this way isn’t just that your site will work in older browsers (albeit in a rudimentary way). It also ensures that if anything goes wrong in a modern browser, it won’t be catastrophic. There’s a common misconception that progressive enhancement means that you’ll spend your time dealing with older browsers, but in fact the opposite is true. Putting the basic functionality into place doesn’t take very long at all. And once you’ve done that, you’re free to spend all your time experimenting with the latest and greatest browser technologies, secure in the knowledge that even if they aren’t universally supported yet, that’s OK: you’ve already got your fallback in place. The key to thinking about web development this way is realising that there isn’t one final interface – there could be many, slightly different interfaces depending on the properties and capabilities of any particular user agent at any particular moment. And that’s OK. Websites do not need to look the same in every browser. Once you truly accept that, it’s an immensely liberating idea. Instead of spending your time trying to make websites look the same in wildly varying browsers, you can spend your time making sure that the core functionality of what you build works everywhere, while providing the best possible experience for more capable browsers. Allow me to demonstrate with a simple example: navigation. Step one: core functionality Let’s say we have a straightforward website about the twelve days of Christmas, with a page for each day. The core functionality is pretty clear: To read about any particular day. To browse from day to day. The first is easily satisfied by marking up the text with headings, paragraphs and all the usual structural HTML elements. The second is satisfied by providing a list of good ol’ hyperlinks. Now where’s the best place to position this navigation list? Personally, I’m a big fan of the jump-to-footer pattern. This puts the content first and the navigation second. At the top of the page there’s a link with an href attribute pointing to the fragment identifier for the navigation. <body> <main role="main" id="top"> <a href="#menu" class="control">Menu</a> ... </main> <nav role="navigation" id="menu"> ... <a href="#top" class="control">Dismiss</a> </nav> </body> See the footer-anchor pattern in action. Because it’s nothing more than a hyperlink, this works in just about every browser since the dawn of the web. Following hyperlinks is what web browsers were made to do (hence the name). Step two: layout as an enhancement The footer-anchor pattern is a particularly neat solution on small-screen devices, like mobile phones. Once more screen real estate is available, I can use the magic of CSS to reposition the navigation above the content. I could use position: absolute, flexbox or, in this case, display: table. @media all and (min-width: 35em) { .control { display: none; } body { display: table; } [role="navigation"] { display: table-caption; columns: 6 15em; } } See the styles for wider screens in action Step three: enhance! Right. At this point I’m providing core functionality to everyone, and I’ve got nice responsive styles for wider screens. I could stop here, but the real advantage of progressive enhancement is that I don’t have to. From here on, I can go crazy adding all sorts of fancy enhancements for modern browsers, without having to worry about providing a fallback for older browsers – the fallback is already in place. What I’d really like is to provide a swish off-canvas pattern for small-screen devices. Here’s my plan: Position the navigation under the main content. Listen out for the .control links being activated and intercept that action. When those links are activated, toggle a class of .active on the body. If the .active class exists, slide the content out to reveal the navigation. Here’s the CSS for positioning the content and navigation: @media all and (max-width: 35em) { [role="main"] { transition: all .25s; width: 100%; position: absolute; z-index: 2; top: 0; right: 0; } [role="navigation"] { width: 75%; position: absolute; z-index: 1; top: 0; right: 0; } .active [role="main"] { transform: translateX(-75%); } } In my JavaScript, I’m going to listen out for any clicks on the .control links and toggle the .active class on the body accordingly: (function (win, doc) { 'use strict'; var linkclass = 'control', activeclass = 'active', toggleClassName = function (element, toggleClass) { var reg = new RegExp('(s|^)' + toggleClass + '(s|$)'); if (!element.className.match(reg)) { element.className += ' ' + toggleClass; } else { element.className = element.className.replace(reg, ''); } }, navListener = function (ev) { ev = ev || win.event; var target = ev.target || ev.srcElement; if (target.className.indexOf(linkclass) !== -1) { ev.preventDefault(); toggleClassName(doc.body, activeclass); } }; doc.addEventListener('click', navListener, false); }(this, this.document)); I’m all set, right? Not so fast! Cutting the mustard I’ve made the assumption that addEventListener will be available in my JavaScript. That isn’t a safe assumption. That’s because JavaScript – unlike HTML or CSS – isn’t fault-tolerant. If you use an HTML element or attribute that a browser doesn’t understand, or if you use a CSS selector, property or value that a browser doesn’t understand, it’s no big deal. The browser will just ignore what it doesn’t understand: it won’t throw an error, and it won’t stop parsing the file. JavaScript is different. If you make an error in your JavaScript, or use a JavaScript method or property that a browser doesn’t recognise, that browser will throw an error, and it will stop parsing the file. That’s why it’s important to test for features before using them in JavaScript. That’s also why it isn’t safe to rely on JavaScript for core functionality. In my case, I need to test for the existence of addEventListener: (function (win, doc) { if (!win.addEventListener) { return; } ... }(this, this.document)); The good folk over at the BBC call this kind of feature test cutting the mustard. If a browser passes the test, it cuts the mustard, and so it gets the enhancements. If a browser doesn’t cut the mustard, it doesn’t get the enhancements. And that’s fine because, remember, websites don’t need to look the same in every browser. I want to make sure that my off-canvas styles are only going to apply to mustard-cutting browsers. I’m going to use JavaScript to add a class of .cutsthemustard to the document: (function (win, doc) { if (!win.addEventListener) { return; } ... var enhanceclass = 'cutsthemustard'; doc.documentElement.className += ' ' + enhanceclass; }(this, this.document)); Now I can use the existence of that class name to adjust my CSS: @media all and (max-width: 35em) { .cutsthemustard [role="main"] { transition: all .25s; width: 100%; position: absolute; z-index: 2; top: 0; right: 0; } .cutsthemustard [role="navigation"] { width: 75%; position: absolute; z-index: 1; top: 0; right: 0; } .cutsthemustard .active [role="main"] { transform: translateX(-75%); } } See the enhanced mustard-cutting off-canvas navigation. Remember, this only applies to small screens so you might have to squish your browser window. Enhance all the things! This was a relatively simple example, but it illustrates the thinking behind progressive enhancement: once you’re providing the core functionality to everyone, you’re free to go crazy with all the latest enhancements for modern browsers. Progressive enhancement doesn’t mean you have to provide all the same functionality to everyone – quite the opposite. That’s why it’s key to figure out early on what the core functionality is, and make sure that it can be provided with the most basic technology. But from that point on, you’re free to add many more features that aren’t mission-critical. You should reward more capable browsers by giving them more of those features, such as animation in CSS, geolocation in JavaScript, and new input types in HTML. Like I said, progressive enhancement isn’t a technology. It’s a way of thinking. Once you start thinking this way, you’ll be prepared for whatever the next ten years throws at us. 2014 Jeremy Keith jeremykeith 2014-12-09T00:00:00+00:00 https://24ways.org/2014/responsive-enhancement/ code
69 How to Do a UX Review A UX review is where an expert goes through a website looking for usability and experience problems and makes recommendations on how to fix them. I’ve completed a number of UX reviews over my twelve years working as a user experience consultant and I thought I’d share my approach. I’ll be talking about reviewing websites here; you can adapt the approach for web apps, or mobile or desktop apps. Why conduct a review Typically, a client asks for a review to be undertaken by a trusted and, ideally, detached third party who either works for an agency or is a freelancer. Often they may ask a new member of the UX team to complete one, or even set it as a task for a job interview. This indicates the client is looking for an objective view, seen from the outside as a user would see the website. I always suggest conducting some user research rather than a review. Users know their goals and watching them make (what you might think of as) mistakes on the website is invaluable. Conducting research with six users can give you six hours’ worth of review material from six viewpoints. In short, user research can identify more problems and show how common those problems might be. There are three reasons, though, why a review might better suit client needs than user research: Quick results: user research and analysis takes at least three weeks. Limited budget: the £6–10,000 cost to run user research is about twice the cost of a UX review. Users are hard to reach: in the business-to-business world, reaching users is difficult, especially if your users hold senior positions in their organisations. Working with consumers is much easier as there are often more of them. There is some debate about the benefits of user research over UX review. In my experience you learn far more from research, but opinions differ. Be objective The number one mistake many UX reviewers make is reporting back the issues they identify as their opinion. This can cause credibility problems because you have to keep justifying why your opinion is correct. I’ve had the most success when giving bad news in a UX review and then finally getting things fixed when I have been as objective as possible, offering evidence for why something may be a problem. To be objective we need two sources of data: numbers from analytics to appeal to reason; and stories from users in the form of personas to speak to emotions. Highlighting issues with dispassionate numerical data helps show the extent of the problem. Making the problems more human using personas can make the problem feel more real. Numbers from analytics The majority of clients I work with use Google Analytics, but if you use a different analytics package the same concepts apply. I use analytics to find two sets of things. 1. Landing pages and search terms Landing pages are the pages users see first when they visit a website – more often than not via a Google search. Landing pages reveal user goals. If a user landed on a page called ‘Yellow shoes’ their goal may well be to find out about or buy some yellow shoes. It would be great to see all the search terms bringing people to the website but in 2011 Google stopped providing search term data to (rightly!) protect users’ privacy. You can get some search term data from Google Webmaster tools, but we must rely on landing pages as a clue to our users’ goals. The thing to look for is high-traffic landing pages with a high bounce rate. Bounce rate is the percentage of visitors to a website who navigate away from the site after viewing only one page. A high bounce rate (over 50%) isn’t good; above 70% is bad. To get a list of high-traffic landing pages with a high bounce rate install this bespoke report. Google Analytics showing landing pages ordered by popularity and the bounce rate for each. This is the list of pages with high demand and that have real problems as the bounce rate is high. This is the main focus of the UX review. 2. User flows We have the beginnings of the user journey: search terms and initial landing pages. Now we can tap into the really useful bit of Google Analytics. Called behaviour flows, they show the most common order of pages visited. Behaviour flows from Google Analytics, showing the routes users took through the website. Here we can see the second and third (and so on) pages users visited. Importantly, we can also see the drop-outs at each step. If your client has it set up, you can also set goal pages (for example, a post-checkout contact us and thank you page). You can then see a similar view that tracks back from the goal pages. If your client doesn’t have this, suggest they set up goal tracking. It’s easy to do. We now have the remainder of the user journey. A user journey Expect the work in analytics to take up to a day. We may well identify more than one user journey, starting from different landing pages and going to different second- and third-level pages. That’s a good thing and shows we have different user types. Talking of user types, we need to define who our users are. Personas We have some user journeys and now we need to understand more about our users’ motivations and goals. I have a love-hate relationship with personas, but used properly these portraits of users can help bring a human touch to our UX review. I suggest using a very cut-down view of a persona. My old friends Steve Cable and Richard Caddick at cxpartners have a great free template for personas from their book Communicating the User Experience. The first thing to do is find a picture that represents that persona. Don’t use crappy stock photography – it’s sometimes hard to relate to perfect-looking people) – use authentic-looking people. Here’s a good collection of persona photos. An example persona. The personas have three basic attributes: Goals: we can complete these drawing on the analytics data we have (see example). Musts: things we have to do to meet the persona’s needs. Must nots: a list of things we really shouldn’t do. Completing points 2 and 3 can often be done during the writing of the report. Let’s take an example. We know that the search term ‘yellow shoes’ takes the user to the landing page for yellow shoes. We also know this page has a high bounce rate, meaning it doesn’t provide a good experience. With our expert hat on we can review the page. We will find two types of problem: Usability issues: ineffective button placement or incorrect wording, links not looking like links, and so on. Experience issues: for example, if a product is out of stock we have to contact the business to ask them to restock. That link is very small and hard to see. We could identify that the contact button isn’t easy to find (a usability issue) but that’s not the real problem here. That the user has to ask the business to restock the item is a bad user experience. We add this to our personas’ must nots. The big experience problems with the site form the musts and must nots for our personas. We now have a story around our user journey that highlights what is going wrong. If we’ve identified a number of user journeys, multiple landing pages and differing second and third pages visited, we can create more personas to match. A good rule of thumb is no more than three personas. Any more and they lose impact, watering down your results. Expect persona creation to take up to a day to complete. Let’s start the review We take the user journeys and we follow them step by step, working through the website looking for the reasons why users drop out at each step. Using Keynote or PowerPoint, I structure the final report around the user journey with separate sections for each step. For each step we’ll find both usability and experience problems. Split the results into those two groups. Usability problems are fairly easy to fix as they’re often quick design changes. As you go along, note the usability problems in one place: we’ll call this ‘quick wins’. Simple quick fixes are a reassuring thing for a client to see and mean they can get started on stuff right away. You can mark the severity of usability issues. Use a scale from 1 to 3 (if you use 1 to 5 everything ends up being a 3!) where 1 is minor and 3 is serious. Review the website on the device you’d expect your persona to use. Are they using the site on a smartphone? Review it on a smartphone. I allow one page or slide per problem, which allows me to explain what is going wrong. For a usability problem I’ll often make a quick wireframe or sketch to explain how to address it. A UX review slide displaying all the elements to be addressed. These slides may be viewed from across the room on a screen so zoom into areas of discussion. (Quick tip: if you use Google Chrome, try Awesome Screenshot to capture screens.) When it comes to the more severe experience problems – things like an online shop not offering next day delivery, or a business that needs to promise to get back to new customers within a few hours – these will take more than a tweak to the UI to fix. Call these something different. I use the terms like business challenges and customer experience issues as they show that it will take changes to the organisation and its processes to address them. It’s often beyond the remit of a humble UX consultant to recommend how to fix organisational issues, so don’t try. Again, create a page within your document to collect all of the business challenges together. Expect the review to take between one and three days to complete. The final report should follow this structure: The approach Overview of usability quick wins Overview of experience issues Overview of Google Analytics findings The user journeys The personas Detailed page-by-page review (broken down by steps on the user journey) There are two academic theories to help with the review. Heuristic evaluation is a set of criteria to organise the issues you find. They’re great for categorising the usability issues you identify but in practice they can be quite cumbersome to apply. I prefer the more scientific and much simpler cognitive walkthrough that is focused on goals and actions. A workshop to go through the findings The most important part of the UX review process is to talk through the issues with your client and their team. A document can only communicate a certain amount. Conversations about the findings will help the team understand the severity of the issues you’ve uncovered and give them a chance to discuss what to do about them. Expect the workshop to last around three hours. When presenting the report, explain the method you used to conduct the review, the data sources, personas and the reasoning behind the issues you found. Start by going through the usability issues. Often these won’t be contentious and you can build trust and improve your credibility by making simple, easy to implement changes. The most valuable part of the workshop is conversation around each issue, especially the experience problems. The workshop should include time to talk through each experience issue and how the team will address it. I collect actions on index cards throughout the workshop and make a note of who will take what action with each problem. Index cards showing the problem and who is responsible. When talking through the issues, the person who designed the site is probably in the room – they may well feel threatened. So be nice. When I talk through the report I try to have strong ideas, weakly held. At the end of the workshop you’ll have talked through each of the issues and identified who is responsible for addressing them. To close the workshop I hand out the cards to the relevant people, giving them a physical reminder of the next steps they have to take. That’s my process for conducting a review. I’d love to hear any tips you have in the comments. 2015 Joe Leech joeleech 2015-12-03T00:00:00+00:00 https://24ways.org/2015/how-to-do-a-ux-review/ ux
142 Revealing Relationships Can Be Good Form A few days ago, a colleague of mine – someone I have known for several years, who has been doing web design for several years and harks back from the early days of ZDNet – was running through a prototype I had put together for some user testing. As with a lot of prototypes, there was an element of ‘smoke and mirrors’ to make things look like they were working. One part of the form included a yes/no radio button, and selecting the Yes option would, in the real and final version of the form, reveal some extra content. Rather than put too much JavaScript in the prototype, I took a preverbial shortcut and created a link which I wrapped around the text next to the radio button – clicking on that link would cause the form to mimic a change event on the radio button. But it wasn’t working for him. Why was that? Because whereas I created the form using a <label> tag for each <input> and naturally went to click on the text rather than the form control itself, he was going straight for the control (and missing the sneaky little <a href> I’d placed around the text). Bah! There goes my time-saver. So, what did I learn? That a web professional who has used the Internet for years had neither heard of the <label> tag, nor had he ever tried clicking on the text. It just goes to show that despite its obvious uses, the label element is not as well known as it rightfully deserves to be. So, what’s a web-standards-loving guy to do? Make a bit more bleedin’ obvious, that’s what! The Mouse Pointer Trick OK, this is the kind of thing that causes some people outrage. A dead simple way of indicating that the label does something is to use a snippet of CSS to change the default mouse cursor to a hand. It’s derided because the hand icon is usually used for links, and some would argue that using this technique is misleading: label { cursor: pointer; } This is not a new idea, though, and you didn’t come here for this. The point is that with something very simple, you’ve made the label element discoverable. But there are other ways that you can do this that are web standards friendly and won’t upset the purists quite so much as the hand/pointer trick. Time to wheel in the JavaScript trolley jack … Our Old Friend AddEvent First things, first, you’ll need to use the addEvent function (or your favourite variation thereof) that Scott Andrew devised and make that available to the document containing the form: function addEvent(elm, evType, fn, useCapture) { if(elm.addEventListener) { elm.addEventListener(evType, fn, useCapture); return true; } else if (elm.attachEvent) { var r = elm.attachEvent('on' + evType, fn); return r; } else { elm['on' + evType] = fn; } } Finding All Your Labels Once you’ve linked to the addEvent function (or embedded it on the page), you can start to get your JavaScripting fingers a-flexing. Now, what I’m suggesting you do here is: Identify all the label elements on the page by working your way through the DOM Find out the value of the for attribute for each label that you uncover Attach a behaviour or two to each of those label elements – and to the input that the label relates to (identified with the for attribute) Here’s the technobabble version of the steps above: function findLabels() { var el = document.getElementsByTagName("label"); for (i=0;i<el.length;i++) { var thisId = el[i].getAttribute("for"); if ((thisId)==null) { thisId = el[i].htmlFor; } if(thisId!="") { //apply these behaviours to the label el[i].onmouseover = highlightRelationship; el[i].onmouseout = hideRelationship; } } } function highlightRelationship() { var thisId = this.getAttribute("for"); if ((thisId)==null) { thisId = this.htmlFor; } this.className="showRel"; document.getElementById(thisId).className="showRel"; //if (document.getElementById(thisId).type=="text") document.getElementById(thisId).select(); } function hideRelationship() { var thisId = this.getAttribute("for"); if ((thisId)==null) { thisId = this.htmlFor; } this.className=""; document.getElementById(thisId).className=""; } addEvent(window, 'load', findLabels, false); Using the above script, you can apply a CSS class (I’ve called it showRel) to the elements when you hover over them. How you want it to look is up to you, of course. Here are a few examples of the idea. Note: the design is not exactly what you’d call ‘fancy’, and in the examples there is one input that looks broken but it is deliberately moved away from the label it relates to, just to demonstrate that you can show the relationship even from afar. Background colour changes on hover Background colour change + mouse pointer trick Background colour change + mouse pointer trick + text selection Hopefully you’ll agree that using an unobtrusive piece of JavaScript you can make otherwise ‘shy’ elements like the label reveal their true colours. Although you might want to tone down the colours from the ones I’ve used in this demo! 2006 Ian Lloyd ianlloyd 2006-12-13T00:00:00+00:00 https://24ways.org/2006/revealing-relationships-can-be-good-form/ ux
4 Credits and Recognition A few weeks ago, I saw a friendly little tweet from a business congratulating a web agency on being nominated for an award. The business was quite happy for them and proud to boot — they commented on how the same agency designed their website, too. What seemed like a nice little shout-out actually made me feel a little disappointed. Why? In reality, I knew that the web agency didn’t actually design the site — I did, when I worked at a different agency responsible for the overall branding and identity. I certainly wasn’t disappointed at the business — after all, saying that someone designed your site when they were responsible for development is an easy mistake to make. Chances are, the person behind the tweets and status updates might not even know the difference between words like design and development. What really disappointed me was the reminder of how many web workers out there never explain their roles in a project when displaying work in a portfolio. If you’re strictly a developer and market yourself as such, there might be less room for confusion, but things can feel a little deceptive if you offer a wide range of services yet never credit the other players when collaboration is part of the game. Unfortunately, this was the case in this situation. Whatever happened to credit where credit’s due? Advertising attribution Have you ever thumbed through an advertising annual or browsed through the winners of an advertising awards website, like the campaign below from Kopenhagen Chocolate on Advertising Age? If so, it’s likely that you’ve noticed some big differences in how the work is credited. Everyone involved in a creative advertising project is mentioned. Art directors, writers, creative directors, photographers, illustrators and, of course, the agency all get a fair shot at fifteen minutes of fame. Why can’t we take this same idea and introduce it to our own showcases? Crediting on client sites Ah, the good old days of web rings, guestbooks, and under construction GIFs, when slipping in a cheeky “designed by” link in the footer of your masterpiece was just another common practice. These days most clients, especially larger companies and corporations, aren’t willing to have any names on their site except their own. If you’d still like to leave a little proof of authorship on a website, consider adding a humans.txt file to the root of the site and, if possible, add an author tag in the <head> of the site: <link type="text/plain" rel="author" href="http://domain/humans.txt"> It’s a great way to add more detailed information than just a meta name without being intrusive. The example on the humanstxt.org website serves to act as a guideline, but how much detail you add is completely up to you and your team. Part of the humans.txt file on humanstxt.org Alternatively, you can use the HTML5 rel="author" attribute to link to information about the author of the page in the form of a mailto: address, a link to a contact form, or a separate authors page. Crediting in portfolios While humans.txt is a great approach when you’re authoring a site, it’s even more important to clearly define your role in your own portfolio. While I believe it’s proper etiquette to include the names of folks you collaborated with, sometimes it might not be necessary (or even possible) to list every single person, especially if you’ve worked with a large agency. “Fake it till you make it” is not a term that should apply to your portfolio. Clearly stating your own responsibilities means that nobody else browsing your work samples will assume that you did more than your actual share, and being ambiguous about your role isn’t fair to yourself, or others. Before adding any work to your portfolio, ensure that you have permission from your client. Even if you included a clause in your contract about being allowed to post your work online, it’s always best to double-check. Sometimes you might not know if your work has been officially launched, and leaking something before it’s ready is bound to make a client frown. Examples There are plenty of portfolios out there that we can use for inspiration. Here are some examples that I like from other folks in the web industry: Anna Debenham In her portfolio, Anna outlines her responsibilities and those of others. In the description, Anna clearly explains her duties of doing the HTML and CSS, along with performing research and testing the prototype in schools. She also credits Laura Kalbag for the design work. Naomi Atkinson Design The work portfolio of Naomi Atkinson Design is short and to the point — they were responsible for the iPhone app design and IA for Artspotter. The portfolio of Naomi Atkinson Design states clearly what they did. Amber Weinberg Amber Weinberg is strictly a developer, but a potential client could see her portfolio and assume she might be a designer as well. To avoid any misunderstandings, she states her roles up front in a section called “What I Did,” supported by examples of her code. Amber Weinberg sets out all her roles in each of her portfolio’s case studies. What if someone doesn’t want to be credited? Let’s face it — we’ve all been there. A project, for whatever reason, turns out to be an absolute disaster and we don’t feel like it’s an accurate representation of the quality of our work. If you’re crediting someone else but suspect they might rather pretend it never happened, be sure to drop them a line and ask if they’d like to be included. And, if someone contacts you and asks to remove their name, don’t feel offended — just politely remove it. Get updating! Now that the holiday season is almost here, many of you might be planning to set aside some time for personal projects. Grab yourself a gingerbread latte and get those portfolios up to date. Remember, It doesn’t have to be long-winded, just honest. Happy holidays! 2013 Geri Coady gericoady 2013-12-16T00:00:00+00:00 https://24ways.org/2013/credits-and-recognition/ process
48 A Holiday Wish A friend and I were talking the other day about why clients spend more on toilet cleaning than design, and how the industry has changed since the mid-1990s, when we got our starts. Early in his career, my friend wrote a fine CSS book, but for years he has called himself a UX designer. And our conversation got me thinking about how I reacted to that title back when I first started hearing it. “Just what this business needs,” I said to myself, “another phony expert.” Okay, so I was wrong about UX, but my touchiness was not altogether unfounded. In the beginning, our industry was divided between freelance jack-of-all-trade punks, who designed and built and coded and hosted and Photoshopped and even wrote the copy when the client couldn’t come up with any, and snot-slick dot-com mega-agencies that blew up like Alice and handed out titles like impoverished nobles in the years between the world wars. I was the former kind of designer, a guy who, having failed or just coasted along at a cluster of other careers, had suddenly, out of nowhere, blossomed into a web designer—an immensely curious designer slash coder slash writer with a near-insatiable lust to shave just one more byte from every image. We had modems back then, and I dreamed in sixteen colors. My source code was as pretty as my layouts (arguably prettier) and I hoovered up facts and opinions from newsgroups and bulletin boards as fast as any loudmouth geek could throw them. It was a beautiful life. But soon, too soon, the professional digital agencies arose, buying loft buildings downtown, jacking in at T1 speeds, charging a hundred times what I did, and communicating with their clients in person, in large artfully bedecked rooms, wearing hand-tailored Barney’s suits and bringing back the big city bullshit I thought I’d left behind when I quit advertising to become a web designer. Just like the big bad ad agencies of my early career, the new digital agencies stocked every meeting with a totem pole worth of ranks and titles. If the client brought five upper middle managers to the meeting, the agency did likewise. If fifteen stakeholders got to ask for a bigger logo, fifteen agency personnel showed up to take notes on the percentage of enlargement required. But my biggest gripe was with the titles. The bigger and more expensive the agency, the lousier it ran with newly invented titles. Nobody was a designer any more. Oh, no. Designer, apparently, wasn’t good enough. Designer was not what you called someone you threw that much money at. Instead of designers, there were user interaction leads and consulting middleware integrators and bilabial experience park rangers and you name it. At an AIGA Miami event where I was asked to speak in the 1990s, I once watched the executive creative director of the biggest dot-com agency of the day make a presentation where he spent half his time bragging that the agency had recently shaved down the number of titles for people who basically did design stuff from forty-six to just twenty-three—he presented this as though it were an Einsteinian coup—and the other half of his time showing a film about the agency’s newly opened branch in Oslo. The Oslo footage was shot in December. I kept wondering which designer in the audience who lived in the constant breezy balminess of Miami they hoped to entice to move to dark, wintry Norway. But I digress. Shortly after I viewed this presentation, the dot-com world imploded, brought about largely by the euphoric excess of the agencies and their clients. But people still needed websites, and my practice flourished—to the point where, in 1999, I made the terrifying transition from guy in his underwear working freelance out of his apartment to head of a fledgling design studio. (Note: you never stop working on that change.) I had heard about experience design in the 1990s, but assumed it was a gig for people who only knew one font. But sometime around 2004 or 2005, among my freelance and small-studio colleagues, like a hobbit in the Shire, I began hearing whispers in the trees of a new evil stirring. The fires of Mordor were burning. Web designers were turning in their HTML editing tools and calling themselves UXers. I wasn’t sure if they pronounced it “uck-sir,” or “you-ex-er,” but I trusted their claims to authenticity about as far as I trusted the actors in a Doctor Pepper commercial when they claimed to be Peppers. I’m an UXer, you’re an UXer, wouldn’t you like to be an UXer too? No thanks, said I. I still make things. With my hands. Such was my thinking. I may have earned an MFA at the end of some long-past period of soul confusion, but I have working-class roots and am profoundly suspicious of, well, everything, but especially of anything that smacks of pretense. I got exporting GIFs. I didn’t get how white papers and bullet points helped anybody do anything. I was wrong. And gradually I came to know I was wrong. And before other members of my tribe embraced UX, and research, and content strategy, and the other airier consultant services, I was on board. It helped that my wife of the time was a librarian from Michigan, so I’d already bought into the cult of information architecture. And if I wasn’t exactly the seer who first understood how borderline academic practices related to UX could become as important to our medium and industry as our craft skills, at least I was down a lot faster than Judd Apatow got with feminism. But I digress. I love the web and all the people in it. Today I understand design as a strategic practice above all. The promise of the web, to make all knowledge accessible to all people, won’t be won by HTML5, WCAG 2, and responsive web design alone. We are all designers. You may call yourself a front-end developer, but if you spend hours shaving half-seconds off an interaction, that’s user experience and you, my friend, are a designer. If the client asks, “Can you migrate all my old content to the new CMS?” and you answer, “Of course we can, but should we?”, you are a designer. Even our users are designers. Think about it. Once again, as in the dim dumb dot-com past, we seem to be divided by our titles. But, O, my friends, our varied titles are only differing facets of the same bright gem. Sisters, brothers, we are all designers. Love on! Love on! And may all your web pages, cards, clusters, clumps, asides, articles, and relational databases be bright. 2014 Jeffrey Zeldman jeffreyzeldman 2014-12-18T00:00:00+00:00 https://24ways.org/2014/a-holiday-wish/ ux
100 Moo'y Christmas A note from the editors: Moo has changed their API since this article was written. As the web matures, it is less and less just about the virtual world. It is becoming entangled with our world and it is harder to tell what is virtual and what is real. There are several companies who are blurring this line and make the virtual just an extension of the physical. Moo is one such company. Moo offers simple print on demand services. You can print business cards, moo mini cards, stickers, postcards and more. They give you the ability to upload your images, customize them, then have them sent to your door. Many companies allow this sort of digital to physical interaction, but Moo has taken it one step further and has built an API. Printable stocking stuffers The Moo API consists of a simple XML file that is sent to their servers. It describes all the information needed to dynamically assemble and print your object. This is very helpful, not just for when you want to print your own stickers, but when you want to offer them to your customers, friends, organization or community with no hassle. Moo handles the check-out and shipping, all you need to do is what you do best, create! Now using an API sounds complicated, but it is actually very easy. I am going to walk you through the options so you can easily be printing in no time. Before you can begin sending data to the Moo API, you need to register and get an API key. This is important, because it allows Moo to track usage and to credit you. To register, visit http://www.moo.com/api/ and click “Request an API key”. In the following examples, I will use {YOUR API KEY HERE} as a place holder, replace that with your API key and everything will work fine. First thing you need to do is to create an XML file to describe the check-out basket. Open any text-editor and start with some XML basics. Don’t worry, this is pretty simple and Moo gives you a few tools to check your XML for errors before you order. <?xml version="1.0" encoding="UTF-8"?> <moo xsi:noNamespaceSchemaLocation="http://www.moo.com/xsd/api_0.7.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <request> <version>0.7</version> <api_key>{YOUR API KEY HERE}</api_key> <call>build</call> <return_to>http://www.example.com/return.html</return_to> <fail_to>http://www.example.com/fail.html</fail_to> </request> <payload> ... </payload> </moo> Much like HTML’s <head> and <body>, Moo has created <request> and <payload> elements all wrapped in a <moo> element. The <request> element contains a few pieces of information that is the same across all the API calls. The <version> element describes which version of the API is being used. This is more important for Moo than for you, so just stick with “0.7” for now. The <api_key> allows Moo to track sales, referrers and credit your account. The <call> element can only take “build” so that is pretty straight forward. The <return_to> and <fail_to> elements are URLs. These are optional and are the URLs the customer is redirected to if there is an error, or when the check out process is complete. This allows for some basic branding and a custom “thank you” page which is under your control. That’s it for the <request> element, pretty easy so far! Next up is the <payload> element. What goes inside here describes what is to be printed. There are two possible elements, we can put <chooser> or we can put <products> directly inside <payload>. They work in a similar ways, but they drop the customer into different parts of the Moo checkout process. If you specify <products> then you send the customer straight to the Moo payment process. If you specify <chooser> then you send the customer one-step earlier where they are allowed to pick and choose some images, remove the ones they don’t like, adjust the crop, etc. The example here will use <chooser> but with a little bit of homework you can easily adjust to <products> if you desire. ... <chooser> <product_type>sticker</product_type> <images> <url>http://example.com/images/christmas1.jpg</url> </images> </chooser> ... Inside the <chooser> element, we can see there are two basic piece of information. The type of product we want to print, and the images that are to be printed. The <product_type> element can take one of five options and is required! The possibilities are: minicard, notecard, sticker, postcard or greetingcard. We’ll now look at two of these more closely. Moo Stickers In the Moo sticker books you get 90 small squarish stickers in a small little booklet. The simplest XML you could send would be something like the following payload: ... <payload> <chooser> <product_type>sticker</product_type> <images> <url>http://example.com/image1.jpg</url> </images> <images> <url>http://example.com/image2.jpg</url> </images> <images> <url>http://example.com/image3.jpg</url> </images> </chooser> </payload> ... This creates a sticker book with only 3 unique images, but 30 copies of each image. The Sticker books always print 90 stickers in multiples of the images you uploaded. That example only has 3 <images> elements, but you can easily duplicate the XML and send up to 90. The <url> should be the full path to your image and the image needs to be a minimum of 300 pixels by 300 pixels. You can add more XML to describe cropping, but the simplest option is to either, let your customers choose or to pre-crop all your images square so there are no issues. The full XML you would post to the Moo API to print sticker books would look like this: <?xml version="1.0" encoding="UTF-8"?> <moo xsi:noNamespaceSchemaLocation="http://www.moo.com/xsd/api_0.7.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <request> <version>0.7</version> <api_key>{YOUR API KEY HERE}</api_key> <call>build</call> <return_to>http://www.example.com/return.html</return_to> <fail_to>http://www.example.com/fail.html</fail_to> </request> <payload> <chooser> <product_type>sticker</product_type> <images> <url>http://example.com/image1.jpg</url> </images> <images> <url>http://example.com/image2.jpg</url> </images> <images> <url>http://example.com/image3.jpg</url> </images> </chooser> </payload> </moo> Mini-cards The mini-cards are the small cute business cards in 14×35 dimensions and come in packs of 100. Since the mini-cards are print on demand, this allows you to have 100 unique images on the back of the cards. Just like the stickers example, we need the same XML setup. The <moo> element and <request> elements will be the same as before. The part you will focus on is the <payload> section. Since you are sending along specific information, we can’t use the <chooser> option any more. Switch this to <products> which has a child of <product>, which in turn has a <product_type> and <designs>. This might seem like a lot of work, but once you have it set up you won’t need to change it. ... <payload> <products> <product> <product_type>minicard</product_type> <designs> ... </designs> </product> </products> </payload> ... So now that we have the basic framework, we can talk about the information specific to minicards. Inside the <designs> element, you will have one <design> for each card. Much like before, this contains a way to describe the image. Note that this time the element is called <image>, not images plural. Inside the <image> element you have a <url> which points to where the image lives and a <type>. The <type> should just be set to ‘variable’. You can pass crop information here instead, but we’re going to keep it simple for this tutorial. If you are interested in how that works, you should refer to the official API documentation. ... <design> <image> <url>http://example.com/image1.jpg</url> <type>variable</type> </image> </design> ... So far, we have managed to build a pack of 100 Moo mini-cards with the same image on the front. If you wanted 100 different images, you just need to replicate this snippit, 99 more times. That describes the front design, but the flip-side of your mini-cards can contain 6 lines of text, which is customizable in a variety of colors, fonts and styles. The API allows you to create different text on the back of each mini-card, something the web interface doesn’t implement. To describe the text on the mini-card we need to add a <text_collection> element inside the <design> element. If you skip this element, the back of your mini-card will just be blank, but that’s not very festive! Inside the <text_collection> element, we need to describe the type of text we want to format, so we add a <minicard> element, which in turn contains all the lines of text. Each of Moo’s printed products take different numbers of lines of text, so if you are not planning on making mini-cards, be sure to consult the documentation. For mini-cards, we can have 6 distinct lines, each with their own style and layout. Each line is represented by an element <text_line> which has several optional children. The <id> tells which line of the 6 to print the text one. The <string> is the text you want to print and it must be shorter than 38 characters. The <bold> element is false by default, but if you want your text bolded, then add this and set it to true. The <align> element is also optional. By default it is set to align left. You can also set this to right or center if you desirer. The <font> element takes one of 3 types, modern, traditional or typewriter. The default is modern. Finally, you can set the <colour>, yes that’s color with a ‘u’, Moo is a British company, so they get to make the rules. When you start a print on demand company, you can spell it however you want. The <colour> element takes a 6 character hex value with a leading #. <design> ... <text_collection> <minicard> <text_line> <id>(1-6)</id> <string>String, I must be less than 38 chars!</string> <bold>true</bold> <align>left</align> <font>modern</font> <colour>#ff0000</colour> </text_line> </minicard> </text_collection> </design> If you combine all of this into a mini-card request you’d get this example: <?xml version="1.0" encoding="UTF-8"?> <moo xsi:noNamespaceSchemaLocation="http://www.moo.com/xsd/api_0.7.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <request> <version>0.7</version> <api_key>{YOUR API KEY HERE}</api_key> <call>build</call> <return_to>http://www.example.com/return.html</return_to> <fail_to>http://www.example.com/fail.html</fail_to> </request> <payload> <products> <product> <product_type>minicard</product_type> <designs> <design> <image> <url>http://example.com/image1.jpg</url> <type>variable</type> </image> <text_collection> <minicard> <text_line> <id>1</id> <string>String, I must be less than 38 chars!</string> <bold>true</bold> <align>left</align> <font>modern</font> <colour>#ff0000</colour> </text_line> </minicard> </text_collection> </design> </designs> </product> </products> </payload> </moo> Now you know how to construct the XML that describes what to print. Next, you need to know how to send it to Moo to make it happen! Posting to the API So your XML is file ready to go. First thing we need to do is check it to make sure it’s valid. Moo has created a simple validator where you paste in your XML, and it alerts you to problems. When you have a fully valid XML file, you’ll want to send that to the Moo API. There are a few ways to do this, but the simplest is with an HTML form. This is the sample code for an HTML form with a big “Buy My Stickers” button. Once you know that it is working, you can use all your existing HTML knowledge to style it up any way you like. <form method="POST" action="http://www.moo.com/api/api.php"> <input type="hidden" name="xml" value="<?xml version="1.0" encoding="UTF-8"?> <moo xsi:noNamespaceSchemaLocation="http://www.moo.com/xsd/api_0.7.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <request>....</request> <payload>...</payload> </moo> "> <input type="submit" name="submit" value="Buy My Stickers"/> </form> This is just a basic <form> element that submits to the Moo API, http://www.moo.com/api/api.php, when someone clicks the button. There is a hidden input called “xml” which contains the value the XML file we created previously. For those of you who need to “view source” to fully understand what’s happening can see a working version and peek under the hood. Using the API has advantages over uploading the images directly yourself. The images and text that you send via the API can be dynamic. Some companies, like Dopplr, have taken user profiles and dynamic data that changes every minute to generate customer stickers of places that you’ve travelled to or mini-cards with a world map of all the cities you have visited. Every single customer has different travel plans and therefore different sets of stickers and mini-card maps. The API allows for the utmost current information to be printed, on demand, in real-time. Go forth and Moo’ltiply See, making an API call wasn’t that hard was it? You are now 90% of the way to creating anything with the Moo API. With a bit of reading, you can learn that extra 10% and print any Moo product. Be on the lookout in 2009 for the official release of the 1.0 API with improvements and some extras that were not available when this article was written. This article is released under the creative-commons attribution share-a-like license. That means you are free to re-distribute it, mash it up, translate it and otherwise re-using it ways the author never considered, in return he only asks you mention his name. This work by Brian Suda is licensed under a Creative Commons Attribution-Share Alike 3.0 Unported License. 2008 Brian Suda briansuda 2008-12-19T00:00:00+00:00 https://24ways.org/2008/mooy-christmas/ code
160 Tracking Christmas Cheer with Google Charts A note from the editors: Since this article was written Google has retired the Charts API. Let’s get something out in the open: I love statistics. As an informatician I can’t 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’ll show you what you can and can’t do with Google Charts. Mummy, it’s my first chart The 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’s servers — you need only reference an image in your HTML. You pass along the data — the numbers for the charts, axis labels, and so on — in the query string of the image’s URL. If you want to add charts to your blog or web site, there’s probably no quicker way to get started. Here’s a simple example: if we add the following line to an HTML page: <img src="http://chart.apis.google.com/chart?cht=lc&chs=200x125&chd=s:ZreelPuevfgznf2008" /> Then we’ll see the line graph in Figure 1 appear in our page. That graph is hosted on Google’s own server1: http://chart.apis.google.com/. Figure 1: A simple example of a line graph created with Google Charts. If you look at the URL used in the example you’ll notice we’re passing some parameters along in the query string (the bit after the question mark). The query string looks like this: cht=lc&chs=200x125&chd=s:ZreelPuevfgznf2008 It’s contains everything Google Charts needs to draw the graph. There are three parameters in the query string: cht; this specifies the type of chart Google Charts will generate (in this case, lc is a line chart). chs, the value of which is 200x125; this defines the chart’s size (200 pixels wide by 125 pixels high). chd, the value of which is s:ZreelPuevfgznf2008; this is the actual chart data, which we’ll discuss in more detail later. These 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). Christmas pie After I discovered the option to create a pie chart I instantly thought of graphing all the types of food and beverages that I’ll consume at this year’s 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). By changing the value of the cht parameter in the image’s 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. Figure 2: Pie chart with a title. To add this chart to your own page, you include the following (notice that you can’t include spaces in URLs, so you need to encode them as plus-signs.): <img src="http://chart.apis.google.com/chart?chtt=Food+and+Drink+Consumed+Christmas+2007&cht=p&chs=300x300&chd=s:ZreelPuevfgznf2008" /> Ok, that’s 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: Egg nog 10% Christmas Ham 20% Milk (not including egg nog) 8% Cookies 25% Roasted Chestnuts 5% Chocolate 3% Various Other Beverages 15% Various Other Foods 9% Snacks 5% I 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: chl=Egg+nog|Christmas+Ham|Milk+(not+including+egg+nog)|Cookies|Roast+Chestnuts|Chocolate|Various+Other+Beverages|Various+Other+Foods|Snacks Next 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 — but by no means complicated. There are three different ways to encode your data on a chart. As I’m only dealing with small numbers, I’m going to use what Google calls simple encoding. Simple 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. In 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. In 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. If you think figuring this out for each chart may make your head explode, don’t worry: help is out there. Do you remember I said I needed to change the image dimensions to be square, to accommodate the pie chart? Well now I’m including labels I need even more room. And as I’m in a Christmassy mood I’m going to add some festive colours too. The optional chco parameter is used to change the chart color. You set this using the same hexadecimal (“hex”) notation found in CSS. So let’s make our pie chart green by adding chco=00AF33 (don’t 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 “Milk” and “Cookies” slices were consumed together, so we can make those two slices more of a redish colour. I’ll use shades of green for the other slices. My chco parameter now looks like this: chco=00AF33,4BB74C,EE2C2C,CC3232,33FF33,66FF66,9AFF9A,C1FFC1,CCFFCC. After all this, I’m left with the following URL: http://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 What does that give us? I’m glad you asked. I have the rather beautiful 600-pixel wide pie chart you see in Figure 3. Figure 3: A Christmassy pie chart with labels. But I don’t like pie charts The 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’re an anti-pie-chartist, what can you do? You 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’ll talk more about how to do all this in the next section. In Figure 4 you’ll see the newly-converted bar graph. The URL for the graph is: http://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 Figure 4: The pie chart from Figure 3 represented as a bar chart. Two lines, one graph Pie charts and bar charts are interesting, but what if I want to compare last year’s Christmas cheer with this year’s? That sounds like I’ll need two lines on one graph. The 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: <img src="http://chart.apis.google.com/chart?chs=800x300&cht=lxy&chd=t:0,100|0,100" /> The 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’m going to demostrate a different encoding, text encoding. To use this I start the value of the chd parameter with “t:” instead of “s:”, 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. Figure 5: A simple line graph with x and y co-ordinates. To make this graph a little more pleasing to the eye, I can add much the same as I did to the pie chart. I’ll add a chart title. Maybe something like “Projected Christmas Cheer for 2007”. Just as before I would add a chtt parameter to the image URL: &chtt=Projected+Christmas+Cheer+for+2007 Next, let’s add some labels on the y axis to represent a scale from 0 to 100. On the x axis let’s 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’m 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. Now 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 — in this case the x-axis. 1:Label2 is the first index of chxt — the y-axis. The order of these parameters or labels doesn’t matter as long as you associate them to their chxt correctly. The next thing to know about chxl is that you can add an empty label. Labels are separated by vertical pipe; if you don’t put any text in a label, you just leave the two vertical pipes empty (“||”) and Google Charts will allocate space but no label. For 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. We can do the same thing to get specific dates along the x-axis as well. Let’s add the 1st of December, St. Nick’s 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’ll use 0: as a reference in the chxt parameter tell Google Charts which axis to label. In full, the chxl parameter now looks like: chxl=1:||||||50|||||100|0:|Dec+1st|||||6th||||10th|||||15th|||||20th|||||25th|26th|||||Dec+31st That’s pretty. Before we begin to graph our data, I’ll 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. As 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. The 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: chg=3.333,10,1,3 If I add that to the chart URL I end up with: http://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 Which results in the chart shown in Figure 6. Figure 6: Chart ready to receive the Christmas cheer values. Real data Now the chart is ready I can add historical data from 2006 and current data from 2007. Having a look at last year’s cheer levels we find some highs and lows through-out the month: Dec 1st Advent starts; life is good 30% Dec 6th St. Nick’s Day, awake to find good things in my shoes 45% Dec 8th Went Christmas carolling, nearly froze 20% Dec 10th Christmas party at work, very nice dinner 50% Dec 18th Panic Christmas shopping, hate rude people 15% Dec 23rd Off Work, home eating holiday food 80% Dec 25th Opened presents, good year, but got socks again from Grandma 60% Dec 26th Boxing Day; we’re off and no one knows why 70% Dec 28th Third day of left overs 40% Dec 29th Procured some fireworks for new years 55% Dec 31st New Year’s Eve 80% Since I’m plotting data for 2006 and 2007 on the same graph I’ll need two different colours — one for each year’s line — 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’ll use chdl=2006|2007. I also want to colour-code them, so I’ll need to add the chco as I did for the pie chart. I want a red line and a green line, so I’ll use chco=458B00,CD2626 and add this to the image URL. Let’s 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. The 1st of December is 0 and the 31st is 100. Everything else is somewhere in between. Our formula is: (d – 1) × 100 ÷ (31 – 1) Where 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: 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 Onto 2007: I can put the data for the month so far to see how we are trending. Dec 1st Christmas shopping finished already 50% Dec 4th Computer hard disk drive crashed (not Christmas related accident, but put me in a bad mood) 10% Dec 6th Missed St. Nick’s Day completely due to travelling 30% Dec 9th Dinner with friends before they travel 55% Dec 11th 24ways article goes live 60% Using 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: 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 Passing this to Google Charts results in Figure 7. http://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 Figure 7: Projected Christmas cheer for 2006 and 2007. Did someone mention Edward Tufte? Google 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 “small, high resolution graphics embedded in a context of words, numbers, images”. They can be extremely useful, but can you create them in Google Charts? The answer is: “Yes, but it’s an undocumented feature”. (The usual disclaimer about undocumented features applies.) If 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 — a sparkline — small enough to fit into a sentence. Google uses the lfi type all throughout the their financial site, but it’s not yet part of the official API. MerryChristmas http://chart.apis.google.com/chart?cht=lfi&chs=100x15&chd=s:MerryChristmas 24ways http://chart.apis.google.com/chart?cht=lfi&chs=100x15&chd=s:24ways&chco=999999 HappyHolidays http://chart.apis.google.com/chart?cht=lfi&chs=100x15&chd=s:HappyHolidays&chco=ff0000 HappyNewYear http://chart.apis.google.com/chart?cht=lfi&chs=100x15&chd=s:HappyNewYear&chco=0000ff Summary The 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’ve finished ready the article I hope you waste no more time: go forth and chart! Further reading Google Charts API More on Google Charts How to handle negative numbers 12 Days of Christmas Pie Chart 1 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 – try them! 2007 Brian Suda briansuda 2007-12-11T00:00:00+00:00 https://24ways.org/2007/tracking-christmas-cheer-with-google-charts/ ux
109 Geotag Everywhere with Fire Eagle A note from the editors: Since this article was written Yahoo! has retired the Fire Eagle service. Location, they say, is everywhere. Everyone has one, all of the time. But on the web, it’s taken until this year to see the emergence of location in the applications we use and build. The possibilities are broad. Increasingly, mobile phones provide SDKs to approximate your location wherever you are, browser extensions such as Loki and Mozilla’s Geode provide browser-level APIs to establish your location from the proximity of wireless networks to your laptop. Yahoo’s Brickhouse group launched Fire Eagle, an ambitious location broker enabling people to take their location from any of these devices or sources, and provide it to a plethora of web services. It enables you to take the location information that only your iPhone knows about and use it anywhere on the web. That said, this is still a time of location as an emerging technology. Fire Eagle stores your location on the web (protected by application-specific access controls), but to try and give an idea of how useful and powerful your location can be — regardless of the services you use now — today’s 24ways is going to build a bookmarklet to call up your location on demand, in any web application. Location Support on the Web Over the past year, the number of applications implementing location features has increased dramatically. Plazes and Brightkite are both full featured social networks based around where you are, whilst Pownce rolled in Fire Eagle support to allow geotagging of all the content you post to their microblogging service. Dipity’s beautiful timeline shows for you moving from place to place and Six Apart’s activity stream for Movable Type started exposing your movements. The number of services that hook into Fire Eagle will increase as location awareness spreads through the developer community, but you can use your location on other sites indirectly too. Consider Flickr. Now world renowned for their incredible mapping and places features, geotagging on Flickr started out as a grassroots extension of regular tagging. That same technique can be used to start rolling geotagging in any publishing platform you come across, for any kind of content. Machine-tags (geo:lat= and geo:lon=) and the adr and geo microformats can be used to enhance anything you write with location information. A crash course in avian inflammability Fire Eagle is a location store. A broker between services and devices which provide location and those which consume it. It’s a switchboard that controls which pieces of your location different applications can see and use, and keeps hidden anything you want kept private. A blog widget that displays your current location in public can be restricted to display just your current city, whilst a service that provides you with a list of the nearest ATMs will operate better with a precise street address. Even if your iPhone tells Fire Eagle exactly where you are, consuming applications only see what you want them to see. That’s important for users to realise that they’re in control, but also important for application developers to remember that you cannot rely on having super-accurate information available all the time. You need to build location aware applications which degrade gracefully, because users will provide fuzzier information — either through choice, or through less accurate sources. Application specific permissions are controlled through an OAuth API. Each application has a unique key, used to request a second, user-specific key that permits access to that user’s information. You store that user key and it remains valid until such a time as the user revokes your application’s access. Unlike with passwords, these keys are unique per application, so revoking the access rights of one application doesn’t break all the others. Building your first Fire Eagle app; Geomarklet Fire Eagle’s developer documentation can take you through examples of writing simple applications using server side technologies (PHP, Python). Here, we’re going to write a client-side bookmarklet to make your location available in every site you use. It’s designed to fast-track the experience of having location available everywhere on web, and show you how that can be really handy. Hopefully, this will set you thinking about how location can enhance the new applications you build in 2009. An oddity of bookmarklets Bookmarklets (or ‘favlets’, for those of an MSIE persuasion) are a strange environment to program in. Critically, you have no persistent storage available. As such, using token-auth APIs in a static environment requires you to build you application in a slightly strange way; authing yourself in advance and then hardcoding the keys into your script. Get started Before you do anything else, go to http://fireeagle.com and log in, get set up if you need to and by all means take a look around. Take a look at the mobile updaters section of the application gallery and perhaps pick out an app that will update Fire Eagle from your phone or laptop. Once that’s done, you need to register for an application key in the developer section. Head straight to /developer/create and complete the form. Since you’re building a standalone application, choose ‘Auth for desktop applications’ (rather than web applications), and select that you’ll be ‘accessing location’, not updating. At the end of this process, you’ll have two application keys, a ‘Consumer Key’ and a ‘Consumer Secret’, which look like these: Consumer Key luKrM9U1pMnu Consumer Secret ZZl9YXXoJX5KLiKyVrMZffNEaBnxnd6M These keys combined allow your application to make requests to Fire Eagle. Next up, you need to auth yourself; granting your new application permission to use your location. Because bookmarklets don’t have local storage, you can’t integrate the auth process into the bookmarklet itself — it would have no way of storing the returned key. Instead, I’ve put together a simple web frontend through which you can auth with your application. Head to Auth me, Amadeus!, enter the application keys you just generated and hit ‘Authorize with Fire Eagle’. You’ll be taken to the Fire Eagle website, just as in regular Fire Eagle applications, and after granting access to your app, be redirected back to Amadeus which will provide you your user tokens. These tokens are used in subsequent requests to read your location. And, skip to the end… The process of building the bookmarklet, making requests to Fire Eagle, rendering it to the page and so forth follows, but if you’re the impatient type, you might like to try this out right now. Take your four API keys from above, and drag the following link to your Bookmarks Toolbar; it contains all the code described below. Before you can use it, you need to edit in your own API keys. Open your browser’s bookmark editor and where you find text like ‘YOUR_CONSUMER_KEY_HERE’, swap in the corresponding key you just generated. Get Location Bookmarklet Basics To start on the bookmarklet code, set out a basic JavaScript module-pattern structure: var Geomarklet = function() { return ({ callback: function(json) {}, run: function() {} }); }; Geomarklet.run(); Next we’ll add the keys obtained in the setup step, and also some basic Fire Eagle support objects: var Geomarklet = function() { var Keys = { consumer_key: 'IuKrJUHU1pMnu', consumer_secret: 'ZZl9YXXoJX5KLiKyVEERTfNEaBnxnd6M', user_token: 'xxxxxxxxxxxx', user_secret: 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' }; var LocationDetail = { EXACT: 0, POSTAL: 1, NEIGHBORHOOD: 2, CITY: 3, REGION: 4, STATE: 5, COUNTRY: 6 }; var index_offset; return ({ callback: function(json) {}, run: function() {} }); }; Geomarklet.run(); The Location Hierarchy A successful Fire Eagle query returns an object called the ‘location hierarchy’. Depending on the level of detail shared, the index of a particular piece of information in the array will vary. The LocationDetail object maps the array indices of each level in the hierarchy to something comprehensible, whilst the index_offset variable is an adjustment based on the detail of the result returned. The location hierarchy object looks like this, providing a granular breakdown of a location, in human consumable and machine-friendly forms. "user": { "location_hierarchy": [{ "level": 0, "level_name": "exact", "name": "707 19th St, San Francisco, CA", "normal_name": "94123", "geometry": { "type": "Point", "coordinates": [ - 0.2347530752, 67.232323] }, "label": null, "best_guess": true, "id": , "located_at": "2008-12-18T00:49:58-08:00", "query": "q=707%2019th%20Street,%20Sf" }, { "level": 1, "level_name": "postal", "name": "San Francisco, CA 94114", "normal_name": "12345", "woeid": , "place_id": "", "geometry": { "type": "Polygon", "coordinates": [], "bbox": [] }, "label": null, "best_guess": false, "id": 59358791, "located_at": "2008-12-18T00:49:58-08:00" }, { "level": 2, "level_name": "neighborhood", "name": "The Mission, San Francisco, CA", "normal_name": "The Mission", "woeid": 23512048, "place_id": "Y12JWsKbApmnSQpbQg", "geometry": { "type": "Polygon", "coordinates": [], "bbox": [] }, "label": null, "best_guess": false, "id": 59358801, "located_at": "2008-12-18T00:49:58-08:00" }, } In this case the first object has a level of 0, so the index_offset is also 0. Prerequisites To query Fire Eagle we call in some existing libraries to handle the OAuth layer and the Fire Eagle API call. Your bookmarklet will need to add the following scripts into the page: The SHA1 encryption algorithm The OAuth wrapper An extension for the OAuth wrapper The Fire Eagle wrapper itself When the bookmarklet is first run, we’ll insert these scripts into the document. We’re also inserting a stylesheet to dress up the UI that will be generated. If you want to follow along any of the more mundane parts of the bookmarklet, you can download the full source code. Rendering This bookmarklet can be extended to support any formatting of your location you like, but for sake of example I’m going to build three common formatters that you’ll find useful for common location scenarios: Sites which already ask for your location; and in publishing systems that accept tags or HTML mark-up. All the rendering functions are items in a renderers object, so they can be iterated through easily, making it trivial to add new formatting functions as your find new use cases (just add another function to the object). var renderers = { geotag: function(user) { if(LocationDetail.EXACT !== index_offset) { return false; } else { var coords = user.location_hierarchy[LocationDetail.EXACT].geometry.coordinates; return "geo:lat=" + coords[0] + ", geo:lon=" + coords[1]; } }, city: function(user) { if(LocationDetail.CITY < index_offset) { return false; } else { return user.location_hierarchy[LocationDetail.CITY - index_offset].name; } } You should always fail gracefully, and in line with catering to users who choose not to share their location precisely, always check that the location has been returned at the level you require. Geotags are expected to be precise, so if an exact location is unavailable, returning false will tell the rendering aspect of the bookmarklet to ignore the function altogether. These first two are quite simple, geotag returns geo:lat=-0.2347530752, geo:lon=67.232323 and city returns San Francisco, CA. This final renderer creates a chunk of HTML using the adr and geo microformats, using all available aspects of the location hierarchy, and can be used to geotag any content you write on your blog or in comments: html: function(user) { var geostring = ''; var adrstring = ''; var adr = []; adr.push('<p class="adr">'); // city if(LocationDetail.CITY >= index_offset) { adr.push( '\n <span class="locality">' + user.location_hierarchy[LocationDetail.CITY-index_offset].normal_name + '</span>,' ); } // county if(LocationDetail.REGION >= index_offset) { adr.push( '\n <span class="region">' + user.location_hierarchy[LocationDetail.REGION-index_offset].normal_name + '</span>,' ); } // locality if(LocationDetail.STATE >= index_offset) { adr.push( '\n <span class="region">' + user.location_hierarchy[LocationDetail.STATE-index_offset].normal_name + '</span>,' ); } // country if(LocationDetail.COUNTRY >= index_offset) { adr.push( '\n <span class="country-name">' + user.location_hierarchy[LocationDetail.COUNTRY-index_offset].normal_name + '</span>' ); } // postal if(LocationDetail.POSTAL >= index_offset) { adr.push( '\n <span class="postal-code">' + user.location_hierarchy[LocationDetail.POSTAL-index_offset].normal_name + '</span>,' ); } adr.push('\n</p>\n'); adrstring = adr.join(''); if(LocationDetail.EXACT === index_offset) { var coords = user.location_hierarchy[LocationDetail.EXACT].geometry.coordinates; geostring = '<p class="geo">' +'\n <span class="latitude">' + coords[0] + '</span>;' + '\n <span class="longitude">' + coords[1] + '</span>\n</p>\n'; } return (adrstring + geostring); } Here we check the availability of every level of location and build it into the adr and geo patterns as appropriate. Just as for the geotag function, if there’s no exact location the geo markup won’t be returned. Finally, there’s a rendering method which creates a container for all this data, renders all the applicable location formats and then displays them in the page for a user to copy and paste. You can throw this together with DOM methods and some simple styling, or roll in some components from YUI or JQuery to handle drawing full featured overlays. You can see this simple implementation for rendering in the full source code. Make the call With a framework in place to render Fire Eagle’s location hierarchy, the only thing that remains is to actually request your location. Having already authed through Amadeus earlier, that’s as simple as instantiating the Fire Eagle JavaScript wrapper and making a single function call. It’s a big deal that whilst a lot of new technologies like OAuth add some complexity and require new knowledge to work with, APIs like Fire Eagle are really very simple indeed. return { run: function() { insert_prerequisites(); setTimeout( function() { var fe = new FireEagle( Keys.consumer_key, Keys.consumer_secret, Keys.user_token, Keys.user_secret ); var script = document.createElement('script'); script.type = 'text/javascript'; script.src = fe.getUserUrl( FireEagle.RESPONSE_FORMAT.json, 'Geomarklet.callback' ); document.body.appendChild(script); }, 2000 ); }, callback: function(json) { if(json.rsp && 'fail' == json.rsp.stat) { alert('Error ' + json.rsp.code + ": " + json.rsp.message); } else { index_offset = json.user.location_hierarchy[0].level; draw_selector(json); } } }; We first insert the prerequisite scripts required for the Fire Eagle request to function, and to prevent trying to instantiate the FireEagle object before it’s been loaded over the wire, the remaining instantiation and request is wrapped inside a setTimeout delay. We then create the request URL, referencing the Geomarklet.callback callback function and then append the script to the document body — allowing a cross-domain request. The callback itself is quite simple. Check for the presence and value of rsp.status to test for errors, and display them as required. If the request is successful set the index_offset — to adjust for the granularity of the location hierarchy — and then pass the object to the renderer. The result? When Geomarklet.run() is called, your location from Fire Eagle is read, and each renderer displayed on the page in an easily copy and pasteable form, ready to be used however you need. Deploy The final step is to convert this code into a long string for use as a bookmarklet. Easiest for Mac users is the JavaScript bundle in TextMate — choose Bundles: JavaScript: Copy as Bookmarklet to Clipboard. Then create a new ‘Get Location’ bookmark in your browser of choice and paste in. Those without TextMate can shrink their code down into a single line by first running their code through the JSLint tool (to ensure the code is free from errors and has all the required semi-colons) and then use a find-and-replace tool to remove line breaks from your code (or even run your code through JSMin to shrink it down). With the bookmarklet created and added to your bookmarks bar, you can now call up your location on any page at all. Get a feel for a web where your location is just another reliable part of the browsing experience. Where next? So, the Geomarklet you’ve been guided through is a pretty simple premise and pretty simple output. But from this base you can start to extend: Add code that will insert each of the location renderings directly into form fields, perhaps, or how about site-specific handlers to add your location tags into the correct form field in Wordpress or Tumblr? Paste in your current location to Google Maps? Or Flickr? Geomarklet gives you a base to start experimenting with location on your own pages and the sites you browse daily. The introduction of consumer accessible geo to the web is an adventure of discovery; not so much discovering new locations, but discovering location itself. 2008 Ben Ward benward 2008-12-21T00:00:00+00:00 https://24ways.org/2008/geotag-everywhere-with-fire-eagle/ code
329 Broader Border Corners A note from the editors: Since this article was written the CSS border-radius property has become widely supported in browsers. It should be preferred to this image technique. A quick and easy recipe for turning those single-pixel borders that the kids love so much into into something a little less right-angled. Here’s the principle: We have a box with a one-pixel wide border around it. Inside that box is another box that has a little rounded-corner background image sitting snugly in one of its corners. The inner-box is then nudged out a bit so that it’s actually sitting on top of the outer box. If it’s all done properly, that little background image can mask the hard right angle of the default border of the outer-box, giving the impression that it actually has a rounded corner. Take An Image, Finely Chopped Add A Sprinkle of Markup <div id="content"> <p>Lorem ipsum etc. etc. etc.</p> </div> Throw In A Dollop of CSS #content { border: 1px solid #c03; } #content p { background: url(corner.gif) top left no-repeat; position: relative; left: -1px; top: -1px; padding: 1em; margin: 0; } Bubblin’ Hot The content div has a one-pixel wide red border around it. The paragraph is given a single instance of the background image, created to look like a one-pixel wide arc. The paragraph is shunted outside of the box – back one pixel and up one pixel – so that it is sitting over the div’s border. The white area of the image covers up that part of the border’s corner, and the arc meets up with the top and left border. Because, in this example, we’re applying a background image to a paragraph, its top margin needs to be zeroed so that it starts at the top of its container. Et voilà. Bon appétit. Extra Toppings If you want to apply a curve to each one of the corners and you run out of meaningful markup to hook the background images on to, throw some spans or divs in the mix (there’s nothing wrong with this if that’s the effect you truly want – they don’t hurt anybody) or use some nifty DOM Scripting to put the scaffolding in for you. Note that if you’ve got more than one of these relative corners, you will need to compensate for the starting position of each box which is nested in an already nudged parent. You’re not limited to one pixel wide, rounded corners – the same principles apply to thicker borders, or corners with different shapes. 2005 Patrick Griffiths patrickgriffiths 2005-12-14T00:00:00+00:00 https://24ways.org/2005/broader-border-corners/ design
144 The Mobile Web, Simplified A note from the editors: although eye-opening in 2006, this article is no longer relevant to today’s mobile web. Considering a foray into mobile web development? Following are four things you need to know before making the leap. 1. 4 billion mobile subscribers expected by 2010 Fancy 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. 2. Context is king Your 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’re probably seeking specific data such as directions or show times, rather than the plethora of data at your disposal via a desktop PC. The mobile web, a phrase often used to indicate “accessing the web on a mobile device”, 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’ll be off to a great start. 3. WAP 2.0 is an XHTML environment In a nutshell, here are a few fundamental tenets of mobile internet technology: Wireless Application Protocol (WAP) is the protocol for enabling mobile access to internet content. Wireless Markup Language (WML) was the language of choice for WAP 1.0. Nearly all devices sold today are WAP 2.0 devices. With the introduction of WAP 2.0, XHTML Mobile Profile (XHTML-MP) became the preferred markup language. XHTML-MP will be familiar to anyone experienced with XHTML Transitional or Strict. Summary? The mobile web is rapidly becoming an XHTML environment, and thus you and I can apply our existing “desktop web” 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’m generalizing things gratuitously, but the point remains: Get off yo’ lazy butt and begin to take mobile seriously. I’ll even pass you a few tips for getting started. First, the DOCTYPE for XHTML-MP is as follows: <!DOCTYPE html PUBLIC "-//WAPFORUM//DTD XHTML Mobile 1.0//EN" "http://www.openmobilealliance.org/tech/DTD/xhtml-mobile10.dtd"> As 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). Once you’ve made it to the body, the XHTML-MP markup is not unlike what you’re already used to. A few resources worth skimming: Developers Home XHTML-MP Tutorial – An impressively replete resource for all things XHTML-MP XHTML-MP Tags List – A complete list of XHTML-MP elements and accompanying attributes And 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’re 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. Stocking 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. 4. “Cell phone” is so DynaTAC If you’re a U.S. resident, listen up: You must rid your vocabulary of the term “cell phone”. We’re 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: “mobile” or “mobile phone” or “handset” or “handy”. If you’re not sure which, go for “mobile”. Such as, “Yo dog, check out my new mobile.” More importantly, however, is overcoming the mentality that access to the mobile web can be done only with a phone. Instead, “device” encourages us to think phone, handheld computer, watch, Nintendo DS, car, you name it. Simple enough? 2006 Cameron Moll cameronmoll 2006-12-19T00:00:00+00:00 https://24ways.org/2006/the-mobile-web-simplified/ ux
164 My Other Christmas Present Is a Definition List A note from the editors: readers should note that the HTML5 redefinition of definition lists has come to pass and is now à la mode. 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. No, not tables. Definition lists. Ah, definition lists. Often used but rarely understood. Examining the definition of definitions To start with, let’s see what the HTML spec has to say about them. Definition lists vary only slightly from other types of lists in that list items consist of two parts: a term and a description. The 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). Excellent, we can all grasp that. But it very quickly starts to fall apart. Even in the HTML specification the definition list is mis-used. Another application of DL, for example, is for marking up dialogues, with each DT naming a speaker, and each DD containing his or her words. Wrong. Completely and utterly wrong. This is the biggest flaw in the HTML spec, along with dropping support for the start attribute on ordered lists. “Why?”, you may ask. Let me give you an example from Romeo and Juliet, act 2, scene 2. <dt>Juliet</dt> <dd>Romeo!</dd> <dt>Romeo</dt> <dd>My niesse?</dd> <dt>Juliet</dt> <dd>At what o'clock tomorrow shall I send to thee?</dd> <dt>Romeo</dt> <dd>At the hour of nine.</dd> Now, the problem here is that a given definition can have multiple descriptions (the DD). Really the dialog “descriptions” should be rolled up under the terms, like so: <dt>Juliet</dt> <dd>Romeo!</dd> <dd>At what o'clock tomorrow shall I send to thee?</dd> <dt>Romeo</dt> <dd>My niesse?</dd> <dd>At the hour of nine.</dd> Suddenly the play won’t make anywhere near as much sense. (If it’s anything, the correct markup for a play is an ordered list of CITE and BLOCKQUOTE elements.) This is the first part of the problem. That simple example has turned definition lists in everyone’s mind from pure definitions to more along the lines of a list with pre-configured heading(s) and text(s). Screen reader, enter stage left. In many screen readers, a simple definition list would be read out as “definition term equals definition description”. So in our play excerpt, Juliet equals Romeo! That’s 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. Behaviour and convention The 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. The 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). They also note that the “dl element is inappropriate for marking up dialogue, since dialogue is ordered”. So for that example they have created a DIALOG (sic) element. Strange, then, that they keep DL as-is but instead refer to it an “association list”. 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 “pave the cowpath” of convention. How to use a definition list Given 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’t. We don’t have HTML5 yet, so we’re stuck with the existing semantics of HTML4 and XHTML1. Which means that: Listing dialogue is not defining anything. Listing the attributes of a piece of hardware (resolution = 1600×1200) is illustrating sample values, not defining anything (however, stating what ‘resolution’ actually means in this context would be a definition). Listing 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.) A menu of navigation items is simply a nested ordered or unordered list of links, not a definition list. Applying styling handles to form labels and elements is not a good use for a definition list. And so on. Living by the specification, a definition list should be used for term definitions – glossaries, lexicons and dictionaries – only. Anything else is a crime against markup. 2007 Mark Norman Francis marknormanfrancis 2007-12-05T00:00:00+00:00 https://24ways.org/2007/my-other-christmas-present-is-a-definition-list/ code
159 How Media Studies Can Massage Your Message A young web designer once told his teacher ‘just get to the meat already.’ He was frustrated with what he called the ‘history lessons and name-dropping’ aspects of his formal college course. He just wanted to learn how to build Web sites, not examine the reasons why. Technique and theory are both integrated and necessary portions of a strong education. The student’s 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. History 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’s medium. Controlling the Message ‘The computer can’t tell you the emotional story. It can give you the exact mathematical design, but what’s missing is the eyebrows.’ – Frank Zappa Media is meant to express an idea. The great media theorist Marshall McLuhan suggests that not only is media interesting because it’s 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: ‘The medium is the message.’ If 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. Figure 1 Must 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. Takeaway: Getting the message right involves understanding that message in order to direct it to your audience accordingly. A Separate Piece If 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. For 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’ve 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. For 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. Examination: The Glass Bead Game Figure 2 Figure 2 shows two screenshots of CoreWave’s historic ‘Glass Bead Game.’ Fashioned after Herman Hesse’s 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. Takeaway: 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. Computers and Human Interaction Since 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 ‘So how do you feel about that?’ This caused me no end of laughter and I instantly quipped back ‘It’s okay by me ELIZA.’ We both enjoyed the joke, but then I tried to share it with another dare I say younger colleague, and the reference was lost. Raise 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? Conversation with Eliza There 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. Figure 3 shows a screen shot of the interaction. ELIZA first welcomes me, says ‘Hello, How do you do. Please state your problem’ 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. Figure 3 Albeit a very limited demonstration of how humans could interact with a computer in 1966, it’s 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. Figure 4 Takeway: the better we know our environment, the more we can alter it to emulate, expand and even supersede our message. Leveraging Holiday Cheer Since most of us at least have a few days off for the holidays now that Christmas is upon us, now’s a perfect time to reflect on ones’ 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’s ‘The Medium is the Massage.’ Leverage that holiday cheer and here’s to a prosperous, interactive new year. 2007 Molly Holzschlag mollyholzschlag 2007-12-22T00:00:00+00:00 https://24ways.org/2007/how-media-studies-can-massage-your-message/ ux
65 The Accessibility Mindset Accessibility is often characterized as additional work, hard to learn and only affecting a small number of people. Those myths have no logical foundation and often stem from outdated information or misconceptions. Indeed, it is an additional skill set to acquire, quite like learning new JavaScript frameworks, CSS layout techniques or new HTML elements. But it isn’t particularly harder to learn than those other skills. A World Health Organization (WHO) report on disabilities states that, [i]ncluding children, over a billion people (or about 15% of the world’s population) were estimated to be living with disability. Being disabled is not as unusual as one might think. Due to chronic health conditions and older people having a higher risk of disability, we are also currently paving the cowpath to an internet that we can still use in the future. Accessibility has a very close relationship with usability, and advancements in accessibility often yield improvements in the usability of a website. Websites are also more adaptable to users’ needs when they are built in an accessible fashion. Beyond the bare minimum In the time of table layouts, web developers could create code that passed validation rules but didn’t adhere to the underlying semantic HTML model. We later developed best practices, like using lists for navigation, and with HTML5 we started to wrap those lists in nav elements. Working with accessibility standards is similar. The Web Content Accessibility Guidelines (WCAG) 2.0 can inform your decision to make websites accessible and can be used to test that you met the success criteria. What it can’t do is measure how well you met them. W3C developed a long list of techniques that can be used to make your website accessible, but you might find yourself in a situation where you need to adapt those techniques to be the most usable solution for your particular problem. The checkbox below is implemented in an accessible way: The input element has an id and the label associated with the checkbox refers to the input using the for attribute. The hover area is shown with a yellow background and a black dotted border: Open video The label is clickable and the checkbox has an accessible description. Job done, right? Not really. Take a look at the space between the label and the checkbox: Open video The gutter is created using a right margin which pushes the label to the right. Users would certainly expect this space to be clickable as well. The simple solution is to wrap the label around the checkbox and the text: Open video You can also set the label to display:block; to further increase the clickable area: Open video And while we’re at it, users might expect the whole box to be clickable anyway. Let’s apply the CSS that was on a wrapping div element to the label directly: Open video The result enhances the usability of your form element tremendously for people with lower dexterity, using a voice mouse, or using touch interfaces. And we only used basic HTML and CSS techniques; no JavaScript was added and not one extra line of CSS. <form action="#"> <label for="uniquecheckboxid"> <input type="checkbox" name="checkbox" id="uniquecheckboxid" /> Checkbox 4 </label> </form> Button Example The button below looks like a typical edit button: a pencil icon on a real button element. But if you are using a screen reader or a braille keyboard, the button is just read as “button” without any indication of what this button is for. Open video A screen reader announcing a button. Contains audio. The code snippet shows why the button is not properly announced: <button> <span class="icon icon-pencil"></span> </button> An icon font is used to display the icon and no text alternative is given. A possible solution to this problem is to use the title or aria-label attributes, which solves the alternative text use case for screen reader users: Open video A screen reader announcing a button with a title. However, screen readers are not the only way people with and without disabilities interact with websites. For example, users can reset or change font families and sizes at will. This helps many users make websites easier to read, including people with dyslexia. Your icon font might be replaced by a font that doesn’t include the glyphs that are icons. Additionally, the icon font may not load for users on slow connections, like on mobile phones inside trains, or because users decided to block external fonts altogether. The following screenshots show the mobile GitHub view with and without external fonts: The mobile GitHub view with and without external fonts. Even if the title/aria-label approach was used, the lack of visual labels is a barrier for most people under those circumstances. One way to tackle this is using the old-fashioned img element with an appropriate alt attribute, but surprisingly not every browser displays the alternative text visually when the image doesn’t load. <button> <img src="icon-pencil.svg" alt="Edit"> </button> Providing always visible text is an alternative that can work well if you have the space. It also helps users understand the meaning of the icons. <button> <span class="icon icon-pencil"></span> Edit </button> This also reads just fine in screen readers: Open video A screen reader announcing the revised button. Clever usability enhancements don’t stop at a technical implementation level. Take the BBC iPlayer pages as an example: when a user navigates the “captioned videos” or “audio description” categories and clicks on one of the videos, captions or audio descriptions are automatically switched on. Small things like this enhance the usability and don’t need a lot of engineering resources. It is more about connecting the usability dots for people with disabilities. Read more about the BBC iPlayer accessibility case study. More information W3C has created several documents that make it easier to get the gist of what web accessibility is and how it can benefit everyone. You can find out “How People with Disabilities Use the Web”, there are “Tips for Getting Started” for developers, designers and content writers. And for the more seasoned developer there is a set of tutorials on web accessibility, including information on crafting accessible forms and how to use images in an accessible way. Conclusion You can only produce a web project with long-lasting accessibility if accessibility is not an afterthought. Your organization, your division, your team need to think about accessibility as something that is the foundation of your website or project. It needs to be at the same level as performance, code quality and design, and it needs the same attention. Users often don’t notice when those fundamental aspects of good website design and development are done right. But they’ll always know when they are implemented poorly. If you take all this into consideration, you can create accessibility solutions based on the available data and bring accessibility to people who didn’t know they’d need it: Open video In this video from the latest Apple keynote, the Apple TV is operated by voice input through a remote. When the user asks “What did she say?” the video jumps back fifteen seconds and captions are switched on for a brief time. All three, the remote, voice input and captions have their roots in assisting people with disabilities. Now they benefit everyone. 2015 Eric Eggert ericeggert 2015-12-17T00:00:00+00:00 https://24ways.org/2015/the-accessibility-mindset/ code
211 Automating Your Accessibility Tests Accessibility is one of those things we all wish we were better at. It can lead to a bunch of questions like: how do we make our site better? How do we test what we have done? Should we spend time each day going through our site to check everything by hand? Or just hope that everyone on our team has remembered to check their changes are accessible? This is where automated accessibility tests can come in. We can set up automated tests and have them run whenever someone makes a pull request, and even alongside end-to-end tests, too. Automated tests can’t cover everything however; only 20 to 50% of accessibility issues can be detected automatically. For example, we can’t yet automate the comparison of an alt attribute with an image’s content, and there are some screen reader tests that need to be carried out by hand too. To ensure our site is as accessible as possible, we will still need to carry out manual tests, and I will cover these later. First, I’m going to explain how I implemented automated accessibility tests on Elsevier’s ecommerce pages, and share some of the lessons I learnt along the way. Picking the right tool One of the hardest, but most important parts of creating our automated accessibility tests was choosing the right tool. We began by investigating aXe CLI, but soon realised it wouldn’t fit our requirements. It couldn’t check pages that required a visitor to log in, so while we could test our product pages, we couldn’t test any customer account pages. Instead we moved over to Pa11y. Its beforeScript step meant we could log into the site and test pages such as the order history. The example below shows the how the beforeScript step completes a login form and then waits for the login to complete before testing the page: beforeScript: function(page, options, next) { // An example function that can be used to make sure changes have been confirmed before continuing to run Pa11y function waitUntil(condition, retries, waitOver) { page.evaluate(condition, function(err, result) { if (result || retries < 1) { // Once the changes have taken place continue with Pa11y testing waitOver(); } else { retries -= 1; setTimeout(function() { waitUntil(condition, retries, waitOver); }, 200); } }); } // The script to manipulate the page must be run with page.evaluate to be run within the context of the page page.evaluate(function() { const user = document.querySelector('#login-form input[name="email"]'); const password = document.querySelector('#login-form input[name="password"]'); const submit = document.querySelector('#login-form input[name="submit"]'); user.value = 'user@example.com'; password.value = 'password'; submit.click(); }, function() { // Use the waitUntil function to set the condition, number of retries and the callback waitUntil(function() { return window.location.href === 'https://example.com'; }, 20, next); }); } The waitUntil callback allows the test to be delayed until our test user is successfully logged in. Another thing to consider when picking a tool is the type of error messages it produces. aXe groups all elements with the same error together, so the list of issues is a lot easier to read, and it’s easier to identify the most commons problems. For example, here are some elements that have insufficient colour contrast: Violation of "color-contrast" with 8 occurrences! Ensures the contrast between foreground and background colors meets WCAG 2 AA contrast ratio thresholds. Correct invalid elements at: - #maincontent > .make_your_mark > div:nth-child(2) > p > span > span - #maincontent > .make_your_mark > div:nth-child(4) > p > span > span - #maincontent > .inform_your_decisions > div:nth-child(2) > p > span > span - #maincontent > .inform_your_decisions > div:nth-child(4) > p > span > span - #maincontent > .inform_your_decisions > div:nth-child(6) > p > span > span - #maincontent > .inform_your_decisions > div:nth-child(8) > p > span > span - #maincontent > .inform_your_decisions > div:nth-child(10) > p > span > span - #maincontent > .inform_your_decisions > div:nth-child(12) > p > span > span For details, see: https://dequeuniversity.com/rules/axe/2.5/color-contrast aXe also provides links to their site where they discuss the best way to fix the problem. In comparison, Pa11y lists each individual error which can lead to a very verbose list. However, it does provide helpful suggestions of how to fix problems, such as suggesting an alternative shade of a colour to use: • Error: This element has insufficient contrast at this conformance level. Expected a contrast ratio of at least 4.5:1, but text in this element has a contrast ratio of 2.96:1. Recommendation: change text colour to #767676. ⎣ WCAG2AA.Principle1.Guideline1_4.1_4_3.G18.Fail ⎣ #maincontent > div:nth-child(10) > div:nth-child(8) > p > span > span ⎣ <span style="color:#969696">Featured products:</span> Integrating into our build pipeline We decided the perfect time to run our accessibility tests would be alongside our end-to-end tests. We have a Jenkins job that detects changes to our staging site and then triggers the end-to-end tests, and in turn our accessibility tests. Our Jenkins job retrieves the contents of a GitHub repository containing our Pa11y script file and npm package manifest. Once Jenkins has cloned the repository, it installs any dependencies and executes the tests via: npm install && npm test Bundling the URLs to be tested into our test script means we don’t have a command line style test where we list each URL we wish to test in the Jenkins CLI. It’s an effective method but can also be cluttered, and obscure which URLs are being tested. In the middle of the office we have a monitor displaying a Jenkins dashboard and from this we can see if the accessibility tests are passing or failing. Everyone in the team has access to the Jenkins logs and when the build fails they can see why and fix the issue. Fixing the issues As mentioned earlier, Pa11y can generate a long list of areas for improvement which can be very verbose and quite overwhelming. I recommend going through the list to see which issues occur most frequently and fix those first. For example, we initially had a lot of errors around colour contrast, and one shade of grey in particular. By making this colour darker, the number of errors decreased, and we could focus on the remaining issues. Another thing I like to do is to tackle the quick fixes, such as adding alt text to images. These are small things that allow us to make an impact instantly, giving us time to fix more detailed concerns such as addressing tabindex issues, or speaking to our designers about changing the contrast of elements on the site. Manual testing Adding automated tests to check our site for accessibility is great, but as I mentioned earlier, this can only cover 20-50% of potential issues. To improve on this, we need to test by hand too, either by ourselves or by asking others. One way we can test our site is to throw our mouse or trackpad away and interact with the site using only a keyboard. This allows us to check items such as tab order, and ensure menu items, buttons etc. can be used without a mouse. The commands may be different on different operating systems, but there are some great guides online for learning more about these. It’s tempting to add alt text and aria-labels to make errors go away, but if they don’t make any sense, what use are they really? Using a screenreader we can check that alt text accurately represents the image. This is also a great way to double check that our ARIA roles make sense, and that they correctly identify elements and how to interact with them. When testing our site with screen readers, it’s important to remember that not all screen readers are the same and some may interact with our site differently to others. Consider asking a range of people with different needs and abilities to test your site, too. People experience the web in numerous ways, be they permanent, temporary or even situational. They may interact with your site in ways you hadn’t even thought about, so this is a good way to broaden your knowledge and awareness. Tips and tricks One of our main issues with Pa11y is that it may find issues we don’t have the power to solve. A perfect example of this is the one pixel image Facebook injects into our site. So, we wrote a small function to go though such errors and ignore the ones that we cannot fix. const test = pa11y({ .... hideElements: '#ratings, #js-bigsearch', ... }); const ignoreErrors: string[] = [ '<img src="https://books.google.com/intl/en/googlebooks/images/gbs_preview_button1.gif" border="0" style="cursor: pointer;" class="lightbox-is-image">', '<script type="text/javascript" id="">var USI_orderID=google_tag_mana...</script>', '<img height="1" width="1" style="display:none" src="https://www.facebook.com/tr?id=123456789012345&ev=PageView&noscript=1">' ]; const filterResult = result => { if (ignoreErrors.indexOf(result.context) > -1) { return false; } return true; }; Initially we wanted to focus on fixing the major problems, so we added a rule to ignore notices and warnings. This made the list or errors much smaller and allowed us focus on fixing major issues such as colour contrast and missing alt text. The ignored notices and warnings can be added in later after these larger issues have been resolved. const test = pa11y({ ignore: [ 'notice', 'warning' ], ... }); Jenkins gotchas While using Jenkins we encountered a few problems. Sometimes Jenkins would indicate a build had passed when in reality it had failed. This was because Pa11y had timed out due to PhantomJS throwing an error, or the test didn’t go past the first URL. Pa11y has recently released a new beta version that uses headless Chrome instead of PhantomJS, so hopefully these issues will less occur less often. We tried a few approaches to solve these issues. First we added error handling, iterating over the array of test URLs so that if an unexpected error happened, we could catch it and exit the process with an error indicating that the job had failed (using process.exit(1)). for (const url of urls) { try { console.log(url); let urlResult = await run(url); urlResult = urlResult.filter(filterResult); urlResult.forEach(result => console.log(result)); } catch (e) { console.log('Error:', e); process.exit(1); } } We also had issues with unhandled rejections sometimes caused by a session disconnecting or similar errors. To avoid Jenkins indicating our site was passing with 100% accessibility, when in reality it had not executed any tests, we instructed Jenkins to fail the job when an unhandled rejection or uncaught exception occurred: process.on('unhandledRejection', (reason, p) => { console.log('Unhandled Rejection at:', p, 'reason:', reason); process.exit(1); }); process.on('uncaughtException', (err) => { console.log('Caught exception: ${err}n'); process.exit(1); }); Now it’s your turn That’s it! That’s how we automated accessibility testing for Elsevier ecommerce pages, allowing us to improve our site and make it more accessible for everyone. I hope our experience can help you automate accessibility tests on your own site, and bring the web a step closer to being accessible to all. 2017 Seren Davies serendavies 2017-12-07T00:00:00+00:00 https://24ways.org/2017/automating-your-accessibility-tests/ code
7 Get Started With GitHub Pages (Plus Bonus Jekyll) After several failed attempts at getting set up with GitHub Pages, I vowed that if I ever figured out how to do it, I’d write it up. Fortunately, I did eventually figure it out, so here is my write-up. Why I think GitHub Pages is cool Normally when you host stuff on GitHub, you’re just storing your files there. If you push site files, what you’re storing is the code, and when you view a file, you’re viewing the code rather than the output. What GitHub Pages lets you do is store those files, and if they’re HTML files, you can view them like any other website, so there’s no need to host them separately yourself. GitHub Pages accepts static HTML but can’t execute languages like PHP, or use a database in the way you’re probably used to, so you’ll need to output static HTML files. This is where templating tools such as Jekyll come in, which I’ll talk about later. The main benefit of GitHub Pages is ease of collaboration. Changes you make in the repository are automatically synced, so if your site’s hosted on GitHub, it’s as up-to-date as your GitHub repository. This really appeals to me because when I just want to quickly get something set up, I don’t want to mess around with hosting; and when people submit a pull request, I want that change to be visible as soon as I merge it without having to set up web hooks. Before you get started If you’ve used GitHub before, already have an account and know the basics like how to set up a repository and clone it to your computer, you’re good to go. If not, I recommend getting familiar with that first. The GitHub site has extensive documentation on getting started, and if you’re not a fan of using the command line, the official GitHub apps for Mac and Windows are great. I also found this tutorial about GitHub Pages by Thinkful really useful, and it contains details on how to turn an existing repository into a GitHub Pages site. Although this involves a bit of using the command line, it’s minimal, and I’ll guide you through the basics. Setting up GitHub Pages For this demo we’re going to build a Christmas recipe site — nothing complex, just a place to store recipes so we can share them with people, and they can fork or suggest changes to ones they like. My GitHub username is maban, and the project I’ve set up is called christmas-recipes, so once I’ve set up GitHub Pages, the site can be found here: http://maban.github.io/christmas-recipes/ You can set up a custom domain, but by default, the URL for your GitHub Pages site is your-username.github.io/your-project-name. Set up the repository The first thing we’re going to do is create a new GitHub repository, in exactly the same way as normal, and clone it to the computer. Let’s give it the name christmas-recipes. There’s nothing in it at the moment, but that’s OK. After setting up the repository on the GitHub website, I cloned it to my computer in my Sites folder using the GitHub app (you can clone it somewhere else, if you want), and now I have a local repository synced with the remote one on GitHub. Navigate to the repository Now let’s open up the command line and navigate to the local repository. The easiest way to do this in Terminal is by typing cd and dragging and dropping the folder into the terminal window and pressing Return. You can refer to Chris Coyier’s GIF illustrating this very same thing, from last week’s 24 ways article “Grunt for People Who Think Things Like Grunt are Weird and Hard” (which is excellent). So, for me, that’s… cd /Users/Anna/Sites/christmas-recipes Create a special GitHub Pages branch So far we haven’t done anything different from setting up a regular repository, but here’s where things change. Now we’re in the right place, let’s create a gh-pages branch. This tells GitHub that this is a special branch, and to treat the contents of it differently. Make sure you’re still in the christmas-recipes directory, and type this command to create the gh-pages branch: git checkout --orphan gh-pages That --orphan option might be new to you. An orphaned branch is an empty branch that’s disconnected from the branch it was created off, and it starts with no commits, making it a special standalone branch. checkout switches us from the branch we were on to that branch. If all’s gone well, we’ll get a message saying Switched to a new branch ‘gh-pages’. You may get an error message saying you don’t have admin privileges, in which case you’ll need to type sudo at the start of that command. Make gh-pages your default branch (optional) The gh-pages branch is separate to the master branch, but by default, the master branch is what will show up if we go to our repository’s URL on GitHub. To change this, go to the repository settings and select gh-pages as the default branch. If, like me, you only want the one branch, you can delete the master branch by following Oli Studholme’s tutorial. It’s actually really easy to do, and means you only have to worry about keeping one branch up to date. If you prefer to work from master but push updates to the gh-pages branch, Lea Verou has written up a quick tutorial on how to do this, and it basically involves working from the master branch, and using git rebase to bring one branch up to date with another. At the moment, we’ve only got that branch on the local machine, and it’s empty, so to be able to see something at our special GitHub Pages URL, we’ll need to create a page and push it to the remote repository. Make a page Open up your favourite text editor, create a file called index.html in your christmas-recipes folder, and put some exciting text in it. Don’t worry about the markup: all we need is text because right now we’re just checking it works. Now, let’s commit and push our changes. You can do that in the command line if you’re comfortable with that, or you can do it via the GitHub app. Don’t forget to add a useful commit message. Now we’re ready to see our gorgeous new site! Go to your-username.github.io/your-project-name and, hopefully, you’ll see your first GitHub Pages site. If not, don’t panic, it can take up to ten minutes to publish, so you could make a quick cake in a cup while you wait. After a short wait, our page should be live! Hopefully that wasn’t too traumatic. Now we know it works, we can add some proper markup and CSS and even some more pages. If you’re feeling brave, how about we take it to the next level… Setting up Jekyll Since GitHub Pages can’t execute languages like PHP, we need to give it static HTML files. This is fine if there are only a few pages, but soon we’ll start to miss things like PHP includes for content that’s the same on every page, like headers and footers. Jekyll helps set up templates and turn them into static HTML. It separates markup from content, and makes it a lot easier for people to edit pages collaboratively. With our recipe site, we want to make it really easy for people to fix typos or add notes, without having to understand PHP. Also, there’s the added benefit that static HTML pages load really fast. Jekyll isn’t officially supported on Windows, but it is still possible to run it if you’re prepared to get your hands dirty. Install Jekyll Back in Terminal, we’re going to install Jekyll… gem install jekyll …and wait for the script to run. This might take a few moments. It might take so long that you get worried its broken, but resist the urge to start mashing your keyboard like I did. Get Jekyll to run on the repository Fingers crossed nothing has gone wrong so far. If something did go wrong, don’t give up! Check this helpful post by Andy Taylor – you probably just need to install something else first. Now we’re going to tell Jekyll to set up a new project in the repository, which is in my Sites folder (yours may be in a different place). Remember, we can drag the directory into the terminal window after the command. jekyll new /Users/Anna/Sites/christmas-recipes If everything went as expected, we should get this error message: Conflict: /Users/Anna/Sites/christmas-recipes exists and is not empty. But that’s OK. It’s just upset because we’ve got that index.html file and possibly also a README.md in there that we made earlier. So move those onto your desktop for the moment and run the command again. jekyll new /Users/Anna/Sites/christmas-recipes It should say that the site has installed. Check you’re in the repository, and if you’re not, navigate to it by typing cd , drag the christmas-recipes directory into terminal… jekyll cd /Users/Anna/Sites/christmas-recipes …and type this command to tell Jekyll to run: jekyll serve --watch By adding --watch at the end, we’re forcing Jekyll to rebuild the site every time we hit Save, so we don’t have to keep telling it to update every time we want to view the changes. We’ll need to run this every time we start work on the project, otherwise changes won’t be applied. For now, wait while it does its thing. Update the config file When it’s finished, we’ll see the text press ctrl-c to stop. Don’t do that, though. Instead, open up the directory. You’ll notice some new files and folders in there. There’s one called _site, and that’s where all the site files are saved when they’re turned into static HTML. Don’t touch the files in here — they’re the generated files and will get overwritten every time we make changes to pages and layouts. There’s a file in our directory called _config.yml. This has some settings we can change, one of them being what our base URL is. GitHub Pages will assume the base URL is above the project repository, so changing the settings here will help further down the line when setting up navigation links. Replace the contents of the _config.yml file with this: name: Christmas Recipes markdown: redcarpet pygments: true baseurl: /christmas-recipes Set up your files Overwrite the index.html file in the root with the one we made earlier (you might want to pop the README.md back in there, too). Delete the files in the css folder — we’ll add our own later. View the Jekyll site Open up your favourite browser and type http://localhost:4000/christmas-recipes in the address bar. Check it out, that’s your site! But it could do with a bit more love. Set up the _includes files It’s always useful to be able to pull in snippets of content onto pages, such as the header and footer, so they only need to be updated in one place. That’s what an _includes folder is for in Jekyll. Create a folder in the root called _includes, and within it add two files: head.html and foot.html. In head.html, paste the following: <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>{{ page.title }}</title> <link rel="stylesheet" href="{{ site.baseurl }}/css/main.css" > </head> <body> and in foot.html: </body> </html> Whenever we want to pull in something from the _includes folder, we can use {% include filename.html %} in the layout file — I’ll show you how to set that up in next step. Making layouts In our directory, there’s a folder called _layouts and this lets us create a reusable template for pages. Inside that is a default.html file. Delete everything in default.html and paste in this instead: {% include head.html %} <h1>{{ page.title }}</h1> {{ content }} {% include foot.html %} That’s a very basic page with a header, footer, page title and some content. To apply this template to a page, go back into the index.html page and add this snippet to the very top of the file: --- layout: default title: Home --- Now save the index.html file and hit Refresh in the browser. We should see a heading where {{ page.title }} was in the layout, which matches what comes after title: on the page itself (in this case, Home). So, if we wanted a subheading to appear on every page, we could add {{ page.subheading }} to where we want it to appear in our layout file, and a line that says subheading: This is a subheading in between the dashes at the top of the page itself. Using Markdown for templates Anything on a page that sits under the closing dashes is output where {{ content }} appears in the template file. At the moment, this is being output as HTML, but we can use Markdown instead, and Jekyll will convert that into HTML. For this recipe site, we want to make it as easy as possible for people to be able to collaborate, and also have the markup separate from the content, so let’s use Markdown instead of HTML for the recipes. Telling a page to use Markdown instead of HTML is incredibly simple. All we need to do is change the filename from .html to .md, so let’s rename the index.html to index.md. Now we can use Markdown, and Jekyll will output that as HTML. Create a new layout We’re going to create a new layout called recipe which is going to be the template for any recipe page we create. Let’s keep it super simple. In the _layouts folder, create a file called recipe.html and paste in this: {% include head.html %} <main> <h1>{{ page.title }}</h1> {{ content }} <p>Recipe by <a href="{{ page.recipe-attribution-link }}">{{ page.recipe-attribution }}</a>.</p> </main> {% include nav.html %} {% include foot.html %} That’s our template. The content that goes on the recipe layout includes a page title, the recipe content, a recipe attribution and a recipe attribution link. Adding some recipe pages Create a new file in the root of the christmas-recipes folder and call it gingerbread.md. Paste the following into it: --- layout: recipe title: Gingerbread recipe-attribution: HungryJenny recipe-attribution-link: http://www.opensourcefood.com/people/HungryJenny/recipes/soft-christmas-gingerbread-cookies --- Makes about 15 small cookies. ## Ingredients * 175g plain flour * 90g brown sugar * 50g unsalted butter, diced, at room temperature * 2 tbsp golden syrup * 1 egg, beaten * 1 tsp ground ginger * 1 tsp cinnamon * 1 tsp bicarbonate of soda * Icing sugar to dust ## Method 1. Sift the flour, ginger, cinnamon and bicarbonate of soda into a large mixing bowl. 2. Use your fingers to rub in the diced butter. Mix in the sugar. 3. Mix the egg with the syrup then pour into the flour mixture. Fold in well to form a dough. 4. Tip some flour onto the work surface and knead the dough until smooth. 5. Preheat the oven to 180°C. 6. Roll the dough out flat and use a shaped cutter to make as many cookies as you like. 7. Transfer the cookies to a tray and bake in the oven for 15 minutes. Lightly dust the cookies with icing sugar. The content is in Markdown, and when we hit Save, it’ll be converted into HTML in the _site folder. Save the file, and go to http://localhost:4000/christmas-recipes/gingerbread.html in your favourite browser. As you can see, the Markdown content has been converted into HTML, and the attribution text and link has been inserted in the right place. Add some navigation In your _includes folder, create a new file called nav.html. Here is some code that will generate your navigation: <nav class="nav-primary" role="navigation" > <ul> {% for p in site.pages %} <li> <a {% if p.url == page.url %}class="active"{% endif %} href="{{ site.baseurl }}{{ p.url }}">{{ p.title }}</a> </li> {% endfor %} </ul> </nav> This is going to look for all pages and generate a list of them, and give the navigation item that is currently active a class of active so we can style it differently. Now we need to include that navigation snippet in our layout. Paste {% include nav.html %} in default.html file, under {{ content }}. Push the changes to GitHub Pages Now we’ve got a couple of pages, it’s time to push our changes to GitHub. We can do this in exactly the same way as before. Check your special GitHub URL (your-username.github.io/your-project-name) and you should see your site up and running. If you quit Terminal, don’t forget to run jekyll serve --watch from within the directory the next time you want to work on the files. Next steps Now we know the basics of creating Jekyll templates and publishing them as GitHub Pages, we can have some fun adding more pages and styling them up. Here’s one I made earlier I’ve only been using Jekyll for a matter of weeks, mainly for prototyping. It’s really good as a content management system for blogs, and a lot of people host their Jekyll blogs on GitHub, such as Harry Roberts By hosting the code so openly it will make me take more pride in it and allow me to work on it much more easily; no excuses now! Overall, the documentation for Jekyll feels a little sparse and geared more towards blogs than other sites, but as more people discover the benefits of it, I’m sure this will improve over time. If you’re interested in poking about with some code, all the files from this tutorial are available on GitHub. 2013 Anna Debenham annadebenham 2013-12-18T00:00:00+00:00 https://24ways.org/2013/get-started-with-github-pages/  
125 Accessible Dynamic Links Although hyperlinks are the soul of the World Wide Web, it’s worth using them in moderation. Too many links becomes a barrier for visitors navigating their way through a page. This difficulty is multiplied when the visitor is using assistive technology, or is using a keyboard; being able to skip over a block of links doesn’t make the task of finding a specific link any easier. In an effort to make sites easier to use, various user interfaces based on the hiding and showing of links have been crafted. From drop-down menus to expose the deeper structure of a website, to a decluttering of skip links so as not to impact design considerations. Both are well intentioned with the aim of preserving a good usability experience for the majority of a website’s audience; hiding the real complexity of a page until the visitor interacts with the element. When JavaScript is not available The modern dynamic link techniques rely on JavaScript and CSS, but regardless of whether scripting and styles are enabled or not, we should consider the accessibility implications, particularly for screen-reader users, and people who rely on keyboard access. In typical web standards-based drop-down navigation implementations, the rough consensus is that the navigation should be structured as nested lists so when JavaScript is not available the entire navigation map is available to the visitor. This creates a situation where a visitor is faced with potentially well over 50 links on every page of the website. Keyboard access to such structures is frustrating, there’s far too many options, and the method of serially tabbing through each link looking for a specific one is tedious. Instead of offering the visitor an indigestible chunk of links when JavaScript is not available, consider instead having the minimum number of links on a page, and when JavaScript is available bringing in the extra links dynamically. Santa Chris Heilmann offers an excellent proof of concept in making Ajax navigation optional. When JavaScript is enabled, we need to decide how to hide links. One technique offers a means of comprehensively hiding links from keyboard users and assistive technology users. Another technique allows keyboard and screen-reader users to access links while they are hidden, and making them visible when reached. Hiding the links In JavaScript enhanced pages whether a link displays on screen depends on a certain event happening first. For example, a visitor needs to click a top-level navigation link that makes a set of sub-navigation links appear. In these cases, we need to ensure that these links are not available to any user until that event has happened. The typical way of hiding links is to style the anchor elements, or its parent nodes with display: none. This has the advantage of taking the links out of the tab order, so they are not focusable. It’s useful in reducing the number of links presented to a screen-reader or keyboard user to a minimum. Although the links are still in the document (they can be referenced and manipulated using DOM Scripting), they are not directly triggerable by a visitor. Once the necessary event has happened, like our visitor has clicked on a top-level navigation link which shows our hidden set of links, then we can display the links to the visitor and make them triggerable. This is done simply by undoing the display: none, perhaps by setting the display back to block for block level elements, or inline for inline elements. For as long as this display style remains, the links are in the tab order, focusable by keyboard, and triggerable. A common mistake in this situation is to use visibility: hidden, text-indent: -999em, or position: absolute with left: -999em to position these links off-screen. But all of these links remain accessible via keyboard tabbing even though the links remain hidden from screen view. In some ways this is a good idea, but for hiding sub-navigation links, it presents the screen-reader user and keyboard user with too many links to be of practical use. Moving the links out of sight If you want a set of text links accessible to screen-readers and keyboard users, but don’t want them cluttering up space on the screen, then style the links with position: absolute; left: -999em. Links styled this way remain in the tab order, and are accessible via keyboard. (The position: absolute is added as a style to the link, not to a parent node of the link – this will give us a useful hook to solve the next problem). a.helper { position: absolute; left: -999em; } One important requirement when displaying links off-screen is that they are visible to a keyboard user when they receive focus. Tabbing on a link that is not visible is a usability mudpit, since the visitor has no visible cue as to what a focused link will do, or where it will go. The simple answer is to restyle the link so that it appears on the screen when the hidden link receives focus. The anchor’s :focus pseudo-class is a logical hook to use, and with the following style repositions the link onscreen when it receives the focus: a.helper:focus, a.helper.focus { top: 0; left: 0; } This technique is useful for hiding skip links, and options you want screen-reader and keyboard users to use, but don’t want cluttering up the page. Unfortunately Internet Explorer 6 and 7 don’t support the focus pseudo-class, which is why there’s a second CSS selector a.helper.focus so we can use some JavaScript to help out. When the page loads, we look for all links that have a class of helper and add in onfocus and onblur event handlers: if (anchor.className == "helper") { anchor.onfocus = function() { this.className = 'helper focus'; } anchor.onblur = function() { this.className = 'helper'; } } Since we are using JavaScript to cover up for deficiencies in Internet Explorer, it makes sense to use JavaScript initially to place the links off-screen. That way an Internet Explorer user with JavaScript disabled can still use the skip link functionality. It is vital that the number of links rendered in this way is kept to a minimum. Every link you offer needs to be tabbed through, and gets read out in a screen reader. Offer these off-screen links that directly benefit these types of visitor. Andy Clarke and Kimberly Blessing use a similar technique in the Web Standards Project‘s latest design, but their technique involves hiding the skip link in plain sight and making it visible when it receives focus. Navigate the page using just the tab key to see the accessibility-related links appear when they receive focus. This technique is also a good way of hiding image replaced text. That way the screen-readers still get the actual text, and the website still gets its designed look. Which way? If the links are not meant to be reachable until a certain event has occurred, then the display: none technique is the preferred approach. If you want the links accessible but out of the way until they receive focus, then the off-screen positioning (or Andy’s hiding in plain sight technique) is the way to go. 2006 Mike Davies mikedavies 2006-12-05T00:00:00+00:00 https://24ways.org/2006/accessible-dynamic-links/ ux
231 Designing for iOS: Life Beyond Media Queries Although not a new phenomenon, media queries seem to be getting a lot attention online recently and for the right reasons too – it’s great to be able to adapt a design with just a few lines of CSS – but many people are relying only on them to create an iPhone-specific version of their website. I was pleased to hear at FOWD NYC a few weeks ago that both myself and Aral Balkan share the same views on why media queries aren’t always going to be the best solution for mobile. Both of us specialise in iPhone design ourselves and we opt for a different approach to media queries. The trouble is, regardless of what you have carefully selected to be display:none; in your CSS, the iPhone still loads everything in the background; all that large imagery for your full scale website also takes up valuable mobile bandwidth and time. You can greatly increase the speed of your website by creating a specific site tailored to mobile users with just a few handy pointers – media queries, in some instances, might be perfectly suitable but, in others, here’s what you can do. Redirect your iPhone/iPod Touch users To detect whether someone is viewing your site on an iPhone or iPod Touch, you can either use JavaScript or PHP. The JavaScript if((navigator.userAgent.match(/iPhone/i)) || (navigator.userAgent.match(/iPod/i))) { if (document.cookie.indexOf("iphone_redirect=false") == -1) window.location = "http://mobile.yoursitehere.com"; } The PHP if(strstr($_SERVER['HTTP_USER_AGENT'],'iPhone') || strstr($_SERVER['HTTP_USER_AGENT'],'iPod')) { header('Location: http://mobile.yoursitehere.com'); exit(); } Both of these methods redirect the user to a site that you have made specifically for the iPhone. At this point, be sure to provide a link to the full version of the website, in case the user wishes to view this and not be thrown into an experience they didn’t want, with no way back. Tailoring your site So, now you’ve got 320 × 480 pixels of screen to play with – and to create a style sheet for, just as you would for any other site you build. There are a few other bits and pieces that you can add to your code to create a site that feels more like a fully immersive iPhone app rather than a website. Retina display When building your website specifically tailored to the iPhone, you might like to go one step further and create a specific style sheet for iPhone 4’s Retina display. Because there are four times as many pixels on the iPhone 4 (640 × 960 pixels), you’ll find specifics such as text shadows and borders will have to be increased. <link rel="stylesheet" media="only screen and (-webkit-min-device-pixel-ratio: 2)" type="text/css" href="../iphone4.css" /> (Credit to Thomas Maier) Prevent user scaling This declaration, added into the <head>, stops the user being able to pinch-zoom in and out of your design, which is perfect if you are designing to the exact pixel measurements of the iPhone screen. <meta name="viewport" content="width=device-width; initial-scale=1.0; maximum-scale=1.0;"> Designing for orientation As iPhones aren’t static devices, you’ll also need to provide a style sheet for horizontal orientation. We can do this by inserting some JavaScript into the <head> as follows: <script type="text/javascript"> function orient() { switch(window.orientation) { case 0: document.getElementById("orient_css").href = "css/iphone_portrait.css"; break; case -90: document.getElementById("orient_css").href = "css/iphone_landscape.css"; break; case 90: document.getElementById("orient_css").href = "css/iphone_landscape.css"; break; } } window.onload = orient(); </script> You can also specify orientation styles using media queries. This is absolutely fine, as by this point you’ll already be working with mobile-specific graphics and have little need to set a lot of things to display:none; <link rel="stylesheet" media="only screen and (max-device-width: 480px)" href="/iphone.css"> <link rel="stylesheet" media="only screen and (orientation: portrait)" href="/portrait.css"> <link rel="stylesheet" media="only screen and (orientation: landscape)” href="/landscape.css"> Remove the address and status bars, top and bottom To give you more room on-screen and to make your site feel more like an immersive web app, you can place the following declaration into the <head> of your document’s code to remove the address and status bars at the top and bottom of the screen. <meta name="apple-mobile-web-app-capable" content="yes" /> Making the most of inbuilt functions Similar to mailto: e-mail links, the iPhone also supports another two handy URI schemes which are great for enhancing contact details. When tapped, the following links will automatically bring up the appropriate call or text interface: <a href="tel:01234567890">Call us</a> <a href="sms:01234567890">Text us</a> iPhone-specific Web Clip icon Although I believe them to be fundamentally flawed, since they rely on the user bookmarking your site, iPhone Web Clip icons are still a nice touch. You need just two declarations, again in the <head> of your document: <link rel="apple-touch-icon" href="icons/regular_icon.png" /> <link rel="apple-touch-icon" sizes="114x114" href="icons/retina_icon.png" /> For iPhone 4 you’ll need to create a 114 × 114 pixels icon; for a non-Retina display, a 57 × 57 pixels icon will do the trick. Precomposed Apple adds its standard gloss ‘moon’ over the top of any icon. If you feel this might be too much for your particular icon and would prefer a matte finish, you can add precomposed to the end of the apple-touch-icon declaration to remove the standard gloss. <link rel="apple-touch-icon-precomposed" href="/images/touch-icon.png" /> Wrapping up Media queries definitely have their uses. They make it easy to build a custom experience for your visitor, regardless of their browser’s size. For more complex sites, however, or where you have lots of imagery and other content that isn’t necessary on the mobile version, you can now use these other methods to help you out. Remember, they are purely for presentation and not optimisation; for busy people on the go, optimisation and faster-running mobile experiences can only be a good thing. Have a wonderful Christmas fellow Webbies! 2010 Sarah Parmenter sarahparmenter 2010-12-17T00:00:00+00:00 https://24ways.org/2010/life-beyond-media-queries/ code
324 Debugging CSS with the DOM Inspector An Inspector Calls The larger your site and your CSS becomes, the more likely that you will run into bizarre, inexplicable problems. Why does that heading have all that extra padding? Why is my text the wrong colour? Why does my navigation have a large moose dressed as Noel Coward on top of all the links? Perhaps you work in a collaborative environment, where developers and other designers are adding code? In which case, the likelihood of CSS strangeness is higher. You need to debug. You need Firefox’s wise-guy know-it-all, the DOM Inspector. The DOM Inspector knows where everything is in your layout, and more importantly, what causes it to look the way it does. So without further ado, load up any css based site in your copy of Firefox (or Flock for that matter), and launch the DOM Inspector from the Tools menu. The inspector uses two main panels – the left to show the DOM tree of the page, and the right to show you detail: The Inspector will look at whatever site is in the front-most window or tab, but you can also use it without another window. Type in a URL at the top (A), press ‘Inspect’ (B) and a third panel appears at the bottom, with the browser view. I find this layout handier than looking at a window behind the DOM Inspector. Step 1 – find your node! Each element on your page – be it a HTML tag or a piece of text, is called a ‘node’ of the DOM tree. These nodes are all listed in the left hand panel, with any ID or CLASS attribute values next to them. When you first look at a page, you won’t see all those yet. Nested HTML elements (such as a link inside a paragraph) have a reveal triangle next to their name, clicking this takes you one level further down. This can be fine for finding the node you want to look at, but there are easier ways. Say you have a complex rounded box technique that involves 6 nested DIVs? You’d soon get tired of clicking all those triangles to find the element you want to inspect. Click the top left icon © – “Find a node to inspect by clicking on it” and then select the area you want to inspect. Boom! All that drilling down the DOM tree has been done for you! Huzzah! If you’re looking for an element that you know has an ID (such as <ul id="navigation">), or a specific HTML tag or attribute, click the binoculars icon (D) for “Finds a node to inspect by ID, tag or attribute” (You can also use Ctrl-F or Apple-F to do this if the DOM Inspector is the frontmost window) : Type in the name and Bam! You’re there! Pressing F3 will take you to any other instances. Notice also, that when you click on a node in the inspector, it highlights where it is in the browser view with a flashing red border! Now that we’ve found the troublesome node on the page, we can find out what’s up with it… Step 2 – Debug that node! Once the node is selected, we move over to the right hand panel. Choose ‘CSS Style Rules’ from the document menu (E), and all the CSS rules that apply to that node are revealed, in the order that they load: You’ll notice that right at the top, there is a CSS file you might not recognise, with a file path beginning with “resource://”. This is the browsers default CSS, that creates the basic rendering. You can mostly ignore this, especially if use the star selector method of resetting default browser styles. Your style sheets come next. See how helpful it is? It even tells you the line number where to find the related CSS rules! If you use CSS shorthand, you’ll notice that the values are split up (e.g margin-left, margin-right etc.). Now that you can see all the style rules affecting that node, the rest is up to you! Happy debugging! 2005 Jon Hicks jonhicks 2005-12-22T00:00:00+00:00 https://24ways.org/2005/debugging-css-with-the-dom-inspector/ process
247 Managing Flow and Rhythm with CSS Custom Properties An important part of designing user interfaces is creating consistent vertical rhythm between elements. Creating consistent, predictable space doesn’t just make your web pages and views look better, but it can also improve the scan-ability. Browsers ship with default CSS and these styles often create consistent rhythm for flow elements out of the box. The problem is though that we often reset these styles with a reset. Elements such as <div> and <section> also have no default margin or padding associated with them. I’ve tried all sorts of weird and wonderful techniques to find a balance between using inherited CSS while also levelling the playing field for component driven front-ends with very little success. This experimentation is how I landed on the flow utility, though and I’m going to show you how it works. Let’s dive in! The Flow utility With the ever-growing number of folks working with component libraries and design systems, we could benefit from a utility that creates space for us, only when it’s appropriate to do so. The problem with my previous attempts at fixing this is that the spacing values were very rigid. That’s fine for 90% of contexts, but sometimes, it’s handy to be able to tweak the values based on the exact context of your component. This is where CSS Custom Properties come in handy. The code .flow { --flow-space: 1em; } .flow > * + * { margin-top: var(--flow-space); } What this code does is enable you to add a class of flow to an element which will then add margin-top to sibling elements within that element. We use the lobotomised owl selector to select these siblings. This approach enables an almost anonymous and automatic system which is ideal for component library based front-ends where components probably don’t have any idea what surrounds them. The other important part of this utility is the usage of the --flow-space custom property. We define it in the .flow component and each element within it will be spaced by --flow-space, by default. The beauty about setting this as a custom property is that custom properties also participate in the cascade, so we can utilise specificity to change it if we need it. Pretty cool, right? Let’s look at some examples. A basic example See the Pen CSS Flow Utility: Basic implementation by Andy Bell (@hankchizljaw) on CodePen. https://codepen.io/hankchizljaw/pen/LXqerj What we’ve got in this example is some basic HTML content that has a class of flow on the parent article element. Because there’s a very heavy-handed reset added as a dependency, all of the content would have been squished together without the flow utility. Because our --flow-space custom property is set to 1em, the space between elements is 1X the font size of the element in question. This means that a <h2> in this context has a calculated margin-top value of 28.8px, because it has an assigned font size of 1.8rem. If we were to globally change the --flow-space value to 1.1em for example, we’d affect everything because margin values would be calculated as 1.1X the font size. This example looks great because using font size as the basis of rhythm works really well. What if we wanted to to tweak certain elements within this article, though? See the Pen CSS Flow Utility: Tweaked Basic implementation by Andy Bell (@hankchizljaw) on CodePen. https://codepen.io/hankchizljaw/pen/qQgxaY I like lots of whitespace with my article layouts, so the 1em space isn’t going to cut it for all elements. I like to provide plenty of space between headed sections, so I increase the --flow-space in these instances: h2 { --flow-space: 3rem; } Notice also how I also switch over to using rem units? I want to make sure that these overrides are always based on the root font size. This is a personal preference of mine and you can use whatever units you want. Just be aware that it’s better for accessibility to use flexible units like em, rem and %, so that a user’s font size preferences are honoured. A more advanced example Although the flow utility is super useful for a plethora of contexts, it really shines when working with a few unrelated components. Instead of having to write specific layout CSS just for your particular context, you can use flow and --flow-space to create predictable and contextual space. See the Pen CSS Flow Utility: Unrelated components by Andy Bell (@hankchizljaw) on CodePen. https://codepen.io/hankchizljaw/pen/ZmPGyL In this example, we’ve got ourselves a little prototype layout that features a media element, followed by a grid of features. By using flow, it was really quick and easy to generate space between those two main elements. It was also easy to create space within the components. For example, I added it to the .media__content element, so that the article’s content would space itself: <article class="media__content flow"> ... </article> Something to remember though: the custom properties cascade in the same way that other CSS values do, so you’ve got to keep that in mind. We’ve got a great example of that in this example where because we’ve got the flow utility on our .features component, which has a --flow-space override: the child elements of .features will inherit that value, so we’ve had to set another value on the .features__list element. “But what about old browsers?”, I hear you cry We’re using CSS Custom Properties that at the time of writing, have about 88% support. One thing we can do to remedy the other 12% of browsers is to set a default, traditional margin-top value of 1em, so it calculates itself based on the element’s font-size: .flow { --flow-space: 1em; } .flow > * + * { margin-top: 1em; margin-top: var(--flow-space); } Thanks to the cascading and declarative nature of CSS, we can set that default margin-top value and then immediately set it to use the custom property instead. Browsers that understand Custom Properties will automatically apply them—those that don’t will ignore them. Yay for the cascade and progressive enhancement! Wrapping up This tiny little utility can bring great power for when you want to consistently space elements, vertically. It also—thanks to the power of the modern web—allows us to create contextual overrides without creating modifier classes or shame CSS. If you’ve got other methods of doing this sort of work, please let me know on Twitter. I’d love to see what you’re working on! 2018 Andy Bell andybell 2018-12-07T00:00:00+00:00 https://24ways.org/2018/managing-flow-and-rhythm-with-css-custom-properties/ code
61 Animation in Responsive Design Animation and responsive design can sometimes feel like they’re at odds with each other. Animation often needs space to do its thing, but RWD tells us that the amount of space we’ll have available is going to change a lot. Balancing that can lead to some tricky animation situations. Embracing the squishiness of responsive design doesn’t have to mean giving up on your creative animation ideas. There are three general techniques that can help you balance your web animation creativity with your responsive design needs. One or all of these approaches might help you sneak in something just a little extra into your next project. Focused art direction Smaller viewports mean a smaller stage for your motion to play out on, and this tends to amplify any motion in your animation. Suddenly 100 pixels is really far and multiple moving parts can start looking like they’re battling for space. An effect that looked great on big viewports can become muddled and confusing when it’s reframed in a smaller space. Making animated movements smaller will do the trick for simple motion like a basic move across the screen. But for more complex animation on smaller viewports, you’ll need to simplify and reduce the number of moving parts. The key to this is determining what the vital parts of the animation are, to zone in on the parts that are most important to its message. Then remove the less necessary bits to distill the motion’s message down to the essentials. For example, Rally Interactive’s navigation folds down into place with two triangle shapes unfolding each corner on larger viewports. If this exact motion was just scaled down for narrower spaces the two corners would overlap as they unfolded. It would look unnatural and wouldn’t make much sense. Open video The main purpose of this animation is to show an unfolding action. To simplify the animation, Rally unfolds only one side for narrower viewports, with a slightly different animation. The action is still easily interpreted as unfolding and it’s done in a way that is a better fit for the available space. The message the motion was meant to convey has been preserved while the amount of motion was simplified. Open video Si Digital does something similar. The main concept of the design is to portray the studio as a creative lab. On large viewports, this is accomplished primarily through an animated illustration that runs the full length of the site and triggers its animations based on your scroll position. The illustration is there to support the laboratory concept visually, but it doesn’t contain critical content. Open video At first, it looks like Si Digital just turned off the animation of the illustration for smaller viewports. But they’ve actually been a little cleverer than that. They’ve also reduced the complexity of the illustration itself. Both the amount of motion (reduced down to no motion) and the illustration were simplified to create a result that is much easier to glean the concept from. Open video The most interesting thing about these two examples is that they’re solved more with thoughtful art direction than complex code. Keeping the main concept of the animations at the forefront allowed each to adapt creative design solutions to viewports of varying size without losing the integrity of their design. Responsive choreography Static content gets moved around all the time in responsive design. A three-column layout might line up from left to right on wide viewports, then stack top to bottom on narrower viewports. The same approach can be used to arrange animated content for narrower views, but the animation’s choreography also needs to be adjusted for the new layout. Even with static content, just scaling it down or zooming out to fit it into the available space is rarely an ideal solution. Rearranging your animations’ choreography to change which animation starts when, or even which animations play at all, keeps your animated content readable on smaller viewports. In a recent project I had three small animations that played one after the other, left to right, on wider viewports but needed to be stacked on narrower viewports to be large enough to see. On wide viewports, all three animations could play one right after the other in sequence because all three were in the viewable area at the same time. But once these were stacked for the narrower viewport layouts, that sequence had to change. Open video What was essentially one animation on wider viewports became three separate animations when stacked on narrower viewports. The layout change meant the choreography had to change as well. Each animation starts independently when it comes into view in the stacked layout instead of playing automatically in sequence. (I’ve put the animated parts in this demo if you want to peek under the hood.) Open video I choose to use the GreenSock library, with the choreography defined in two different timelines for this particular project. But the same goals could be accomplished with other JavaScript options or even CSS keyframe animations and media queries. Even more complex responsive choreography can be pulled off with SVG. Media queries can be used to change CSS animations applied to SVG elements at specific breakpoints for starters. For even more responsive power, SVG’s viewBox property, and the positioning of the objects within it, can be adjusted at JavaScript-defined breakpoints. This lets you set rules to crop the viewable area and arrange your animating elements to fit any space. Sarah Drasner has some great examples of how to use this technique with style in this responsive infographic and this responsive interactive illustration. On the other hand, if smart scalability is what you’re after, it’s also possible to make all of an SVG’s shapes and motion scale with the SVG canvas itself. Sarah covers both these clever responsive SVG techniques in detail. Creative and complex animation can easily become responsive thanks to the power of SVG! Open video Bake performance into your design decisions It’s hard to get very far into a responsive design discussion before performance comes up. Performance goes hand in hand with responsive design and your animation decisions can have a big impact on the overall performance of your site. The translate3D “hack”, backface-visibility:hidden, and the will-change property are the heavy hitters of animation performance. But decisions made earlier in your animation design process can have a big impact on rendering performance and your performance budget too. Pick a technology that matches your needs One of the biggest advantages of the current web animation landscape is the range of tools we have available to us. We can use CSS animations and transitions to add just a dash of interface animation to our work, go all out with webGL to create a 3D experience, or anywhere in between. All within our browsers! Having this huge range of options is amazing and wonderful but it also means you need to be cognizant of what you’re using to get the job done. Loading in the full weight of a robust JavaScript animation library is going to be overkill if you’re only animating a few small elements here and there. That extra overhead will have an impact on performance. Performance budgets will not be pleased. Always match the complexity of the technology you choose to the complexity of your animation needs to avoid unnecessary performance strain. For small amounts of animation, stick to CSS solutions since it’s the most lightweight option. As your animations grow in complexity, or start to require more robust logic, move to a JavaScript solution that can accomplish what you need. Animate the most performant properties Whether you’re animating in CSS or JavaScript, you’re affecting specific properties of the animated element. Browsers can animate some properties more efficiently than others based on how many steps need to happen behind the scenes to visually update those properties. Browsers are particularly efficient at animating opacity, scale, rotation, and position (when the latter three are done with transforms). This article from Paul Irish and Paul Lewis gives the full scoop on why. Conveniently, those are also the most common properties used in motion design. There aren’t many animated effects that can’t be pulled off with this list. Stick to these properties to set your animations up for the best performance results from the start. If you find yourself needing to animate a property outside of this list, check CSS Triggers… to find out how much of an additional impact it might have. Offset animation start times Offsets (the concept of having a series of similar movements execute one slightly after the other, creating a wave-like pattern) are a long-held motion graphics trick for creating more interesting and organic looking motion. Employing this trick of the trade can also be smart for performance. Animating a large number of objects all at the same time can put a strain on the browser’s rendering abilities even in the best cases. Adding short delays to offset these animations in time, so they don’t all start at once, can improve rendering performance. Go explore the responsive animation possibilities for yourself! With smart art direction, responsive choreography, and an eye on performance you can create just about any creative web animation you can think up while still being responsive. Keep these in mind for your next project and you’ll pull off your animations with style at any viewport size! 2015 Val Head valhead 2015-12-09T00:00:00+00:00 https://24ways.org/2015/animation-in-responsive-design/ design
86 Flashless Animation Animation in a Flashless world When I splashed down in web design four years ago, the first thing I wanted to do was animate a cartoon in the browser. I’d been drawing comics for years, and I’ve wanted to see them come to life for nearly as long. Flash animation was still riding high, but I didn’t want to learn Flash. I wanted to learn JavaScript! Sadly, animating with JavaScript was limiting and resource-intensive. My initial foray into an infinitely looping background did more to burn a hole in my CPU than amaze my friends (although it still looks pretty cool). And there was still no simple way to incorporate audio. The browser technology just wasn’t there. Things are different now. CSS3 transitions and animations can do most of the heavy lifting and HTML5 audio can serve up the music and audio clips. You can do a lot without leaning on JavaScript at all, and when you lean on JavaScript, you can do so much more! In this project, I’m going to show you how to animate a simple walk cycle with looping audio. I hope this will inspire you to do something really cool and impress your friends. I’d love to see what you come up with, so please send your creations my way at rachelnabors.com! Note: Because every browser wants to use its own prefixes with CSS3 animations, and I have neither the time nor the space to write all of them out, I will use the W3C standard syntaxes; that is, going prefix-less. You can implement them out of the box with something like Prefixfree, or you can add prefixes on your own. If you take the latter route, I recommend using Sass and Compass so you can focus on your animations, not copying and pasting. The walk cycle Walk cycles are the “Hello world” of animation. One of the first projects of animation students is to spend hours drawing dozens of frames to complete a simple loopable animation of a character walking. Most animators don’t have to draw every frame themselves, though. They draw a few key frames and send those on to production animators to work on the between frames (or tween frames). This is meticulous, grueling work requiring an eye for detail and natural movement. This is also why so much production animation gets shipped overseas where labor is cheaper. Luckily, we don’t have to worry about our frame count because we can set our own frames-per-second rate on the fly in CSS3. Since we’re trying to impress friends, not animation directors, the inconsistency shouldn’t be a problem. (Unless your friend is an animation director.) This is a simple walk cycle I made of my comic character Tuna for my CSS animation talk at CSS Dev Conference this year: The magic lies here: animation: walk-cycle 1s steps(12) infinite; Breaking those properties down: animation: <name> <duration> <timing-function> <iteration-count>; walk-cycle is a simple @keyframes block that moves the background sprite on .tuna around: @keyframes walk-cycle { 0% {background-position: 0 0; } 100% {background-position: 0 -2391px;} } The background sprite has exactly twelve images of Tuna that complete a full walk cycle. We’re setting it to cycle through the entire sprite every second, infinitely. So why isn’t the background image scrolling down the .tuna container? It’s all down to the timing function steps(). Using steps() let us tell the CSS to make jumps instead of the smooth transitions you’d get from something like linear. Chris Mills at dev.opera wrote in his excellent intro to CSS3 animation : Instead of giving a smooth animation throughout, [steps()] causes the animation to jump between a set number of steps placed equally along the duration. For example, steps(10) would make the animation jump along in ten equal steps. There’s also an optional second parameter that takes a value of start or end. steps(10, start) would specify that the change in property value should happen at the start of each step, while steps(10, end) means the change would come at the end. (Seriously, go read his full article. I’m not going to touch on half the stuff he does because I cannot improve on the basics any more than he already has.) The background A cat walking in a void is hardly an impressive animation and certainly your buddy one cube over could do it if he chopped up some of those cat GIFs he keeps using in group chat. So let’s add a parallax background! Yes, yes, all web designers signed a peace treaty to not abuse parallax anymore, but this is its true calling—treaty be damned. And to think we used to need JavaScript to do this! It’s still pretty CPU intensive but much less complicated. We start by splitting up the page into different layers, .foreground, .midground, and .background. We put .tuna in the .midground. .background has multiple background images, all set to repeat horizontally: background-image: url(background_mountain5.png), url(background_mountain4.png), url(background_mountain3.png), url(background_mountain2.png), url(background_mountain1.png); background-repeat: repeat-x; With parallax, things in the foreground move faster than those in the background. Next time you’re driving, notice how the things closer to you move out of your field of vision faster than something in the distance, like a mountain or a large building. We can imitate that here by making the background images on top (in the foreground, closer to us) wider than those on the bottom of the stack (in the distance). The different lengths let us use one animation to move all the background images at different rates in the same interval of time: animation: parallax_bg linear 40s infinite; The shorter images have less distance to cover in the same amount of time as the longer images, so they move slower. Let’s have a look at the background’s animation: @keyframes parallax_bg { 0% { background-position: -2400px 100%, -2000px 100%, -1800px 100%, -1600px 100%, -1200px 100%; } 100% { background-position: 0 100%, 0 100%, 0 100%, 0 100%, 0 100%; } } At 0%, all the background images are positioned at the negative value of their own widths. Then they start moving toward background-position: 0 100%. If we wanted to move them in the reverse direction, we’d remove the negative values at 0% (so they would start at 2400px 100%, 2000px 100%, etc.). Try changing the values in the codepen above or changing background-repeat to none to see how the images play together. .foreground and .midground operate on the same principles, only they use single background images. The music After finishing the first draft of my original walk cycle, I made a GIF with it and posted it on YTMND with some music from the movie Paprika, specifically the track “The Girl in Byakkoya.” After showing it to some colleagues in my community, it became clear that this was a winning combination sure to drive away dresscode blues. So let’s use HTML5 to get a clip of that music looping in there! Warning, there is sound. Please adjust your volume or apply headphones as needed. We’re using HTML5 audio’s loop and autoplay abilities to automatically play and loop a sound file on page load: <audio loop autoplay> <source src="http://music.com/clip.mp3" /> </audio> Unfortunately, you may notice there is a small pause between loops. HTML5 audio, thou art half-baked still. Let’s hope one day the Web Audio API will be able to help us out, but until things improve, we’ll have to hack our way around these shortcomings. Turns out there’s a handy little script called seamlessLoop.js which we can use to patch this. Mind you, if we were really getting crazy with the Cheese Whiz, we’d want to get out big guns like sound.js. But that’d be overkill for a mere loop (and explaining the Web Audio API might bore, rather than impress your friends)! Installing seamlessLoop.js will get rid of the pause, and now our walk cycle is complete. (I’ve done some very rough sniffing to see if the browser can play MP3 files. If not, we fall back to using .ogg formatted clips (Opera and Firefox users, you’re welcome).) Really impress your friends by adding a run cycle So we have music, we have a walk cycle, we have parallax. It will be a snap to bring them all together and have a simple, endless animation. But let’s go one step further and knock the socks off our viewers by adding a run cycle. The run cycle Tacking a run cycle on to our walk cycle will require a third animation sequence: a transitional animation of Tuna switching from walking to running. I have added all these to the sprite: Let’s work on getting that transition down. We’re going to use multiple animations on the same .tuna div, but we’re going to kick them off at different intervals using animation-delay—no JavaScript required! Isn’t that magical? It requires a wee bit of math (not much, it doesn’t hurt) to line them up. We want to: Loop the walk animation twice Play the transitional cycle once (it has a finite beginning and end perfectly drawn to pick up between the last frame of the walk cycle and the first frame of the run cycle—no looping this baby) RUN FOREVER. Using the pattern animation: <name> <duration> <timing-function> <delay> <iteration-count>, here’s what that looks like: animation: walk-cycle 1s steps(12) 2, walk-to-run .75s steps(12) 2s 1, run-cycle .75s steps(13) 2.75s infinite; I played with the times to get make the movement more realistic. You may notice that the running animation looks smoother than the walking animation. That’s because it has 13 keyframes running over .75 second instead of 12 running in one second. Remember, professional animation studios use super-high frame counts. This little animation isn’t even up to PBS’s standards! The music: extended play with HTML5 audio sprites My favorite part in the The Girl in Byakkoya is when the calm opening builds and transitions into a bouncy motif. I want to start with Tuna walking during the opening, and then loop the running and bounciness together for infinity. The intro lasts for 24 seconds, so we set our 1 second walk cycle to run for 24 repetitions: walk-cycle 1s steps(12) 24 We delay walk-to-run by 24 seconds so it runs for .75 seconds before… We play run-cycle at 24.75 seconds and loop it infinitely For the music, we need to think of it as two parts: the intro and the bouncy loop. We can do this quite nicely with audio sprites: using one HTML5 audio element and using JavaScript to change the play head location, like skipping tracks with a CD player. Although this technique will result in a small gap in music shifts, I think it’s worth using here to give you some ideas. // Get the audio element var byakkoya = document.querySelector('audio'); // create function to play and loop audio function song(a){ //start playing at 0 a.currentTime = 0; a.play(); //when we hit 64 seconds... setTimeout(function(){ // skip back to 24.5 seconds and keep playing... a.currentTime = 24.55; // then loop back when we hit 64 again, or every 59.5 seconds. setInterval(function(){ a.currentTime = 24.55; },39450); },64000); } The load screen I’ve put it off as long as I can, but now that the music and the CSS are both running on their own separate clocks, it’s imperative that both images and music be fully downloaded and ready to run when we kick this thing off. So we need a load screen (also, it’s nice to give people a heads-up that you’re about to blast them with music, no matter how wonderful that music may be). Since the two timers are so closely linked, we’d best not run the animations until we run the music: * { animation-play-state: paused; } animation-play-state can be set to paused or running, and it’s the most useful thing you will learn today. First we use an event listener to see when the browser thinks we can play through from the beginning to end of the music without pause for buffering: byakkoya.addEventListener("canplaythrough", function () { }); (More on HTML5 audio’s media events at HTML5doctor.com) Inside our event listener, I use a bit of jQuery to add class of .playable to the body when we’re ready to enable the play button: $("body").addClass("playable"); $("#play-me").html("Play me.").click(function(){ song(byakkoya); $("body").addClass("playing"); }); That .playing class is special because it turns on the animations at the same time we start playing the song: .playing * { animation-play-state: running; } The background We’re almost done here! When we add the background, it needs to speed up at the same time that Tuna starts running. The music picks up speed around 24.75 seconds in, and so we’re going to use animation-delay on those backgrounds, too. This will require some math. If you try to simply shorten the animation’s duration at the 24.75s mark, the backgrounds will, mid-scroll, jump back to their initial background positions to start the new animation! Argh! So let’s make a new @keyframe and calculate where the background position would be just before we speed up the animation. Here’s the formula: new 0% value = delay ÷ old duration × length of image new 100% value = new 0% value + length of image Here’s the formula put to work on a smaller scale: Voilà! The finished animation! I’ve always wanted to bring my illustrations to life. Then I woke up one morning and realized that I had all the tools to do so in my browser and in my head. Now I have fallen in love with Flashless animation. I’m sure there will be detractors who say HTML wasn’t meant for this and it’s a gross abuse of the DOM! But I say that these explorations help us expand what we expect from devices and software and challenge us in good ways as artists and programmers. The browser might not be the most appropriate place for animation, but is certainly a fun place to start. There is so much you can do with the spec implemented today, and so much of the territory is still unexplored. I have not yet begun to show you everything. In eight months I expect this demo will represent the norm, not the bleeding edge. I look forward to seeing the wonderful things you create. (Also, someone, please, do something about that gappy HTML5 audio looping. It’s a crying shame!) 2012 Rachel Nabors rachelnabors 2012-12-06T00:00:00+00:00 https://24ways.org/2012/flashless-animation/ code
271 Creating Custom Font Stacks with Unicode-Range Any web designer or front-end developer worth their salt will be familiar with the CSS @font-face rule used for embedding fonts in a web page. We’ve all used it — either directly in our code ourselves, or via one of the web font services like Fontdeck, Typekit or Google Fonts. If you’re like me, however, you’ll be used to just copying and pasting in a specific incantation of lines designed to get different formats of fonts working in different browsers, and may not have really explored all the capabilities of @font-face properties as defined by the spec. One such property — the unicode-range descriptor — sounds pretty dull and is easily overlooked. It does, however, have some fairly interesting possibilities when put to use in creative ways. Unicode-range The unicode-range descriptor is designed to help when using fonts that don’t have full coverage of the characters used in a page. By adding a unicode-range property to a @font-face rule it is possible to specify the range of characters the font covers. @font-face { font-family: BBCBengali; src: url(fonts/BBCBengali.ttf) format("opentype"); unicode-range: U+00-FF; } In this example, the font is to be used for characters in the range of U+00 to U+FF which runs from the unexciting control characters at the start of the Unicode table (symbols like the exclamation mark start at U+21) right through to ÿ at U+FF – the extent of the Basic Latin character range. By adding multiple @font-face rules for the same family but with different ranges, you can build up complete coverage of the characters your page uses by using different fonts. When I say that it’s possible to specify the range of characters the font covers, that’s true, but what you’re really doing with the unicode-range property is declaring which characters the font should be used for. This becomes interesting, because instead of merely working with the technical constraints of available characters in a given font, we can start picking and choosing characters to use and selectively mix fonts together. The best available ampersand A few years back, Dan Cederholm wrote a post encouraging designers to use the best available ampersand. Dan went on to outline how this can be achieved by wrapping our ampersands in a <span> element with a class applied: <span class="amp">&</span> A CSS rule can then be written to select the <span> and apply a different font: span.amp { font-family: Baskerville, Palatino, "Book Antiqua", serif; } That’s a perfectly serviceable technique, but the drawbacks are clear — you have to add extra markup which is borderline presentational, and you also have to be able to add that markup, which isn’t always possible when working with a CMS. Perhaps we could do this with unicode-range. A better best available ampersand The Unicode code point for an ampersand is U+26, so the ampersand font stack above can be created like so: @font-face { font-family: 'Ampersand'; src: local('Baskerville'), local('Palatino'), local('Book Antiqua'); unicode-range: U+26; } What we’ve done here is specify a new family called Ampersand and created a font stack for it with the user’s locally installed copies of Baskerville, Palatino or Book Antiqua. We’ve then limited it to a single character range — the ampersand. Of course, those don’t need to be local fonts — they could be web font files, too. If you have a font with a really snazzy ampersand, go for your life. We can then use that new family in a regular font stack. h1 { font-family: Ampersand, Arial, sans-serif; } With this in place, any <h1> elements in our page will use the Ampersand family (Baskerville, Palatino or Book Antiqua) for ampersands, and Arial for all other characters. If the user doesn’t have any of the Ampersand family fonts available, the ampersand will fall back to the next item in the font stack, Arial. You didn’t think it was that easy, did you? Oh, if only it were so. The problem comes, as ever, with the issue of browser support. The unicode-range property has good support in WebKit browsers (like Safari and Chrome, and the browsers on most popular smartphone platforms) and in recent versions of Internet Explorer. The big stumbling block comes in the form of Firefox, which has no support at all. If you’re familiar with how CSS works when it comes to unsupported properties, you’ll know that if a browser encounters a property it doesn’t implement, it just skips that declaration and moves on to the next. That works perfectly for things like border-radius — if the browser can’t round off the corners, the declaration is skipped and the user sees square corners instead. Perfect. Less perfect when it comes to unicode-range, because if no range is specified then the default is that the font is applied for all characters — the whole range. If you’re using a fancy font for flamboyant ampersands, you probably don’t want that applied to all your text if unicode-range isn’t supported. That would be bad. Really bad. Ensuring good fallbacks As ever, the trick is to make sure that there’s a sensible fallback in place if a browser doesn’t have support for whatever technology you’re trying to use. This is where being a super nerd about understanding the spec you’re working with really pays off. We can make use of the rules of the CSS cascade to make sure that if unicode-range isn’t supported we get a sensible fallback font. What would be ideal is if we were able to follow up the @font-face rule with a second rule to override it if Unicode ranges aren’t implemented. @font-face { font-family: 'Ampersand'; src: local('Baskerville'), local('Palatino'), local('Book Antiqua'); unicode-range: U+26; } @font-face { font-family: 'Ampersand'; src: local('Arial'); } In theory, this code should make sense for all browsers. For those that support unicode-range the two rules become cumulative. They specify different ranges for the same family, and in WebKit browsers this has the expected result of using Arial for most characters, but Baskerville and friends for the ampersand. For browsers that don’t have support, the second rule should just supersede the first, setting the font to Arial. Unfortunately, this code causes current versions of Firefox to freak out and use the first rule, applying Baskerville to the entire range. That’s both unexpected and unfortunate. Bad Firefox. On your rug. If that doesn’t work, what can we do? Well, we know that if given a unicode-range Firefox will ignore the range and apply the font to all characters. That’s really what we’re trying to achieve. So what if we specified a range for the fallback font, but made sure it only covers some obscure high-value Unicode character we’re never going to use in our page? Then it wouldn’t affect the outcome for browsers that do support ranges. @font-face { font-family: 'Ampersand'; src: local('Baskerville'), local('Palatino'), local('Book Antiqua'); unicode-range: U+26; } @font-face { /* Ampersand fallback font */ font-family: 'Ampersand'; src: local('Arial'); unicode-range: U+270C; } By specifying a range on the fallback font, Firefox appears to correctly override the first based on the cascade sort order. Browsers that do support ranges take the second rule in addition, and apply Arial for that obscure character we’re not using in any of our pages — U+270C. So we get our nice ampersands in browsers that support unicode-range and, thanks to our styling of an obscure Unicode character, the font falls back to a perfectly acceptable Arial in browsers that do not offer support. Perfect! That obscure character, my friends, is what Unicode defines as the VICTORY HAND. ✌ So, how can we use this? Ampersands are a neat trick, and it works well in browsers that support ranges, but that’s not really the point of all this. Styling ampersands is fun, but they’re only really scratching the surface. Consider more involved examples, such as substituting a different font for numerals, or symbols, or even caps. Things certainly begin to get a bit more interesting. How do you know what the codes are for different characters? Richard Ishida has a handy online conversion tool available where you can type in the characters and get the Unicode code points out the other end. Of course, the fact remains that browser support for unicode-range is currently limited, so any application needs to have fallbacks that you’re still happy for a significant proportion of your visitors to see. In some cases, such as dedicated pages for mobile devices in an HTML-based phone app, this is immediately useful as support in WebKit browsers is already very good. In other cases, you’ll have to use your own best judgement based on your needs and audience. One thing to keep in mind is that if you’re using web fonts, the entire font will be downloaded even if only one character is used. That said, the font shouldn’t be downloaded if none of the characters within the Unicode range are present in a given page. As ever, there are pros and cons to using unicode-range as well as varied but increasing support in browsers. It remains a useful tool to understand and have in your toolkit for when the right moment comes along. 2011 Drew McLellan drewmclellan 2011-12-01T00:00:00+00:00 https://24ways.org/2011/creating-custom-font-stacks-with-unicode-range/ code
130 Faster Development with CSS Constants Anyone even slightly familiar with a programming language will have come across the concept of constants – a fixed value that can be used through your code. For example, in a PHP script I might have a constant which is the email address that all emails generated by my application get sent to. $adminEmail = 'info@example.com'; I could then use $adminEmail in my script whenever I wanted an email to go to that address. The benefit of this is that when the client decides they want the email to go to a different address, I only need change it in one place – the place where I initially set the constant. I could also quite easily make this value user defined and enable the administrator to update the email address. Unfortunately CSS doesn’t support constants. It would be really useful to be able to define certain values initially and then use them throughout a CSS file, so in this article I’m going to take a look at some of the methods we do have available and provide pointers to more in depth commentary on each. If you have a different method, or tip to share please add it to the comments. So what options do we have? One way to get round the lack of constants is to create some definitions at the top of your CSS file in comments, to define ‘constants’. A common use for this is to create a ‘color glossary’. This means that you have a quick reference to the colors used in the site to avoid using alternates by mistake and, if you need to change the colors, you have a quick list to go down and do a search and replace. In the below example, if I decide I want to change the mid grey to #999999, all I need to do is search and replace #666666 with #999999 – assuming I’ve remember to always use that value for things which are mid grey. /* Dark grey (text): #333333 Dark Blue (headings, links) #000066 Mid Blue (header) #333399 Light blue (top navigation) #CCCCFF Mid grey: #666666 */ This is a fairly low-tech method, but if used throughout the development of the CSS files can make changes far simpler and help to ensure consistency in your color scheme. I’ve seen this method used by many designers however Garrett Dimon documents the method, with more ideas in the comments. Going server-side To truly achieve constants you will need to use something other than CSS to process the file before it is sent to the browser. You can use any scripting language – PHP, ASP, ColdFusion etc. to parse a CSS file in which you have entered constants. So that in a constants section of the CSS file you would have: $darkgrey = '#333333'; $darkblue = '#000066'; The rest of the CSS file is as normal except that when you come to use the constant value you would use the constant name instead of adding the color: p { color: $darkgrey; } Your server-side script could then parse the CSS file, replace the constant names with the constant values and serve a valid CSS file to the browser. Christian Heilmann has done just this for PHP however this could be adapted for any language you might have available on your server. Shaun Inman came up with another way of doing this that removes the need to link to a PHP script and also enables the adding of constants using the syntax of at-rules . This method is again using PHP and will require you to edit an .htaccess file. A further method is to generate static CSS files either using a script locally – if the constants are just to enable speed of development – or as part of the web application itself. Storing a template stylesheet with constant names in place of the values you will want to update means that your script can simply open the template, replace the variables and save the result as a new stylesheet file. While CSS constants are a real help to developers, they can also be used to add new functionality to your applications. As with the email address example that I used at the beginning of this article, using a combination of CSS and server-side scripting you could enable a site administrator to select the colours for a new theme to be used on a page of a content managed site. By using constants you need only give them the option to change certain parts of the CSS and not upload a whole different CSS file, which could lead to some interesting results! As we are unlikely to find real CSS constants under the tree this Christmas the above methods are some possibilities for better management of your stylesheets. However if you have better methods, CSS Constant horror stories or any other suggestions, add your comments below. 2006 Rachel Andrew rachelandrew 2006-12-02T00:00:00+00:00 https://24ways.org/2006/faster-development-with-css-constants/ process
229 Sketching to Communicate As a web designer I’ve always felt that I’d somehow cheated the system, having been absent on the day God handed out the ability to draw. I didn’t study fine art, I don’t have a natural talent to effortlessly knock out a realistic bowl of fruit beside a water jug, and yet somehow I’ve still managed to blag my way this far. I’m sure many of you may feel the same. I had no intention of becoming an artist, but to have enough skill to convey an idea in a drawing would be useful. Instead, my inadequate instrument would doodle drunkenly across the page leaving a web of unintelligible paths instead of the refined illustration I’d seen in my mind’s eye. This – and the natural scrawl of my handwriting – is fine (if somewhat frustrating) when it’s for my eyes only but, when sketching to communicate a concept to a client, such amateur art would be offered with a sense of embarrassment. So when I had the opportunity to take part in some sketching classes whilst at Clearleft I jumped at the chance. Why sketch? In UX workshops early on in a project’s life, sketching is a useful and efficient way to convey and record ideas. It’s disposable and inexpensive, but needn’t look amateur. A picture may be worth a thousand words, but a well executed sketch of how you’ll combine funny YouTube videos with elephants to make Lolephants.com could be worth millions in venture capital. Actually, that’s not bad… ;-) Although (as you will see) the basics of sketching are easy to master, the kudos you will receive from clients for being a ‘proper designer’ makes it worthwhile! Where to begin? Start by not buying yourself a sketch pad. If you were the type of child who ripped the first page out of a school exercise book and started again if you made even a tiny mistake (you’re not alone!), Wreck This Journal may offer a helping hand. Practicing on plain A4 paper instead of any ‘special’ notepad will make the process a whole lot easier, no matter how deliciously edible those Moleskines look. Do buy yourself a black fine-liner pen and a set of grey Pro Markers for shading. These pens are unlike any you will have used before, and look like blended watercolours once the ink is dry. Although multiple strokes won’t create unsightly blotches of heavy ink on the page, they will go right through your top sheet so always remember to keep a rough sheet in the second position as an ink blotter. photo by Tom Harrison Don’t buy pencils to sketch with, as they lack the confidence afforded by the heavy black ink strokes of marker pens and fine-liners. If you’re going to be sketching with clients then invest in some black markers and larger sheets of paper. At the risk of sounding like a stationery brand whore, Sharpies are ideal, and these comedy-sized Post-Its do the job far better than cheaper, less sticky alternatives. Although they’re thicker than most standard paper, be sure to double-layer them if you’re writing on them on a wall, unless you fancy a weekend redecorating your client’s swanky boardroom. The best way to build confidence and improve your sketching technique is, obviously, to practise. Reading this article will be of no help unless you repeat the following examples several times each. Go grab a pen and some paper now, and notice how you improve within even a short period of time. Sketching web UI Most elements of any website can be drawn as a combination of geometric shapes. photo by Nathanael Boehm Circles To draw a circle, get in position and start by resting your hand on the page and making the circular motion a few times without putting pen to paper. As you lower your pen whilst continuing the motion, you should notice the resulting shape is more regular than it otherwise would have been. Squares and rectangles Draw one pair of parallel lines first, followed by the others to complete the shapes. Slightly overlap the ends of the lines to make corners feel more solid than if you were to leave gaps. If you’re drawing a container, always draw the contents first, that way it won’t be a squash to fit them in. If you’re drawing a grid (of thumbnails, for instance), draw all parallel lines first as a series of long dashes to help keep line lengths and angles consistent. Shadows To lift elements from the page for emphasis, add a subtle shadow with a grey marker. For the most convincing look, assume the light source to be at the top left of the page – the shadow should simply be a thick grey line along the bottom and up the right edge of your shape. If the shape is irregular, the shadow should follow its outline. This is a good way to emphasise featured items, speech bubbles, form buttons, and so on. Sketching ideas Arrows Use arrows to show steps in a process or direction of movement. Giving shadows a 3-D feel, or adding a single colour, will help separate them from the rest of the sketch. Faces Start by drawing the circle. The direction of the nose (merely a point) indicates the direction of the person’s gaze. The eyes and mouth show emotion: more open and curvy for happy thoughts; more closed and jagged for angry thoughts. Try out a few shapes and see what emotions they convey. People Remember, we’re aiming for communication rather than realism here. A stick man would be fine. Give him a solid body, as shown in this example, and it becomes easier to pose him. I know you think hands are hard, but they’re quite important to convey some ideas, and for our purposes we don’t need to draw hands with any detail. An oval with a stick does the job of a pointing hand. Close-ups might need more fingers showing, but still don’t require any degree of realism. Signage Don’t be afraid to use words. We’re sketching to communicate, so if the easiest way to show an office block is a building with a big ‘office’ sign on the roof, that’s fine! Labels Likewise, feel free to label interactions. Use upper-case letters for legibility and slightly angle the horizontal bars upwards to create a more positive feel. Clichés Clichés are your friend! Someone’s having an idea? Light bulb above the head. Computer’s crashed? Cloud of smoke with “$£%*!” It’s good to practise regularly. Try applying these principles to still life, too. Look around you now and draw the cup on the table, or the books on the shelf. Think of it as a combination of shapes and aim for symbolism rather than realism, and it’s not as hard as you’d think. I hope this has given you the confidence to give it a shot, and the ability to at least not be mortified with the results! Tip: If you’re involving clients in design games like Leisa Reichelt’s ‘Design Consequences’ it may be wise to tone down the quality of your drawings at that point so they don’t feel intimidated. Remember, it’s important for them to feel at ease with the idea of wireframing in front of you and their colleagues, no matter how bad their line work. For more information see davegrayinfo.com – Dave Gray taught me everything I know :-) 2010 Paul Annett paulannett 2010-12-19T00:00:00+00:00 https://24ways.org/2010/sketching-to-communicate/ business
101 Easing The Path from Design to Development 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. I don’t believe it has to be a battleground. It’s actually more like being a dance partner – our steps are different, but as long as we know our own part and have a little knowledge of our partner’s 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). As the process usually flows from design towards development, it’s most important that designers have a little knowledge of how the site is going to be built. At the specialist web development agency I’m 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. Based on that experience, I’ve put together my checklist of things that designers should consider before handing their work over to a developer to build. Layout One 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’s fluid, which parts expand and which not? If it’s fixed, should it sit in the middle of the window or to one side? If any part of the layout is going to be flexible (get wider and narrower as required), consider how any graphics are affected. Images don’t 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’s shown in the Photoshop comp, it may be necessary to provide separate wider versions of any background images. Text size and content volume A 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’s 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. Keep 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. Similarly, it’s rare theses days to know exactly what content you’re 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. Particular 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’ll always be someone who’ll go there. Expect them to do so. Again, 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’s rarely desirable to make significant changes without revisiting the site’s information architecture more thoroughly, it’s an inevitable fact of life that the structure needs a little bit of flexibility to change over time. Interactions with and without JavaScript A 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. Designers need to consider both states of any feature they’re designing – 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. Logged in and logged out states When designing any type of web application or site that has a membership system – that is to say users can create an account and log into the site – the design will need to consider how any element is presented in both logged in and logged out states. For some items there’ll be no difference, whereas for others there may be considerable differences. Should 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? Couple logged in and logged out states with the possible absence of JavaScript, and every feature needs to be designed in four different states: Logged out with JavaScript available Logged in with JavaScript available Logged out without JavaScript available Logged in without JavaScript available Fonts There are three main causes of war in this world; religions, politics and fonts. I’ve 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’t help but crumble to their curvy charms. Yet, 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’t 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. Messaging Any 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. For 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? With Ajax interactions, the user doesn’t get any visual feedback of the site waiting for a response from the server unless you design it that way. Consider using a ‘waiting’ or ‘in progress’ spinner to give the user some visual feedback of any background processes. How should these look? How do they animate? Similarly, also consider the big error pages like a 404. With luck, these won’t often be seen, but it’s at the point that they are when careful design matters the most. Form fields Depending on the visual style of your site, the look of a browser’s default form fields and buttons can sometimes jar. It’s 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’s not as flexible as most would like). A common request is to replace the default buttons with a graphical button. This is usually achievable in most cases, although it’s not easy to get a consistent result across all browsers – 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’s always best to try and live with the browser’s default form controls. Whichever way you go, it’s 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. Practical tips for handing files over There 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. If 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’t work in the same office as your developer (and so they can’t 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). Finally, 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’s unfamiliar ground and easy to get things wrong. Be the expert of your own domain and help your colleagues out when they’re out of their comfort zone. That goes both ways. In conclusion When 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’s my checklist for handing a design over. Is the layout fixed, or fluid? Does each element cope with expanding for larger text and more content? Are all the graphics large enough to cope with an area expanding? Does each interactive element have a state for with and without JavaScript? Does each element have a state for logged in and logged out users? How are any custom fonts being displayed? (and does the developer have the font to use?) Does each interactive element have error and success messages designed? Do all form fields have a label and each form a submit button? Is your Photoshop comp document well organised? Have you provided flat PDFs of each state? Have you provided a colour reference? Are we having fun yet? 2008 Drew McLellan drewmclellan 2008-12-01T00:00:00+00:00 https://24ways.org/2008/easing-the-path-from-design-to-development/ process
222 Golden Spirals As building blocks go, the rectangle is not one to overwhelm the designer with decisions. On the face of it, you have two options: you can set the width, and the height. But despite this apparent simplicity, there are combinations of width and height that can look unbalanced. If a rectangle is too tall and slim, it might appear precarious. If it is not tall enough, it may simply look flat. But like a guitar string that’s out of tune, you can tweak the proportions little by little until a rectangle feels, as Goldilocks said, just right. A golden rectangle has its height and width in the golden ratio, which is approximately 1:1.618. These proportions have long been recognised as being aesthetically harmonious. Whether through instruction or by intuition, artists have understood how to exploit these proportions over the centuries. Examples can be found in classical architecture, medieval book construction, and even in the recent #newtwitter redesign. A mathematical curiosity The golden rectangle is unique, in that if you remove a square section from it, what is left behind is itself a golden rectangle. The removal of a square can be repeated on the rectangle that is left behind, and then repeated again, as many times as you like. This means that the golden rectangle can be treated as a building block for recursive patterns. In this article, we will exploit this property to build a golden spiral, using only HTML and CSS. The markup The HTML we’ll use for this study is simply a series of nested <div>s. <body> <div id="container"> <div class="cycle"> <div> <div> <div> <div class="cycle"> <div> <div> <div> <div class="cycle"> <div> <div> <div> <div class="cycle"></div> </div> </div> </div> </div> </div> </div> </div> </div> </div> </div> </div> </div> </div> </body> The first of these has the class cycle, and so does every fourth ancestor thereafter. The spiral completes a cycle every four steps, so this class allows styles to be reused on <div>s that appear at the same position in each cycle. Golden proportions To create our spiral we are going to exploit the unique properties of the golden rectangle, so our first priority is to ensure that we have a golden rectangle to begin with. If we pick a length for the short edge – say, 288 pixels – we can then calculate the length of the long edge by multiplying this value by 1.618. In this case, 288 × 1.618 = 466, so our starting point will be a <div> with these properties: #container > div { width: 466px; height: 288px; } The greater than symbol is used here to single out the immediate child of the #container element, without affecting the grandchild or any of the more distant descendants. We could go on to specify the precise pixel dimensions of every child element, but that means doing a lot of sums. It would be much easier if we just specified the dimensions for each element as a percentage of the width and height of its parent. This also has the advantage that if you change the size of the outermost container, all nested elements would be resized automatically – something that we shall exploit later. The approximate value of 38.2% can be derived from (100 × 1 − phi) ÷ phi, where the Greek letter phi (ϕ) stands for the golden ratio. The value of phi can be expressed as phi = (1 + √5 ) ÷ 2, which is approximately 1.618. You don’t have to understand the derivation to use it. Just remember that if you start with a golden rectangle, you can slice 38.2% from it to create a new golden rectangle. This can be expressed in CSS quite simply: .cycle, .cycle > div > div { height: 38.2%; width: 100%; } .cycle > div, .cycle > div > div > div { width: 38.2%; height: 100%; } You can see the result so far by visiting Demo One. With no borders or shading, there is nothing to see yet, so let’s address that next. Shading with transparency We’ll need to apply some shading to distinguish each segment of the spiral from its neighbours. We could start with a white background, then progress through shades of grey: #eee, #ddd, #ccc and so on, but this means hard-coding the background-color for every element. A more elegant solution would be to use the same colour for every element, but to make each one slightly transparent. The nested <div>s that we are working with could be compared to layers in Photoshop. By applying a semi-transparent shade of grey, each successive layer can build on top of the darker layers beneath it. The effect accumulates, causing each successive layer to appear slightly darker than the last. In his 2009 article for 24 ways, Drew McLellan showed how to create a semi-transparent effect by working with RGBA colour. Here, we’ll use the colour black with an alpha value of 0.07. #container div { background-color: rgba(0,0,0,0.07) } Note that I haven’t used the immediate child selector here, which means that this rule will apply to all <div> elements inside the #container, no matter how deeply nested they are. You can view the result in Demo Two. As you can see, the golden rectangles alternate between landscape and portrait orientation. Demo Three). CSS3 specification indicates that a percentage can be used to set the border-radius property, but using percentages does not achieve consistent results in browsers today. Luckily, if you specify a border-radius in pixels using a value that is greater than the width and height of the element, then the resulting curve will use the shorter length side as its radius. This produces exactly the effect that we want, so we’ll use an arbitrarily high value of 10,000 pixels for each border-radius: .cycle { border-radius: 0px; border-bottom-left-radius: 10000px; } .cycle > div { border-radius: 0px; border-bottom-right-radius: 10000px; } .cycle > div > div { border-radius: 0px; border-top-right-radius: 10000px; } .cycle > div > div > div { border-radius: 0px; border-top-left-radius: 10000px; } Note that the specification for the border-radius property is still in flux, so it is advisable to use vendor-specific prefixes. I have omitted them from the example above for the sake of clarity, but if you view source on Demo Four then you’ll see that the actual styles are not quite as brief. Filling the available space We have created an approximation of the Golden Spiral using only HTML and CSS. Neat! It’s a shame that it occupies just a fraction of the available space. As a finishing touch, let’s make the golden spiral expand or contract to use the full space available to it. Ideally, the outermost container should use the full available width or height that could accomodate a rectangle of golden proportions. This behaviour is available for background images using the “ background-size: contain; property, but I know of no way to make block level HTML elements behave in this fashion (if I’m missing something, please enlighten me). Where CSS fails to deliver, JavaScript can usually provide a workaround. This snippet requires jQuery: $(document).ready(function() { var phi = (1 + Math.sqrt(5))/2; $(window).resize(function() { var goldenWidth = windowWidth = $(this).width(), goldenHeight = windowHeight = $(this).height(); if (windowWidth/windowHeight > phi) { // panoramic viewport – use full height goldenWidth = windowHeight * phi; } else { // portrait viewport – use full width goldenHeight = windowWidth / phi; }; $("#container > div.cycle") .width(goldenWidth) .height(goldenHeight); }).resize(); }); You can view the result by visiting Demo Five. Is it just me, or can you see an elephant in there? You can probably think of many ways to enhance this further, but for this study we’ll leave it there. It has been a good excuse to play with proportions, positioning and the immediate child selector, as well as new CSS3 features such as border-radius and RGBA colours. If you are not already designing with golden proportions, then perhaps this will inspire you to begin. 2010 Drew Neil drewneil 2010-12-07T00:00:00+00:00 https://24ways.org/2010/golden-spirals/ design
161 Keeping JavaScript Dependencies At Bay 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. Personally, 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. Starting with a global object This 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: var myAwesomeApp = {}; You can nest any necessary components into this one and also make sure that you check for dependencies like DOM support right up front. Adding the components The other thing to add to this main object is a components object, which defines all the components that are there and their file names. var myAwesomeApp = { components :{ formcheck:{ url:'formcheck.js', loaded:false }, dynamicnav:{ url:'dynamicnav.js', loaded:false }, gallery:{ url:'gallery.js', loaded:false }, lightbox:{ url:'lightbox.js', loaded:false } } }; Technically 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. var myAwesomeApp = { components :{ formcheck:{ url:'formcheck.js', loaded:false }, dynamicnav:{ url:'dynamicnav.js', loaded:false }, gallery:{ url:'gallery.js', loaded:false }, lightbox:{ url:'lightbox.js', loaded:false } }, addComponent:function(component){ var c = this.components[component]; if(c && c.loaded === false){ var s = document.createElement('script'); s.setAttribute('type', 'text/javascript'); s.setAttribute('src',c.url); document.getElementsByTagName('head')[0].appendChild(s); } } }; This allows you to add new components on the fly when they are not defined: if(!myAwesomeApp.components.gallery.loaded){ myAwesomeApp.addComponent('gallery'); }; Verifying that components have been loaded However, 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: var myAwesomeApp = { components :{ formcheck:{ url:'formcheck.js', loaded:false }, dynamicnav:{ url:'dynamicnav.js', loaded:false }, gallery:{ url:'gallery.js', loaded:false }, lightbox:{ url:'lightbox.js', loaded:false } }, addComponent:function(component){ var c = this.components[component]; if(c && c.loaded === false){ var s = document.createElement('script'); s.setAttribute('type', 'text/javascript'); s.setAttribute('src',c.url); document.getElementsByTagName('head')[0].appendChild(s); } }, componentAvailable:function(component){ this.components[component].loaded = true; } } For example the gallery.js file should call this notification as a last line: myAwesomeApp.gallery = function(){ // [... other code ...] }(); myAwesomeApp.componentAvailable('gallery'); Telling the implementers when components are available The 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: var myAwesomeApp = { components :{ formcheck:{ url:'formcheck.js', loaded:false }, dynamicnav:{ url:'dynamicnav.js', loaded:false }, gallery:{ url:'gallery.js', loaded:false }, lightbox:{ url:'lightbox.js', loaded:false } }, addComponent:function(component){ var c = this.components[component]; if(c && c.loaded === false){ var s = document.createElement('script'); s.setAttribute('type', 'text/javascript'); s.setAttribute('src',c.url); document.getElementsByTagName('head')[0].appendChild(s); } }, componentAvailable:function(component){ this.components[component].loaded = true; if(this.listener){ this.listener(component); }; } }; This allows you to write a main listener function that acts when certain components have been loaded, for example: myAwesomeApp.listener = function(component){ if(component === 'gallery'){ showGallery(); } }; Extending with other components As 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: myAwesomeApp.listener = function(component){ if(component === 'bespokecomponent'){ myAwesomeApp.addComponent('bespokelabels'); }; if(component === 'bespokelabels'){ myAwesomeApp.addComponent('bespokedata'); }; if(component === 'bespokedata'){ myAwesomeApp,bespokecomponent.init(); }; }; myAwesomeApp.components.bespokecomponent = { url:'bespoke.js', loaded:false }; myAwesomeApp.components.bespokelabels = { url:'bespokelabels.js', loaded:false }; myAwesomeApp.components.bespokedata = { url:'bespokedata.js', loaded:false }; myAwesomeApp.addComponent('bespokecomponent'); Following 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. Influences If 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. 2007 Christian Heilmann chrisheilmann 2007-12-18T00:00:00+00:00 https://24ways.org/2007/keeping-javascript-dependencies-at-bay/ code
287 Extracting the Content As we throw away our canvas in approaches and yearn for a content-out process, there remains a pain point: the Content. It is spoken of in the hushed tones usually reserved for Lord Voldemort. The-thing-that-someone-else-is-responsible-for-that-must-not-be-named. Designers and developers have been burned before by not knowing what the Content is, how long it is, what style it is and when the hell it’s actually going to be delivered, in internet eons past. Warily, they ask clients for it. But clients don’t know what to make, or what is good, because no one taught them this in business school. Designers struggle to describe what they need and when, so the conversation gets put off until it’s almost too late, and then everyone is relieved that they can take the cop-out of putting up a blog and maybe some product descriptions from the brochure. The Content in content out. I’m guessing, as a smart, sophisticated, and, may I say, nicely-scented reader of the honourable and venerable tradition of 24 ways, that you sense something better is out there. Bunches of boxes to fill in just don’t cut it any more in a responsive web design world. The first question is, how are you going to design something to ensure users have the easiest access to the best Content, if you haven’t defined at the beginning what that Content is? Of course, it’s more than possible that your clients have done lots of user research before approaching you to start this project, and have a plethora of finely tuned Content for you to design with. Have you finished laughing yet? Alright then. Let’s just assume that, for whatever reason of gross oversight, this hasn’t happened. What next? Bringing up Content for the first time with a client is like discussing contraception when you’re in a new relationship. It might be awkward and either party would probably rather be doing something else, but it needs to be broached before any action happens (that, and it’s disastrous to assume the other party has the matter in hand). If we can’t talk about it, how can we expect people to be doing it right and not making stupid mistakes? That being the case, how do we talk about Content? Let’s start by finding a way to talk about it without blushing and scuffing our shoes. And there’s a reason I’ve been treating Content as a Proper Noun. The first step, and I mean really-first-step-way-back-at-the-beginning-of-the-project-while-you-are-still-scoping-out-what-the-hell-you-might-do-for-each-other-and-it’s-still-all-a-bit-awkward-like-a-first-date, is for you to explain to the client how important it is that you, together, work out what is important to your users as part of the user experience design, so that your users get the best user experience. The trouble is that, in most cases, this would lead to blank stares, possibly followed by a light cough and a query about using Comic Sans because it seems friendly. Let’s start by ensuring your clients understand the task ahead. You see, all the time we talk about the Content we do our clients a big disservice. Content is poorly defined. It looms over a project completion point like an unscalable (in the sense of a dozen stacked Kilimanjaros), seething, massive, singular entity. The Content. Defining the problem. We should really be thinking of the Content as ‘contents’; as many parts that come together to form a mighty experience, like hit 90s kids’ TV show Mighty Morphin Power Rangers*. *For those of you who might have missed the Power Rangers, they were five teenagers with attitude, each given crazy mad individual skillz and a coloured lycra suit from an alien overlord. In return, they had to fight a new monster of the week using their abilities and weaponry in sync (even if the audio was not) and then, finally, in thrilling combination as a Humongous Mechanoid Machine of Awesome. They literally joined their individual selves, accessories and vehicles into a big robot. It was a toy manufacturer’s wet dream. So, why do I say Content is like the Power Rangers? Because Content is not just a humongous mecha. It is a combination of well-crafted pieces of contents that come together to form a well-crafted humongous mecha. Of Content. The Red Power Ranger was always the leader. You can imagine your text contents, found on about pages, product descriptions, blog articles, and so on, as being your Red Power Ranger. Maybe your pictures are your Yellow Power Ranger; video is Blue (not used as much as the others, but really impressive when given a good storyline); maybe Pink is your infographics (it’s wrong to find it sexier than the other equally important Rangers, but you kind of do anyway). And so on. These bits of content – Red Text Ranger, Yellow Picture Ranger and others – often join together on a page, like they are teaming up to fight the bad guy in an action scene, and when they all come together (your standard workaday huge mecha) in a launched site, that’s when Content becomes an entity. While you might have a vision for the whole site, Content rarely works that way. Of course, you keep your eye on the bigger prize, the completion of your mega robot, but to get there you need to assemble your working parts, the cogs and springs of contents that will mesh together to finally create your Humongous Mecha of Content. You create parts and join them to form a whole. (It’s rarely seamless; often we need to adjust as we go, but we can create our Mecha’s blueprint by making sure we have all the requisite parts.) The point here is the order these parts were created. No alien overlord plans a Humongous Mechanoid and then thinks, “Gee, how can I split this into smaller fighting units powered by teenagers in snazzy shiny suits?” No toy manufacturer goes into production of a mega robot, made up of model mecha vehicles with detachable arsenal, without thinking how they will easily fit back together to form the ‘Buy all five now to create the mega robot’ set. No good contents are created as a singular entity and chunked up to be slotted in to place any which way, into the body of a site. Think contents, not the Content. Think of contents as smaller units, or as a plural. The Content is what you have at the end. The contents are what you are creating and they are easy to break down. You are no longer scaling the unscalable. You can draw the map and plot the path, page by page, section by section. The page table is your friend To do this, I use a page table. A page table is a simple table template you can create in the word processor of your choice, that you use to tell you everything about the contents of a page – everything except the contents itself. Here’s a page table I created for an employee’s guide to redundancy in the alpha.gov.uk website: Guide to redundancy for employees Page objective: Provide specific information for employees who are facing redundancy about the process, their options and next steps. Source content: directgov page on Redundancy. Scope: In scope Page title An employee’s guide to redundancy Priority content Message: You have rights as an employee facing redundancy Method: A guide written in plain English, with links to appropriate additional content. A video guide (out of scope). Covers the stages of redundancy and rights for those in trade unions and not in trade unions. Glossary of unfamiliar terms. Call to action: Read full guide, act to explore redundancy actions, benefits or new employment. Assets: link to redundancy calculator. Secondary Related items, or popular additional links. Additional tools, such as search and suggestions. location set v not set states microcopy encouraging location set where location may make a difference to the content – ie, Scotland/Northern Ireland. Tertiary Footer and standard links. Content creation: Content exists but was created within the constraints of the previous CMS. Review, correct and edit where necessary. Maintenance: should be flagged for review upon advice from Department of Work and Pensions, and annually. Technology/Publishing/Policy implications: Should be reviewed once the glossary styles have been decided. No video guide in scope at this time, so languages should be simple and screen reader friendly. Reliance on third parties: None, all content and source exists in house. Outstanding questions: None. Download a copy of this page table This particular page table template owes a lot to Brain Traffic’s version found in Kristina Halvorson’s book Content Strategy for the Web. With smaller clients than, say, the government, I might use something a bit more casual. With clients who like timescales and deadlines, I might turn it into a covering sheet, with signatures and agreements from two departments who have to work together to get the piece done on time. I use page tables, and the process of working through them, to reassure clients that I understand the task they face and that I can help them break it down section by section, page stack to page, down to product descriptions and interaction copy. About 80% of my clients break into relieved smiles. Most clients want to work with you to produce something good, they just don’t understand how, and they want you to show them the mountain path on the map. With page tables, clients can understand that with baby steps they can break down their content requirements and commission content they need in time for the designers to work with it (as opposed to around it). If I was Santa, these clients would be on my nice list for sure. My own special brand of Voldemort-content-evilness comes in how I wield my page tables for the other 20%. Page tables are not always thrilling, I’ll admit. Sometimes they get ignored in favour of other things, yet they are crucial to the continual growth and maintenance of a truly content-led site. For these naughty list clients who, even when given the gift of the page table, continually say “Ooh, yes. Content. Right”, I have a special gift. I have a stack of recycled paper under my desk and a cheap black and white laser printer. And I print a blank page table for every conceivable page I can find on the planned redesign. If I’m feeling extra nice, I hole punch them and put them in a fat binder. There is nothing like saying, “This is all the contents you need to have in hand for launch”, and the satisfying thud the binder makes as it hits the table top, to galvanize even the naughtiest clients to start working with you to create the content you need to really create in a content-out way. 2011 Relly Annett-Baker rellyannettbaker 2011-12-15T00:00:00+00:00 https://24ways.org/2011/extracting-the-content/ content
171 Rock Solid HTML Emails At some stage in your career, it’s likely you’ll 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’s more than any other marketing channel, including the cool ones. There 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. Same same, but different Before 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’ll soon realize how different the email game is. While it’s 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’ll outline below. Finally, you need to test your designs regularly. Just because a template looks nice in Hotmail now, doesn’t mean it will next week. Setting your lowest common denominator To maintain your sanity, it’s 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. Knowing which email clients you’re 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’ll 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. Let’s get started. Use tables for layout Because clients like Gmail and Outlook 2007 have poor support for float, margin and padding, you’ll 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. Set the width in each cell, not the table When 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. <table cellspacing="0" cellpadding="10" border="0"> <tr> <td width="80"></td> <td width="280"></td> </tr> </table> Never assume that if you don’t specify a cell width the email client will figure it out. It won’t. Also avoid using percentage based widths. Clients like Outlook 2007 don’t 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. Err toward nesting Table 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. Use a container table for body background colors Many email clients ignore background colors specified in your CSS or the <body> tag. To work around this, wrap your entire email with a 100% width table and give that a background color. <table cellspacing="0" cellpadding="0" border="0" width="100%"> <tr> <td bgcolor=”#000000”> Your email code goes here. </td> </tr> </table> You can use the same approach for background images too. Just remember that some email clients don’t support them, so always provide a fallback color. Avoid unnecessary whitespace in table cells Where possible, avoid whitespace between your <td> tags. Some email clients (ahem, Yahoo! and Hotmail) can add additional padding above or below the cell contents in some scenarios, breaking your design for no apparent reason. CSS and general font formatting While some email designers do their best to avoid CSS altogether and rely on the dreaded <font> tag, the truth is many CSS properties are well supported by most email clients. See this comprehensive list of CSS support across the major clients for a good idea of the safe properties and those that should be avoided. Always move your CSS inline Gmail is the culprit for this one. By stripping the CSS from the <head> and <body> of any email, we’re 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. Avoid shorthand for fonts and hex notation A number of email clients reject CSS shorthand for the font property. For example, never set your font styles like this. p { font:bold 1em/1.2em georgia,times,serif; } Instead, declare the properties individually like this. p { font-weight: bold; font-size: 1em; line-height: 1.2em; font-family: georgia,times,serif; } While we’re 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’s web-safe fonts in email for the foreseeable future. When declaring the color property in your CSS, some email clients don’t support shorthand hexadecimal colors like color:#f60; instead of color:#ff6600;. Stick to the longhand approach for the best results. Paragraphs Just like table cell spacing, paragraph spacing can be tricky to get a consistent result across the board. I’ve seen many designers revert to using double <br /> or DIVs with inline CSS margins to work around these shortfalls, but recent testing showed that paragraph support is now reliable enough to use in most cases (there was a time when Yahoo! didn’t support the paragraph tag at all). The best approach is to set the margin inline via CSS for every paragraph in your email, like so: p { margin: 0 0 1.6em 0; } Again, do this via CSS in the head when building your email, then use Premailer to bring it inline for each paragraph later. If 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’s an example: <td width="200" style="font-weight:bold; font-size:1em; line-height:1.2em; font-family:georgia,'times',serif;">your height sensitive text</td> Links Some 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: <a href="http://somesite.com/" style="color:#ff00ff">this is a link</a> Next, add a redundant span inside the a tag. <a href="http://somesite.com/" style="color:#ff00ff"><span style="color:#ff00ff">this is a link</span></a> To 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. Images in HTML emails The most important thing to remember about images in email is that they won’t 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. With this in mind, here are the essentials to remember when using images in HTML email: Avoid spacer images While 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. Always include the dimensions of your image If 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. Avoid PNGs Lotus Notes 6 and 7 don’t 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. Provide fallback colors for background images Outlook 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. Don’t forget alt text Lack 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’t support alt text at all when images are blocked. Use the display hack for Hotmail For 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. img {display:block;} This removes the padding in Hotmail and still gives you the predicable result in other email clients. Don’t use floats Both 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. <img src="image.jpg" align="right"> If you’re seeing strange image behavior in Yahoo! Mail, adding align=“top” to your images can often solve this problem. Video in email With 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. Turns 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’t supported, you can provide reliable fallback content such as an animated GIF or a clickable image linking to the video in the browser. Of course, the question of whether you should add video to email is another issue altogether. If you lean toward the “yes” side check out the technique with code samples. What about mobile email? The mobile email landscape was a huge mess until recently. With the advent of the iPhone, Android and big improvements from Palm and RIM, it’s becoming less important to think of mobile as a different email platform altogether. That 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. Keep the width less than 600 pixels Because 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. Be aware of automatic text resizing In 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: -webkit-text-size-adjust: none; Don’t forget to test While standards support in email clients hasn’t 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’ve seen a proven design suddenly stop working without explanation. For this reason alone it’s 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. Looking ahead Designing HTML email can be a tough pill for new designers and standardistas to swallow, especially given the fickle and retrospective nature of email clients today. With HTML5 just around the corner we are entering a new, uncertain phase. Will email client developers take the opportunity to repent on past mistakes and bring email clients into the present? The aim of groups such as the Email Standards Project is to make much of the above advice as redundant as the long-forgotten <blink> and <marquee> tags, however, only time will tell if this is to become a reality. Although not the most compliant (or fashionable) medium, the results speak for themselves – email is, and will continue to be one of the most successful and targeted marketing channels available to you. As a designer with HTML email design skills in your arsenal, you have the opportunity to not only broaden your service offering, but gain a unique appreciation of how vital standards are. Next steps Ready to get started? There are a number of HTML email design galleries to provide ideas and inspiration for your own designs. http://www.campaignmonitor.com/gallery/ http://htmlemailgallery.com/ http://inboxaward.com/ Enjoy! 2009 David Greiner davidgreiner 2009-12-13T00:00:00+00:00 https://24ways.org/2009/rock-solid-html-emails/ code
331 Splintered Striper Back in March 2004, David F. Miller demonstrated a little bit of DOM scripting magic in his A List Apart article Zebra Tables. His script programmatically adds two alternating CSS background colours to table rows, making them more readable and visually pleasing, while saving the document author the tedious task of manually assigning the styling to large static data tables. Although David’s original script performs its duty well, it is nonetheless very specific and limited in its application. It only: works on a single table, identified by its id, with at least a single tbody section assigns a background colour allows two colours for odd and even rows acts on data cells, rather than rows, and then only if they have no class or background colour already defined Taking it further In a recent project I found myself needing to apply a striped effect to a medium sized unordered list. Instead of simply modifying the Zebra Tables code for this particular case, I decided to completely recode the script to make it more generic. Being more general purpose, the function in my splintered striper experiment is necessarily more complex. Where the original script only expected a single parameter (the id of the target table), the new function is called as follows: striper('[parent element tag]','[parent element class or null]','[child element tag]','[comma separated list of classes]') This new, fairly self-explanatory function: targets any type of parent element (and, if specified, only those with a certain class) assigns two or more classes (rather than just two background colours) to the child elements inside the parent preserves any existing classes already assigned to the child elements See it in action View the demonstration page for three usage examples. For simplicity’s sake, we’re making the calls to the striper function from the body’s onload attribute. In a real deployment situation, we would look at attaching a behaviour to the onload programmatically — just remember that, as we need to pass variables to the striper function, this would involve creating a wrapper function which would then be attached…something like: function stripe() { striper('tbody','splintered','tr','odd,even'); } window.onload=stripe; A final thought Just because the function is called striper does not mean that it’s limited to purely applying a striped look; as it’s more of a general purpose “alternating class assignment” script, you can achieve a whole variety of effects with it. 2005 Patrick Lauke patricklauke 2005-12-15T00:00:00+00:00 https://24ways.org/2005/splintered-striper/ code
319 Avoiding CSS Hacks for Internet Explorer Back in October, IEBlog issued a call to action, asking developers to clean up their CSS hacks for IE7 testing. Needless to say, a lot of hubbub ensued… both on IEBlog and elsewhere. My contribution to all of the noise was to suggest that developers review their code and use good CSS hacks. But what makes a good hack? Tantek Çelik, the Godfather of CSS hacks, gave us the answer by explaining how CSS hacks should be designed. In short, they should (1) be valid, (2) target only old/frozen/abandoned user-agents/browsers, and (3) be ugly. Tantek also went on to explain that using a feature of CSS is not a hack. Now, I’m not a frequent user of CSS hacks, but Tantek’s post made sense to me. In particular, I felt it gave developers direction on how we should be coding to accommodate that sometimes troublesome browser, Internet Explorer. But what I’ve found, through my work with other developers, is that there is still much confusion over the use of CSS hacks and IE. Using examples from the code I’ve seen recently, allow me to demonstrate how to clean up some IE-specific CSS hacks. The two hacks that I’ve found most often in the code I’ve seen and worked with are the star html bug and the underscore hack. We know these are both IE-specific by checking Kevin Smith’s CSS Filters chart. Let’s look at each of these hacks and see how we can replace them with the same CSS feature-based solution. The star html bug This hack violates Tantek’s second rule as it targets current (and future) UAs. I’ve seen this both as a stand alone rule, as well as an override to some other rule in a style sheet. Here are some code samples: * html div#header {margin-top:-3px;} .promo h3 {min-height:21px;} * html .promo h3 {height:21px;} The underscore hack This hack violates Tantek’s first two rules: it’s invalid (according to the W3C CSS Validator) and it targets current UAs. Here’s an example: ol {padding:0; _padding-left:5px;} Using child selectors We can use the child selector to replace both the star html bug and underscore hack. Here’s how: Write rules with selectors that would be successfully applied to all browsers. This may mean starting with no declarations in your rule! div#header {} .promo h3 {} ol {padding:0;} To these rules, add the IE-specific declarations. div#header {margin-top:-3px;} .promo h3 {height:21px;} ol {padding:0 0 0 5px;} After each rule, add a second rule. The selector of the second rule must use a child selector. In this new rule, correct any IE-specific declarations previously made. div#header {margin-top:-3px;} body > div#header {margin-top:0;} .promo h3 {height:21px;} .promo > h3 {height:auto; min-height:21px;} ol {padding:0 0 0 5px;} html > body ol {padding:0;} Voilà – no more hacks! There are a few caveats to this that I won’t go into… but assuming you’re operating in strict mode and barring any really complicated stuff you’re doing in your code, your CSS will still render perfectly across browsers. And while this may make your CSS slightly heftier in size, it should future-proof it for IE7 (or so I hope). Happy holidays! 2005 Kimberly Blessing kimberlyblessing 2005-12-17T00:00:00+00:00 https://24ways.org/2005/avoiding-css-hacks-for-internet-explorer/ code
166 Performance On A Shoe String Back in the summer, I happened to notice the official Wimbledon All England Tennis Club site had jumped to the top of Alexa’s Movers & Shakers list — 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. Many sites have similar peaks in traffic, especially when they’re based around scheduled events. No one cares about the site for most of the year, and then all of a sudden – wham! – things start getting warm in the data centre. Whilst the thought of chestnuts roasting on an open server has a certain appeal, it’s 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. Traffic graph from Alexa.com Whilst 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’ve 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’t know when the peaks will be. If you’re 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’t 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. In this article I’m going to talk about some of the things we’ve learned about keeping 24 ways running throughout December, whilst not spending a fortune on hosting we don’t need for 11 months of each year. We’ve not always got it right, but we’ve learned a lot along the way. The Problem To 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’s one available not doing anything). Each process takes a bunch of memory, so there’s 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. With 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: Reducing the amount of memory needed by each Apache process Reducing the amount of time each process is needed Reducing the number of requests made to the server Yahoo! 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. Server tweaking If you’re 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. Firstly, 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’s 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’t use mail (ours doesn’t) make sure it’s shut down and not using resources. Secondly, 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. The final thing to check is that Apache isn’t 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’t 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’t even log in to sort it out. Those are the main tidbits I’ve found useful for this site, although it’s worth repeating that entire books have been written on this subject alone. Caching Although the site is generated with PHP and MySQL, the majority of pages served don’t 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’t 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. We 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. The 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. Outsource your feeds We 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’s still 36,000 requests we could easily do without. Each request uses resources and particularly during December, all those requests can add up. The 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’s servers rather than ours. In addition, we get pretty graphs showing how the subscriber-base is building. Off-load big files Larger 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. This year, we started serving most of the images for articles from a subdomain – media.24ways.org. Rather than pointing to our own server, this subdomain points to an Amazon S3 account where the files are held. It’s 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’s so affordable it may not be worth even taking the files back off S3 once December has passed. I 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’re not tied to always using the service, and that it can be transparent to your users. If 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. Off-load small files You’ll have noticed the pattern by now – 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. Earlier this year Gravatar changed hands and is now run by the same team behind WordPress.com. Those guys clearly know what they’re doing when it comes to high performance, so this year we went back to serving avatars directly from them. If 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. Know what you’re paying for The 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. So 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’t even have to pay the setup cost on the new server. So it really pays to know what you’re paying for and keep an eye out of ways you can make improvements without needing to spend more money. Further steps There’s 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’s not minified or compressed. But by tackling the big problems first we’ve 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. Over the last 24 days we’ve served up articles to more than 350,000 visitors without breaking a sweat. On a busy day, that’s been nearly 20,000 visitors in just 24 hours. While in the grand scheme of things that’s not a huge amount of traffic, it can be a lot if you’re not prepared for it. However, with a little planning for the peaks you can help ensure that when the traffic arrives you’re ready to capitalise on it. Of course, people only visit 24 ways for the wealth of knowledge and experience that’s tied up in the articles here. Therefore I’d 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. 2007 Drew McLellan drewmclellan 2007-12-24T00:00:00+00:00 https://24ways.org/2007/performance-on-a-shoe-string/ ux
315 Edit-in-Place with Ajax Back on day one we looked at using the Prototype library to take all the hard work out of making a simple Ajax call. While that was fun and all, it didn’t go that far towards implementing something really practical. We dipped our toes in, but haven’t learned to swim yet. So here is swimming lesson number one. Anyone who’s used Flickr to publish their photos will be familiar with the edit-in-place system used for quickly amending titles and descriptions on photographs. Hovering over an item turns its background yellow to indicate it is editable. A simple click loads the text into an edit box, right there on the page. Prototype includes all sorts of useful methods to help reproduce something like this for our own projects. As well as the simple Ajax GETs we learned how to do last time, we can also do POSTs (which we’ll need here) and a whole bunch of manipulations to the user interface – all through simple library calls. Here’s what we’re building, so let’s do it. Getting Started There are two major components to this process; the user interface manipulation and the Ajax call itself. Our set-up is much the same as last time (you may wish to read the first article if you’ve not already done so). We have a basic HTML page which links in the prototype.js file and our own editinplace.js. Here’s what Santa dropped down my chimney: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/> <title>Edit-in-Place with Ajax</title> <link href="editinplace.css" rel="Stylesheet" type="text/css" /> <script src="prototype.js" type="text/javascript"></script> <script src="editinplace.js" type="text/javascript"></script> </head> <body> <h1>Edit-in-place</h1> <p id="desc">Dashing through the snow on a one horse open sleigh.</p> </body> </html> So that’s our page. The editable item is going to be the <p> called desc. The process goes something like this: Highlight the area onMouseOver Clear the highlight onMouseOut If the user clicks, hide the area and replace with a <textarea> and buttons Remove all of the above if the user cancels the operation When the Save button is clicked, make an Ajax POST and show that something’s happening When the Ajax call comes back, update the page with the new content Events and Highlighting The first step is to offer feedback to the user that the item is editable. This is done by shading the background colour when the user mouses over. Of course, the CSS :hover pseudo class is a straightforward way to do this, but for three reasons, I’m using JavaScript to switch class names. :hover isn’t supported on many elements in Internet Explorer for Windows I want to keep control over when the highlight switches off after an update, regardless of mouse position If JavaScript isn’t available we don’t want to end up with the CSS suggesting it might be With this in mind, here’s how editinplace.js starts: Event.observe(window, 'load', init, false); function init(){ makeEditable('desc'); } function makeEditable(id){ Event.observe(id, 'click', function(){edit($(id))}, false); Event.observe(id, 'mouseover', function(){showAsEditable($(id))}, false); Event.observe(id, 'mouseout', function(){showAsEditable($(id), true)}, false); } function showAsEditable(obj, clear){ if (!clear){ Element.addClassName(obj, 'editable'); }else{ Element.removeClassName(obj, 'editable'); } } The first line attaches an onLoad event to the window, so that the function init() gets called once the page has loaded. In turn, init() sets up all the items on the page that we want to make editable. In this example I’ve just got one, but you can add as many as you like. The function madeEditable() attaches the mouseover, mouseout and click events to the item we’re making editable. All showAsEditable does is add and remove the class name editable from the object. This uses the particularly cunning methods Element.addClassName() and Element.removeClassName() which enable you to cleanly add and remove effects without affecting any styling the object may otherwise have. Oh, remember to add a rule for .editable to your style sheet: .editable{ color: #000; background-color: #ffffd3; } The Switch As you can see above, when the user clicks on an editable item, a call is made to the function edit(). This is where we switch out the static item for a nice editable textarea. Here’s how that function looks. function edit(obj){ Element.hide(obj); var textarea ='<div id="' + obj.id + '_editor"> <textarea id="' + obj.id + '_edit" name="' + obj.id + '" rows="4" cols="60">' + obj.innerHTML + '</textarea>'; var button = '<input id="' + obj.id + '_save" type="button" value="SAVE" /> OR <input id="' + obj.id + '_cancel" type="button" value="CANCEL" /></div>'; new Insertion.After(obj, textarea+button); Event.observe(obj.id+'_save', 'click', function(){saveChanges(obj)}, false); Event.observe(obj.id+'_cancel', 'click', function(){cleanUp(obj)}, false); } The first thing to do is to hide the object. Prototype comes to the rescue with Element.hide() (and of course, Element.show() too). Following that, we build up the textarea and buttons as a string, and then use Insertion.After() to place our new editor underneath the (now hidden) editable object. The last thing to do before we leave the user to edit is it attach listeners to the Save and Cancel buttons to call either the saveChanges() function, or to cleanUp() after a cancel. In the event of a cancel, we can clean up behind ourselves like so: function cleanUp(obj, keepEditable){ Element.remove(obj.id+'_editor'); Element.show(obj); if (!keepEditable) showAsEditable(obj, true); } Saving the Changes This is where all the Ajax fun occurs. Whilst the previous article introduced Ajax.Updater() for simple Ajax calls, in this case we need a little bit more control over what happens once the response is received. For this purpose, Ajax.Request() is perfect. We can use the onSuccess and onFailure parameters to register functions to handle the response. function saveChanges(obj){ var new_content = escape($F(obj.id+'_edit')); obj.innerHTML = "Saving..."; cleanUp(obj, true); var success = function(t){editComplete(t, obj);} var failure = function(t){editFailed(t, obj);} var url = 'edit.php'; var pars = 'id=' + obj.id + '&content=' + new_content; var myAjax = new Ajax.Request(url, {method:'post', postBody:pars, onSuccess:success, onFailure:failure}); } function editComplete(t, obj){ obj.innerHTML = t.responseText; showAsEditable(obj, true); } function editFailed(t, obj){ obj.innerHTML = 'Sorry, the update failed.'; cleanUp(obj); } As you can see, we first grab in the contents of the textarea into the variable new_content. We then remove the editor, set the content of the original object to “Saving…” to show that an update is occurring, and make the Ajax POST. If the Ajax fails, editFailed() sets the contents of the object to “Sorry, the update failed.” Admittedly, that’s not a very helpful way to handle the error but I have to limit the scope of this article somewhere. It might be a good idea to stow away the original contents of the object (obj.preUpdate = obj.innerHTML) for later retrieval before setting the content to “Saving…”. No one likes a failure – especially a messy one. If the Ajax call is successful, the server-side script returns the edited content, which we then place back inside the object from editComplete, and tidy up. Meanwhile, back at the server The missing piece of the puzzle is the server-side script for committing the changes to your database. Obviously, any solution I provide here is not going to fit your particular application. For the purposes of getting a functional demo going, here’s what I have in PHP. <?php $id = $_POST['id']; $content = $_POST['content']; echo htmlspecialchars($content); ?> Not exactly rocket science is it? I’m just catching the content item from the POST and echoing it back. For your application to be useful, however, you’ll need to know exactly which record you should be updating. I’m passing in the ID of my <div>, which is not a fat lot of use. You can modify saveChanges() to post back whatever information your app needs to know in order to process the update. You should also check the user’s credentials to make sure they have permission to edit whatever it is they’re editing. Basically the same rules apply as with any script in your application. Limitations There are a few bits and bobs that in an ideal world I would tidy up. The first is the error handling, as I’ve already mentioned. The second is that from an idealistic standpoint, I’d rather not be using innerHTML. However, the reality is that it’s presently the most efficient way of making large changes to the document. If you’re serving as XML, remember that you’ll need to replace these with proper DOM nodes. It’s also important to note that it’s quite difficult to make something like this universally accessible. Whenever you start updating large chunks of a document based on user interaction, a lot of non-traditional devices don’t cope well. The benefit of this technique, though, is that if JavaScript is unavailable none of the functionality gets implemented at all – it fails silently. It is for this reason that this shouldn’t be used as a complete replacement for a traditional, universally accessible edit form. It’s a great time-saver for those with the ability to use it, but it’s no replacement. See it in action I’ve put together an example page using the inert PHP script above. That is to say, your edits aren’t committed to a database, so the example is reset when the page is reloaded. 2005 Drew McLellan drewmclellan 2005-12-23T00:00:00+00:00 https://24ways.org/2005/edit-in-place-with-ajax/ code
273 There’s No Formula for Great Designs Before he combined them with fluid images and CSS3 media queries to coin responsive design, Ethan Marcotte described fluid grids — one of the most enjoyable parts of responsive design. Enjoyable that is, if you like working with math(s). But fluid grids aren’t perfect and, unless we’re careful when applying them, they can sometimes result in a design that feels disconnected. Recapping fluid grids If you haven’t read Ethan’s Fluid Grids, now would be a good time to do that. It centres around a simple formula for converting pixel widths to percentages: (target ÷ context) × 100 = result How does that work in practice? Well, take that Fireworks or Photoshop comp you’re working on (I call them static design visuals, or just visuals.) Of course, everything on that visual — column divisions, inline images, navigation elements, everything — is measured in pixels. Now: Pick something in the visual and measure its width. That’s our target. Take that target measurement and divide it by the width of its parent (context). Multiply what you’ve got by 100 (shift two decimal places). What you’re left with is a percentage width to drop into your style sheets. For example, divide this 300px wide sidebar division by its 948px parent and then multiply by 100: your original 300px is neatly converted to 31.646%. .content-sub { width : 31.646%; /* 300px ÷ 948px = .31646 */ } That formula makes it surprisingly simple for even die-hard fixed width aficionados to convert their visuals to percentage-based, fluid layouts. It’s a handy formula for those who still design using static visuals, and downright essential for those situations where one person in an organization designs in Fireworks or Photoshop and another develops with CSS. Why? Well, although I think that designing in a browser makes the best sense — particularly when designing for multiple devices — I’ll wager most designers still make visuals in Fireworks or Photoshop and use them for demonstrations and get feedback and sign-off. That’s OK. If you haven’t made the transition to content-out designing in a browser yet, the fluid grids formula helps you carry on pushing pixels a while longer. You can carry on moving pixel width measurements from your visuals to your style sheets, too, in the same way you always have. You can be precise to the pixel and even apply a grid image as a CSS background to help you keep everything lined up perfectly. Once you’re done, and the fixed width layout in the browser matches your visual, loop back through your style sheets and convert those pixels to percentages using the fluid grids formula. With very little extra work, you’ll have a fluid implementation of your fixed width layout. The fluid grids formula is simple and incredibly effective, but not long after I started working responsively I realized that the formula shouldn’t (always) be a one-fix, set-and-forget calculation. I noticed that unless we compensate for problems it sometimes creates, the result can be a disconnected design. Staying connected Good design relies on connectedness, a feeling of natural balance between elements and the grid they’re placed on. Give an element greater prominence or position in a visual hierarchy and you can fundamentally alter the balance and sometimes the meaning of a design. Different from a browser’s page zooming feature — where images, text and overall layout change size by the same ratio — fluid grids flex a layout in response to a window or device width. Columns expand and contract, and within them fluid media (images and videos) can also change size. This can be one of the most impressive demonstrations of responsive design. But not every element within a fluid grid can change size along with the window or device width. For example, type size and leading won’t change along with a column’s width. When columns and elements within them change width, all too easily a visual hierarchy can be broken and along with it the relationship between element sizes and the outer window or viewport. This can happen quickly if you make just one set of fluid grid calculations and use those percentages across every screen width, from smartphones through tablets and up to large desktops. The answer? Make several sets of fluid grids calculations, each one at a significant window or device width breakpoint. Then apply those new percentages, when needed, to help keep elements in proportion and maintain balance and connectedness. Here’s how I work. Avoiding disconnection I’ve never been entirely happy with grid frameworks such as the 960 Grid System, so I start almost every project by creating a custom grid to inform my layout decisions. Here’s a plain version of a grid from a recent project that I’ll use as an illustration. This project’s grid comprises 84px columns and 24px gutters. This creates an odd number of columns at common tablet and desktop widths, and allows for 300px fixed width assets — useful when I need to fit advertising into a desktop layout’s sidebar. Showing common advertising sizes (Larger image) For this project I chose three 320 and Up breakpoints above 320px and, after placing as many columns as would fit those breakpoint widths, I derived three content widths: Breakpoint Columns Content width 768px 7 732px 992px 9 948px 1,382px 13 1,380px Here’s my grid again, this time with pixel measurements and breakpoints overlaid. Showing pixel measurements and breakpoints (Larger image) Now cast your mind back to the fluid grids calculation I made earlier. I divided a 300px element by 948px and arrived at 31.646%. For some elements it’s possible to use that percentage across all screen widths, but others will feel too small in relation to a narrower 768px and too large inside 1,380px. To help maintain connectedness, I make a set of fluid grids calculations based on each of the content widths I established earlier. Now I can shift an element’s percentage width up or down when I switch to a new breakpoint and content width. For example: 300px is 40.984% of 732px 300px is 31.646% of 948px 300px is 21.739% of 1,380px I’ll add all those fluid grid percentages to my grid image and save it for quick reference. Showing percentages at all breakpoints (Larger image) Then I can apply those different percentage widths to elements at each breakpoint using CSS3 media queries. For example, that sidebar division again: /* 732px, 7-column width */ @media only screen and (min-width: 768px) { .content-sub { width : 40.983%; /* 300px ÷ 732px = .40983 */ } } /* 948px, 9-column width */ @media only screen and (min-width: 992px) { .content-sub { width : 31.645%; /* 300px ÷ 948px = .31645 */ } } /* 1380px, 13-column width */ @media only screen and (min-width: 1382px) { .content-sub { width : 21.739%; /* 300px ÷ 1380px = .21739 */ } } The number of changes you make to a layout at different breakpoints will, of course, depend on the specifics of the design you’re working on. Yes, this is additional work, but the result will be a layout that feels better balanced and within which elements remain in harmony with each other while they respond to new screen or device widths. Putting the design in responsive web design Until now, many of the conversations around responsive web design have been about aspects of technical implementation, rather than design. I believe we’re only beginning to understand what’s involved in designing responsively. In future, we’ll likely be making design decisions not just about proportions but also about responsive typography. We’ll also need to learn how to adapt our designs to device characteristics such as touch targets and more. Sometimes we’ll make decisions to improve function, other times because they make a design ‘feel’ right. You’ll know when you’ve made a right decision. You’ll feel it. After all, there really is no formula for making great designs. 2011 Andy Clarke andyclarke 2011-12-23T00:00:00+00:00 https://24ways.org/2011/theres-no-formula-for-great-designs/ ux
309 HTTP/2 Server Push and Service Workers: The Perfect Partnership Being a web developer today is exciting! The web has come a long way since its early days and there are so many great technologies that enable us to build faster, better experiences for our users. One of these technologies is HTTP/2 which has a killer feature known as HTTP/2 Server Push. During this year’s Chrome Developer Summit, I watched a really informative talk by Sam Saccone, a Software Engineer on the Google Chrome team. He gave a talk entitled Planning for Performance, and one of the topics that he covered immediately piqued my interest; the idea that HTTP/2 Server Push and Service Workers were the perfect web performance combination. If you’ve never heard of HTTP/2 Server Push before, fear not - it’s not as scary as it sounds. HTTP/2 Server Push simply allows the server to send data to the browser without having to wait for the browser to explicitly request it first. In this article, I am going to run through the basics of HTTP/2 Server Push and show you how, when combined with Service Workers, you can deliver the ultimate in web performance to your users. What is HTTP/2 Server Push? When a user navigates to a URL, a browser will make an HTTP request for the underlying web page. The browser will then scan the contents of the HTML document for any assets that it may need to retrieve such as CSS, JavaScript or images. Once it finds any assets that it needs, it will then make multiple HTTP requests for each resource that it needs and begin downloading one by one. While this approach works well, the problem is that each HTTP request means more round trips to the server before any data arrives at the browser. These extra round trips take time and can make your web pages load slower. Before we go any further, let’s see what this might look like when your browser makes a request for a web page. If you were to view this in the developer tools of your browser, it might look a little something like this: As you can see from the image above, once the HTML file has been downloaded and parsed, the browser then makes HTTP requests for any assets that it needs. This is where HTTP/2 Server Push comes in. The idea behind HTTP/2 Server Push is that when the browser requests a web page from the server, the server already knows about all the assets that are needed for the web page and “pushes” it to browser. This happens when the first HTTP request for the web page takes place and it eliminates an extra round trip, making your site faster. Using the same example above, let’s “push” the JavaScript and CSS files instead of waiting for the browser to request them. The image below gives you an idea of what this might look like. Whoa, that looks different - let’s break it down a little. Firstly, you can see that the JavaScript and CSS files appear earlier in the waterfall chart. You might also notice that the loading times for the files are extremely quick. The browser doesn’t need to make an extra HTTP request to the server, instead it receives the critical files it needs all at once. Much better! There are a number of different approaches when it comes to implementing HTTP/2 Server Push. Adoption is growing and many commercial CDNs such as Akamai and Cloudflare already offer support for Server Push. You can even roll your own implementation depending on your environment. I’ve also previously blogged about building a basic HTTP/2 Server Push example using Node.js. In this post, I’m not going to dive into how to implement HTTP/2 Server Push as that is an entire post in itself! However, I do recommend reading this article to find out more about the inner workings. HTTP/2 Server Push is awesome, but it isn’t a magic bullet. It is fantastic for improving the load time of a web page when it first loads for a user, but it isn’t that great when they request the same web page again. The reason for this is that HTTP/2 Server Push is not cache “aware”. This means that the server isn’t aware about the state of your client. If you’ve visited a web page before, the server isn’t aware of this and will push the resource again anyway, regardless of whether or not you need it. HTTP/2 Server Push effectively tells the browser that it knows better and that the browser should receive the resources whether it needs them or not. In theory browsers can cancel HTTP/2 Server Push requests if they’re already got something in cache but unfortunately no browsers currently support it. The other issue is that the server will have already started to send some of the resource to the browser by the time the cancellation occurs. HTTP/2 Server Push & Service Workers So where do Service Workers fit in? Believe it or not, when combined together HTTP/2 Server Push and Service Workers can be the perfect web performance partnership. If you’ve not heard of Service Workers before, they are worker scripts that run in the background of your website. Simply put, they act as middleman between the client and the browser and enable you to intercept any network requests that come and go from the browser. They are packed with useful features such as caching, push notifications, and background sync. Best of all, they are written in JavaScript, making it easy for web developers to understand. Using Service Workers, you can easily cache assets on a user’s device. This means when a browser makes an HTTP request for an asset, the Service Worker is able to intercept the request and first check if the asset already exists in cache on the users device. If it does, then it can simply return and serve them directly from the device instead of ever hitting the server. Let’s stop for a second and analyse what that means. Using HTTP/2 Server Push, you are able to push critical assets to the browser before the browser requests them. Then, using Service Workers you are able to cache these resources so that the browser never needs to make a request to the server again. That means a super fast first load and an even faster second load! Let’s put this into action. The following HTML code is a basic web page that retrieves a few images and two JavaScript files. <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>HTTP2 Push Demo</title> </head> <body> <h1>HTTP2 Push</h1> <img src="./images/beer-1.png" width="200" height="200" /> <img src="./images/beer-2.png" width="200" height="200" /> <br> <br> <img src="./images/beer-3.png" width="200" height="200" /> <img src="./images/beer-4.png" width="200" height="200" /> <!-- Scripts --> <script async src="./js/promise.min.js"></script> <script async src="./js/fetch.js"></script> <script> // Register the service worker if ('serviceWorker' in navigator) { navigator.serviceWorker.register('./service-worker.js').then(function(registration) { // Registration was successful console.log('ServiceWorker registration successful with scope: ', registration.scope); }).catch(function(err) { // registration failed :( console.log('ServiceWorker registration failed: ', err); }); } </script> </body> </html> In the HTML code above, I am registering a Service Worker file named service-worker.js. In order to start caching assets, I am going to use the Service Worker toolbox . It is a lightweight helper library to help you get started creating your own Service Workers. Using this library, we can actually cache the base web page with the path /push. The Service Worker Toolbox comes with a built-in routing system which is based on the same routing as Express. With just a few lines of code, you can start building powerful caching patterns. I’ve add the following code to the service-worker.js file. (global => { 'use strict'; // Load the sw-toolbox library. importScripts('/js/sw-toolbox/sw-toolbox.js'); // The route for any requests toolbox.router.get('/push', global.toolbox.fastest); toolbox.router.get('/images/(.*)', global.toolbox.fastest); toolbox.router.get('/js/(.*)', global.toolbox.fastest); // Ensure that our service worker takes control of the page as soon as possible. global.addEventListener('install', event => event.waitUntil(global.skipWaiting())); global.addEventListener('activate', event => event.waitUntil(global.clients.claim())); })(self); Let’s break this code down further. Around line 4, I am importing the Service Worker toolbox. Next, I am specifying a route that will listen to any requests that match the URL /push. Because I am also interested in caching the images and JavaScript for that page, I’ve told the toolbox to listen to these routes too. The best thing about the code above is that if any of the assets exist in cache, we will instantly return the cached version instead of waiting for it to download. If the asset doesn’t exist in cache, the code above will add it into cache so that we can retrieve it when it’s needed again. You may also notice the code global.toolbox.fastest - this is important because gives you the compromise of fulfilling from the cache immediately, while firing off an additional HTTP request updating the cache for the next visit. But what does this mean when combined with HTTP/2 Server Push? Well, it means that on the first load of the web page, you are able to “push” everything to the user at once before the browser has even requested it. The Service Worker activates and starts caching the assets on the users device. The next time a user visits the page, the Service Worker will intercept the request and serve the asset directly from cache. Amazing! Using this technique, the waterfall chart for a repeat visit should look like the image below. If you look closely at the image above, you’ll notice that the web page returns almost instantly without ever making an HTTP request over the network. Using the Service Worker library, we cached the base page for the route /push, which allowed us to retrieve this directly from cache. Whether used on their own or combined together, the best thing about these two features is that they are the perfect progressive enhancement. If your user’s browser doesn’t support them, they will simply fall back to HTTP/1.1 without Service Workers. Your users may not experience as fast a load time as they would with these two techniques, but it would be no different from their normal experience. HTTP/2 Server Push and Service Workers are really the perfect partners when it comes to web performance. Summary When used correctly, HTTP/2 Server Push and Service Workers can have a positive impact on your site’s load times. Together they mean super fast first load times and even faster repeat views to a web page. Whilst this technique is really effective, it’s worth noting that HTTP/2 push is not a magic bullet. Think about the situations where it might make sense to use it and don’t just simply “push” everything; it could actually lead to having slower page load times. If you’d like to learn more about the rules of thumb for HTTP/2 Server Push, I recommend reading this article for more information. All of the code in this example is available on my Github repo - if you have any questions, please submit an issue and I’ll get back to you as soon as possible. If you’d like to learn more about this technique and others relating to HTTP/2, I highly recommend watching Sam Saccone’s talk at this years Chrome Developer Summit. I’d also like to say a massive thank you to Robin Osborne, Andy Davies and Jeffrey Posnick for helping me review this article before putting it live! 2016 Dean Hume deanhume 2016-12-15T00:00:00+00:00 https://24ways.org/2016/http2-server-push-and-service-workers/ code
320 DOM Scripting Your Way to Better Blockquotes Block quotes are great. I don’t mean they’re great for indenting content – that would be an abuse of the browser’s default styling. I mean they’re great for semantically marking up a chunk of text that is being quoted verbatim. They’re especially useful in blog posts. <blockquote> <p>Progressive Enhancement, as a label for a strategy for Web design, was coined by Steven Champeon in a series of articles and presentations for Webmonkey and the SxSW Interactive conference.</p> </blockquote> Notice that you can’t just put the quoted text directly between the <blockquote> tags. In order for your markup to be valid, block quotes may only contain block-level elements such as paragraphs. There is an optional cite attribute that you can place in the opening <blockquote> tag. This should contain a URL containing the original text you are quoting: <blockquote cite="http://en.wikipedia.org/wiki/Progressive_Enhancement"> <p>Progressive Enhancement, as a label for a strategy for Web design, was coined by Steven Champeon in a series of articles and presentations for Webmonkey and the SxSW Interactive conference.</p> </blockquote> Great! Except… the default behavior in most browsers is to completely ignore the cite attribute. Even though it contains important and useful information, the URL in the cite attribute is hidden. You could simply duplicate the information with a hyperlink at the end of the quoted text: <blockquote cite="http://en.wikipedia.org/wiki/Progressive_Enhancement"> <p>Progressive Enhancement, as a label for a strategy for Web design, was coined by Steven Champeon in a series of articles and presentations for Webmonkey and the SxSW Interactive conference.</p> <p class="attribution"> <a href="http://en.wikipedia.org/wiki/Progressive_Enhancement">source</a> </p> </blockquote> But somehow it feels wrong to have to write out the same URL twice every time you want to quote something. It could also get very tedious if you have a lot of quotes. Well, “tedious” is no problem to a programming language, so why not use a sprinkling of DOM Scripting? Here’s a plan for generating an attribution link for every block quote with a cite attribute: Write a function called prepareBlockquotes. Begin by making sure the browser understands the methods you will be using. Get all the blockquote elements in the document. Start looping through each one. Get the value of the cite attribute. If the value is empty, continue on to the next iteration of the loop. Create a paragraph. Create a link. Give the paragraph a class of “attribution”. Give the link an href attribute with the value from the cite attribute. Place the text “source” inside the link. Place the link inside the paragraph. Place the paragraph inside the block quote. Close the for loop. Close the function. Here’s how that translates to JavaScript: function prepareBlockquotes() { if (!document.getElementsByTagName || !document.createElement || !document.appendChild) return; var quotes = document.getElementsByTagName("blockquote"); for (var i=0; i<quotes.length; i++) { var source = quotes[i].getAttribute("cite"); if (!source) continue; var para = document.createElement("p"); var link = document.createElement("a"); para.className = "attribution"; link.setAttribute("href",source); link.appendChild(document.createTextNode("source")); para.appendChild(link); quotes[i].appendChild(para); } } Now all you need to do is trigger that function when the document has loaded: window.onload = prepareBlockquotes; Better yet, use Simon Willison’s handy addLoadEvent function to queue this function up with any others you might want to execute when the page loads. That’s it. All you need to do is save this function in a JavaScript file and reference that file from the head of your document using <script> tags. You can style the attribution link using CSS. It might look good aligned to the right with a smaller font size. If you’re looking for something to do to keep you busy this Christmas, I’m sure that this function could be greatly improved. Here are a few ideas to get you started: Should the text inside the generated link be the URL itself? If the block quote has a title attribute, how would you take its value and use it as the text inside the generated link? Should the attribution paragraph be placed outside the block quote? If so, how would you that (remember, there is an insertBefore method but no insertAfter)? Can you think of other instances of useful information that’s locked away inside attributes? Access keys? Abbreviations? 2005 Jeremy Keith jeremykeith 2005-12-05T00:00:00+00:00 https://24ways.org/2005/dom-scripting-your-way-to-better-blockquotes/ code
95 Giving Content Priority with CSS3 Grid Layout Browser support for many of the modules that are part of CSS3 have enabled us to use CSS for many of the things we used to have to use images for. The rise of mobile browsers and the concept of responsive web design has given us a whole new way of looking at design for the web. However, when it comes to layout, we haven’t moved very far at all. We have talked for years about separating our content and source order from the presentation of that content, yet most of us have had to make decisions on source order in order to get a certain visual layout. Owing to some interesting specifications making their way through the W3C process at the moment, though, there is hope of change on the horizon. In this article I’m going to look at one CSS module, the CSS3 grid layout module, that enables us to define a grid and place elements on to it. This article comprises a practical demonstration of the basics of grid layout, and also a discussion of one way in which we can start thinking of content in a more adaptive way. Before we get started, it is important to note that, at the time of writing, these examples work only in Internet Explorer 10. CSS3 grid layout is a module created by Microsoft, and implemented using the -ms prefix in IE10. My examples will all use the -ms prefix, and not include other prefixes simply because this is such an early stage specification, and by the time there are implementations in other browsers there may be inconsistencies. The implementation I describe today may well change, but is also there for your feedback. If you don’t have access to IE10, then one way to view and test these examples is by signing up for an account with Browserstack – the free trial would give you time to have a look. I have also included screenshots of all relevant stages in creating the examples. What is CSS3 grid layout? CSS3 grid layout aims to let developers divide up a design into a grid and place content on to that grid. Rather than trying to fabricate a grid from floats, you can declare an actual grid on a container element and then use that to position the elements inside. Most importantly, the source order of those elements does not matter. Declaring a grid We declare a grid using a new value for the display property: display: grid. As we are using the IE10 implementation here, we need to prefix that value: display: -ms-grid;. Once we have declared our grid, we set up the columns and rows using the grid-columns and grid-rows properties. .wrapper { display: -ms-grid; -ms-grid-columns: 200px 20px auto 20px 200px; -ms-grid-rows: auto 1fr; } In the above example, I have declared a grid on the .wrapper element. I have used the grid-columns property to create a grid with a 200 pixel-wide column, a 20 pixel gutter, a flexible width auto column that will stretch to fill the available space, another 20 pixel-wide gutter and a final 200 pixel sidebar: a flexible width layout with two fixed width sidebars. Using the grid-rows property I have created two rows: the first is set to auto so it will stretch to fill whatever I put into it; the second row is set to 1fr, a new value used in grids that means one fraction unit. In this case, one fraction unit of the available space, effectively whatever space is left. Positioning items on the grid Now I have a simple grid, I can pop items on to it. If I have a <div> with a class of .main that I want to place into the second row, and the flexible column set to auto I would use the following CSS: .content { -ms-grid-column: 3; -ms-grid-row: 2; -ms-grid-row-span: 1; } If you are old-school, you may already have realised that we are essentially creating an HTML table-like layout structure using CSS. I found the concept of a table the most helpful way to think about the grid layout module when trying to work out how to place elements. Creating grid systems As soon as I started to play with CSS3 grid layout, I wanted to see if I could use it to replicate a flexible grid system like this fluid 16-column 960 grid system. I started out by defining a grid on my wrapper element, using fractions to make this grid fluid. .wrapper { width: 90%; margin: 0 auto 0 auto; display: -ms-grid; -ms-grid-columns: 1fr (4.25fr 1fr)[16]; -ms-grid-rows: (auto 20px)[24]; } Like the 960 grid system I was using as an example, my grid starts with a gutter, followed by the first actual column, plus another gutter repeated sixteen times. What this means is that if I want to span two columns, as far as the grid layout module is concerned that is actually three columns: two wide columns, plus one gutter. So this needs to be accounted for when positioning items. I created a CSS class for each positioning option: column position; rows position; and column span. For example: .grid1 {-ms-grid-column: 2;} /* applying this class positions an item in the first column (the gutter is column 1) */ .grid2 {-ms-grid-column: 4;} /* 2nd column - gutter|column 1|gutter */ .grid3 {-ms-grid-column: 6;} /* 3rd column - gutter|column 1|gutter|column2|gutter */ .row1 {-ms-grid-row:1;} .row2 {-ms-grid-row:3;} .row3 {-ms-grid-row:5;} .colspan1 {-ms-grid-column-span:1;} .colspan2 {-ms-grid-column-span:3;} .colspan3 {-ms-grid-column-span:5;} I could then add multiple classes to each element to set the position on on the grid. This then gives me a replica of the fluid grid using CSS3 grid layout. To see this working fire up IE10 and view Example 1. This works, but… This worked, but isn’t ideal. I considered not showing this stage of my experiment – however, I think it clearly shows how the grid layout module works and is a useful starting point. That said, it’s not an approach I would take in production. First, we have to add classes to our markup that tie an element to a position on the grid. This might not be too much of a problem if we are always going to maintain the sixteen-column grid, though, as I will show you that the real power of the grid layout module appears once you start to redefine the grid, using different grids based on media queries. If you drop to a six-column layout for small screens, positioning items into column 16 makes no sense any more. Calculating grid position using LESS As we’ve seen, if you want to use a grid with main columns and gutters, you have to take into account the spacing between columns as well as the actual columns. This means we have to do some calculating every time we place an item on the grid. In my example above I got around this by creating a CSS class for each position, allowing me to think in sixteen rather than thirty-two columns. But by using a CSS preprocessor, I can avoid using all the classes yet still think in main columns. I’m using LESS for my example. My simple grid framework consists of one simple mixin. .position(@column,@row,@colspan,@rowspan) { -ms-grid-column: @column*2; -ms-grid-row: @row*2-1; -ms-grid-column-span: @colspan*2-1; -ms-grid-row-span: @rowspan*2-1; } My mixin takes four parameters: column; row; colspan; and rowspan. So if I wanted to place an item on column four, row three, spanning two columns and one row, I would write the following CSS: .box { .position(4,3,2,1); } The mixin would return: .box { -ms-grid-column: 8; -ms-grid-row: 5; -ms-grid-column-span: 3; -ms-grid-row-span: 1; } This saves me some typing and some maths. I could also add other prefixed values into my mixin as other browsers started to add support. We can see this in action creating a new grid. Instead of adding multiple classes to each element, I can add one class; that class uses the mixin to create the position. I have also played around with row spans using my mixin and you can see we end up with a quite complicated arrangement of boxes. Have a look at example two in IE10. I’ve used the JavaScript LESS parser so that you can view the actual LESS that I use. Note that I have needed to escape the -ms prefixed properties with ~"" to get LESS to accept them. This is looking better. I don’t have direct positioning information on each element in the markup, just a class name – I’ve used grid(x), but it could be something far more semantic. We can now take the example a step further and redefine the grid based on screen width. Media queries and the grid This example uses exactly the same markup as the previous example. However, we are now using media queries to detect screen width and redefine the grid using a different number of columns depending on that width. I start out with a six-column grid, defining that on .wrapper, then setting where the different items sit on this grid: .wrapper { width: 90%; margin: 0 auto 0 auto; display: ~"-ms-grid"; /* escaped for the LESS parser */ -ms-grid-columns: ~"1fr (4.25fr 1fr)[6]"; /* escaped for the LESS parser */ -ms-grid-rows: ~"(auto 20px)[40]"; /* escaped for the LESS parser */ } .grid1 { .position(1,1,1,1); } .grid2 { .position(2,1,1,1); } /* ... see example for all declarations ... */ Using media queries, I redefine the grid to nine columns when we hit a minimum width of 700 pixels. @media only screen and (min-width: 700px) { .wrapper { -ms-grid-columns: ~"1fr (4.25fr 1fr)[9]"; -ms-grid-rows: ~"(auto 20px)[50]"; } .grid1 { .position(1,1,1,1); } .grid2 { .position(2,1,1,1); } /* ... */ } Finally, we redefine the grid for 960 pixels, back to the sixteen-column grid we started out with. @media only screen and (min-width: 940px) { .wrapper { -ms-grid-columns:~" 1fr (4.25fr 1fr)[16]"; -ms-grid-rows:~" (auto 20px)[24]"; } .grid1 { .position(1,1,1,1); } .grid2 { .position(2,1,1,1); } /* ... */ } If you view example three in Internet Explorer 10 you can see how the items reflow to fit the window size. You can also see, looking at the final set of blocks, that source order doesn’t matter. You can pick up a block from anywhere and place it in any position on the grid. Laying out a simple website So far, like a toddler on Christmas Day, we’ve been playing with boxes rather than thinking about what might be in them. So let’s take a quick look at a more realistic layout, in order to see why the CSS3 grid layout module can be really useful. At this time of year, I am very excited to get out of storage my collection of odd nativity sets, prompting my family to suggest I might want to open a museum. Should I ever do so, I’ll need a website, and here is an example layout. As I am using CSS3 grid layout, I can order my source in a logical manner. In this example my document is as follows, though these elements could be in any order I please: <div class="wrapper"> <div class="welcome"> ... </div> <article class="main"> ... </article> <div class="info"> ... </div> <div class="ads"> ... </div> </div> For wide viewports I can use grid layout to create a sidebar, with the important information about opening times on the top righ,t with the ads displayed below it. This creates the layout shown in the screenshot above. @media only screen and (min-width: 940px) { .wrapper { -ms-grid-columns:~" 1fr (4.25fr 1fr)[16]"; -ms-grid-rows:~" (auto 20px)[24]"; } .welcome { .position(1,1,12,1); padding: 0 5% 0 0; } .info { .position(13,1,4,1); border: 0; padding:0; } .main { .position(1,2,12,1); padding: 0 5% 0 0; } .ads { .position(13,2,4,1); display: block; margin-left: 0; } } In a floated layout, a sidebar like this often ends up being placed under the main content at smaller screen widths. For my situation this is less than ideal. I want the important information about opening times to end up above the main article, and to push the ads below it. With grid layout I can easily achieve this at the smallest width .info ends up in row two and .ads in row five with the article between. .wrapper { display: ~"-ms-grid"; -ms-grid-columns: ~"1fr (4.25fr 1fr)[4]"; -ms-grid-rows: ~"(auto 20px)[40]"; } .welcome { .position(1,1,4,1); } .info { .position(1,2,4,1); border: 4px solid #fff; padding: 10px; } .content { .position(1,3,4,5); } .main { .position(1,3,4,1); } .ads { .position(1,4,4,1); } Finally, as an extra tweak I add in a breakpoint at 600 pixels and nest a second grid on the ads area, arranging those three images into a row when they sit below the article at a screen width wider than the very narrow mobile width but still too narrow to support a sidebar. @media only screen and (min-width: 600px) { .ads { display: ~"-ms-grid"; -ms-grid-columns: ~"20px 1fr 20px 1fr 20px 1fr"; -ms-grid-rows: ~"1fr"; margin-left: -20px; } .ad:nth-child(1) { .position(1,1,1,1); } .ad:nth-child(2) { .position(2,1,1,1); } .ad:nth-child(3) { .position(3,1,1,1); } } View example four in Internet Explorer 10. This is a very simple example to show how we can use CSS grid layout without needing to add a lot of classes to our document. It also demonstrates how we can mainpulate the content depending on the context in which the user is viewing it. Layout, source order and the idea of content priority CSS3 grid layout isn’t the only module that starts to move us away from the issue of visual layout being linked to source order. However, with good support in Internet Explorer 10, it is a nice way to start looking at how this might work. If you look at the grid layout module as something to be used in conjunction with the flexible box layout module and the very interesting CSS regions and exclusions specifications, we have, tantalizingly on the horizon, a powerful set of tools for layout. I am particularly keen on the potential separation of source order from layout as it dovetails rather neatly into something I spend a lot of time thinking about. As a CMS developer, working on larger scale projects as well as our CMS product Perch, I am interested in how we better enable content editors to create content for the web. In particular, I search for better ways to help them create adaptive content; content that will work in a variety of contexts rather than being tied to one representation of that content. If the concept of adaptive content is new to you, then Karen McGrane’s presentation Adapting Ourselves to Adaptive Content is the place to start. Karen talks about needing to think of content as chunks, that might be used in many different places, displayed differently depending on context. I absolutely agree with Karen’s approach to content. We have always attempted to move content editors away from thinking about creating a page and previewing it on the desktop. However at some point content does need to be published as a page, or a collection of content if you prefer, and bits of that content have priority. Particularly in a small screen context, content gets linearized, we can only show so much at a time, and we need to make sure important content rises to the top. In the case of my example, I wanted to ensure that the address information was clearly visible without scrolling around too much. Dropping it with the entire sidebar to the bottom of the page would not have been so helpful, though neither would moving the whole sidebar to the top of the screen so a visitor had to scroll past advertising to get to the article. If our layout is linked to our source order, then enabling the content editor to make decisions about priority is really hard. Only a system that can do some regeneration of the source order on the server-side – perhaps by way of multiple templates – can allow those kinds of decisions to be made. For larger systems this might be a possibility; for smaller ones, or when using an off-the-shelf CMS, it is less likely to be. Fortunately, any system that allows some form of custom field type can be used to pop a class on to an element, and with CSS grid layout that is all that is needed to be able to target that element and drop it into the right place when the content is viewed, be that on a desktop or a mobile device. This approach can move us away from forcing editors to think visually. At the moment, I might have to explain to an editor that if a certain piece of content needs to come first when viewed on a mobile device, it needs to be placed in the sidebar area, tying it to a particular layout and design. I have to do this because we have to enforce fairly strict rules around source order to make the mechanics of the responsive design work. If I can instead advise an editor to flag important content as high priority in the CMS, then I can make decisions elsewhere as to how that is displayed, and we can maintain the visual hierarchy across all the different ways content might be rendered. Why frustrate ourselves with specifications we can’t yet use in production? The CSS3 grid layout specification is listed under the Exploring section of the list of current work of the CSS Working Group. While discussing a module at this stage might seem a bit pointless if we can’t use it in production work, there is a very real reason for doing so. If those of us who will ultimately be developing sites with these tools find out about them early enough, then we can start to give our feedback to the people responsible for the specification. There is information on the same page about how to get involved with the disussions. So, if you have a bit of time this holiday season, why not have a play with the CSS3 grid layout module? I have outlined here some of my thoughts on how grid layout and other modules that separate layout from source order can be used in the work that I do. Likewise, wherever in the stack you work, playing with and thinking about new specifications means you can think about how you would use them to enhance your work. Spot a problem? Think that a change to the specification would improve things for a specific use case? Then you have something you could post to www-style to add to the discussion around this module. All the examples are on CodePen so feel free to play around and fork them. 2012 Rachel Andrew rachelandrew 2012-12-18T00:00:00+00:00 https://24ways.org/2012/css3-grid-layout/ code
167 Back To The Future of Print 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 (“yarrr… I remember back in the browser wars…”) 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. I am going to briefly cover 8 tips and 4 main gotchas when creating print stylesheets in our more enlightened era. Getting started As with regular stylesheets, print CSS can be included in a number of ways2, for our purposes we are going to be using the link element. <link rel="stylesheet" type="text/css" media="print" href="print.css"> This 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 ‘all’ which means that the styles within then apply to print and screen alike. The media type ‘screen’ only applies to the screen and wont be picked up by print, this is the best way of hiding styles from print. Make 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! Another thing you should be thinking is ‘does it need to be printed’. 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. Context 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. Tips and tricks During these tip’s we are going to build up print styles for a textileRef:11112857385470b854b8411:linkStartMarker:“simple example”:/examples/back-to-the-future-of-print/demo-1.html 1. Remove the cruft First 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;. 2. Linearise your content Content doesn’t 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. 3. Improve your type Once you have removed all the useless cruft and jiggled things about a bit, you can concentrate more on the typography of the page. Typography 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). 4. Go wild on links There 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. When 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’s article on generating footnotes for print6. Using some clever selector trickery and CSS generated content you can have the location of the link generated after the link itself. HTML: <p>I wish <a href="http://www.google.com/">Google</a> could find <a href="/photoOfMyKeys.jpg">my keys</a></p> CSS: a:link:after, a:visited:after, a:hover:after, a:active:after { content: " <" attr(href) "> "; } But this is not perfect, in the above example the content of the href is just naively plonked after the link text: I wish Google <http://www.google.com/> would find my keys </photoOfMyKeys.jpg> As 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. CSS: a:link:after, a:visited:after, a:hover:after, a:active:after { content: " <" attr(href) "> "; color: grey; font-style: italic; font-weight: normal; } a[href^="/"]:after { content: " <http://www.example.com"attr(href)"> "; } The output is now what we were looking for (you will need to replace example.com with your own root URL): I wish Google <http://www.google.com/> would find my keys <http://www.example.com/photoOfMyKeys.jpg> Using 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: HTML: <a href="mailto:me@example.com">me@example.com</a> CSS: a[href^="mailto"]:after { content: ""; } This example shows the above in action. Of course with this clever technique, there are the usual browser support issues. While it won’t 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. 5. Jazz your headers for print This is more of a design consideration, don’t 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’s and styling other headings with graduating colors or font sizes. And here is the example complete with jazzy headers. 6. Build in general hooks If 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 7. For that extra touch of class When 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. Using 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’s window.location.href variable. function addPrintFooter() { var p = document.createElement('p'); p.className = 'print-footer'; p.innerHTML = window.location.href; document.body.appendChild(p); } You 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 8. Tabular data across pages If 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 <thead> 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. Also 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. Gotchas 1. Where did all my content go? Absolutely 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’s content will be printed, the rest will look truncated after this. Floating long columns may still have this affect, as mentioned in Eric Meyer’s article on ‘A List Apart’ 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. A 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. Using position:absolute on long columns also has a very similar effect in truncating the content, but can be overridden in print with position:static; Whilst 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. 2. Damn those background browser settings One of the factors of life you now need to accept is that you can’t control the user’s 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. Naturally 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. Where 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. Check 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. One 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’t translate to print, you will need to disable this background bullet and re-instate your trusty friend the list-style-type. 3. Using JavaScript in your CSS? … beware IE6 Internet 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. 4. De-enhance your Progressive enhancements Quite a classic “doh” moment is when you realise that, of course paper doesn’t 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. If 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. And Finally… I 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. Be careful you don’t get caught out by the common gotchas, keep the design simple, test cross browser and relish in the medium of print. Further Reading 1 For more information constantly updated, please see the CSS discuss wiki on print stylesheets 2 For more information on media types and ways of including CSS please refer to the CSS discuss wiki on Media Stylesheets 3 Eric Meyer talks to ThinkVitamin about the importance of context when designing your print strategy. 4 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 5 Richard Rutter Has a fantastic resource on typography which also applies to print. 6 Aaron Gustafson has a great solution to link problem by creating footnotes at the end of the page. 7 The CSS discuss wiki has more detailed information on printing tables and detailed browser support 8 This ‘A List Apart’ article is dated May 10th 2002 though is still mostly relevant 9 Float clearing technique using ‘overflow:hidden’ 10 Autistic Cuckoo describes the interesting insight with regards to expressions specified for screen in IE6 remaining in print 11 Wikipedia has a good article on the definition of progressive enhancement 12 For a really neat trick involving a dynamically generated column to displaying <abbr> and <dfn> meanings (as well as somewhere for the user to write notes), try print previewing on Brian Suda’s site 2007 Natalie Downe nataliedowne 2007-12-09T00:00:00+00:00 https://24ways.org/2007/back-to-the-future-of-print/ design
118 Ghosts On The Internet By rights the internet should be full of poltergeists, poor rootless things looking for their real homes. Many events on the internet are not properly associated with their correct timeframe. I don’t mean a server set to the wrong time, though that happens too. Much of the content published on the internet is separated from any proper reference to its publication time. What does publication even mean? Let me tell you a story… “It is 2019 and this is Kathy Clees reporting on the story of the moment, the shock purchase of Microsoft by Apple Inc. A Internet Explorer security scare story from 2008 was responsible, yes from 11 years ago, accidently promoted by an analyst, who neglected to check the date of their sources.” If you think this is fanciful nonsense, then cast your mind back to September 2008, this story in Wired or The Times (UK) about a huge United Airlines stock tumble. A Florida newspaper had a automated popular story section. A random reader looking at a story about United’s 2002 Bankruptcy proceedings caused this story to get picked up by Google’s later visit to the South Florida Sun Sentinel’s news home page. The story was undated, Google’s news engine apparently gave it a 2008 date, an analyst picked it up and pushed it to Bloomberg and within minutes the United stock was tumbling. Their stock price dropped from $12 to $3, then recovered to $11 over the day. An eight percent fall in share price over a mis-configured date Completing this out of order Christmas Carol, lets look at what is current practice and how dates are managed, we might even get to clank some chains. Publication date used to be inseparable from publication, the two things where stamped on the same piece of paper. How can we determine when things have been published, now? Determining publication dates Time as defined by http://www.w3.org/TR/NOTE-datetime extends ISO 8601, mandating the use of a year value. This is pretty well defined, we can even get very accurate timings down to milliseconds, Ruby and other languages can even handle Calendar reformation. So accuracy is not the issue. One problem is that there are many dates which could be interpreted as the publication date. Publication can mean any of date written or created; date placed on server; last modified date; or the current date from the web server. Created and modified have parallels with file systems, but the large number of database driven websites means that this no longer holds much meaning, as there are no longer any files. Checking web server HEAD may also not correspond, it might give the creation time for the HTML file you are viewing or it might give the last modified time for a file from disk. It is too unreliable and lacking in context to be of real value. So if the web server will not help, then how can we get the right timeframe for our content? We are left with URLs and the actual page content. Looking at Flickr, this picture (by Douglas County History Research Center) has four date values which can be associated with it. It was taken around 1900, scanned in 1992 and placed on Flickr on July 29th, 2008 and replaced later that day. Which dates should be represented here? This is hard question to answer, but currently the date of upload to Flickr is the best represented in terms of the date URL, /photos/douglascountyhistory/archives/date-posted/2008/07/29/, plus some Dublin Core RDF for the year. Flickr uses 2008 as the value for this image. Not accurate, but a reasonable compromise for the millions of other images on their site. Flickr represents location much better than it represents time. For the most part this is fine, but once you go back in time to the 1800s then the maps of the world start to change a lot and you need to reference both time and place. The Google timeline search offers another interesting window on the world, showing results organised by decade for any search term. Being able to jump to a specific occurrence of a term makes it easier to get primary results rather than later reporting. The 1918 “Spanish flu” results jump out in this timeline. Any major news event will have multiple analysis articles after the event, finding the original reporting of hurricane Katrina is harder now. Many publishers are putting older content online, e.g. Harpers or Nature or The Times, often these use good date based URLs, sometimes they are unhelpful database references. If this content is available for free, then how much better would it be to provide good metadata on date of publication. Date based URLs A quick word on date based URLs, they can be brilliant at capturing first published date. However they can be hard to interpret. Is /03/04 a date in March or April, what about 08/03/04? Obviously 2008/03/04 is easier to understand, it is probably March 4th. Including a proper timestamp in the page content avoid this kind of guesswork. Many sites represent the date as a plain text string; a few hook an HTML class of date around it, a very few provide an actual timestamp. Associating the date with the individual content makes it harder to get the date wrong. Movable Type and TypePad are a notable exceptions, they will embed Dublin Core RDF to represent each posting e.g. dc:date="2008-12-18T02:57:28-08:00". WordPress doesn’t support date markup out of the box, though there is a patch and a howto for hAtom available. In terms of newspapers, the BBC use <meta name="OriginalPublicationDate" content="2008/12/18 18:52:05" /> along with opaque URLs such as http://news.bbc.co.uk/1/hi/technology/7787335.stm. The Guardian use nice clear URLs http://www.guardian.co.uk/business/2008/dec/18/car-industry-recession but have no marked up date on the page. The New York Times are similar to the Guardian with nice URLs, http://www.nytimes.com/2008/12/19/business/19markets.html, but again no timestamps. All of these papers have all the data available, but it is not marked up in a useful manner. Syndication formats Syndication formats are better at supporting dates, RSS uses RFC 822 for dates, just like email so dates such as Wed, 17 Dec 2008 12:52:40 GMT are valid, with all the white space issues that entails. The Atom syndication format uses the much clearer http://tools.ietf.org/html/rfc3339 with timestamps of the form 1996-12-19T16:39:57-08:00. Both syndication formats encourage the use of last modified. This is understandable, but a pity as published date is a very useful value. The Atom syndication format supports “published” and mandates “updated” as timestamps, see the Atom RFC 4287 for more detail. Marking up dates However the aim of this short article is to encourage you to use microformats or RDF to encode dates. A good example of this is Twitter, they use hAtom for each individual entry, http://twitter.com/zzgavin/status/1065835819 contains the following markup, which represents a human and a machine readable version of the time of that tweet. <span class="published" title="2008-12-18T22:01:27+00:00">about 3 hours ago</span> The spec for datetime is still draft at the minute and there is still ongoing conversation around the right format and semantics for representing date and time in microformats, see the datetime design pattern for details. The hAtom example page shows the minimal changes required to implement hAtom on well formed blog post content and for other less well behaved content. You have the information already in your content publication systems, this is not some additional onerous content entry task, simply some template formatting. I started to see this as a serious issue after reading Stewart Brand’s Clock of the Long Now about five years ago. Brand’s book explores the issues of short term thinking that permeate our society, thinking beyond the end of the financial year is a stretch for many people. The Long Now has a world view of a 10,000 year timeframe, see http://longnow.org/ for much more information. Freebase from Long Now Board member Danny Hillis, supports dates quite well – see the entry for A Christmas Carol. In conclusion I feel we should be making it easier for people searching for our content in the future. We’ve moved through tagging content and on to geo-tagging content. Now it is time to get the timestamps right on our content. How do I know when something happened and how can I find other things that happened at the same time is a fair question. This should be something I can satisfy simply and easily. There are a range of tools available to us in either hAtom or RDF to specify time accurately alongside the content, so what is stopping you? Thinking of the long term it is hard for us to know now what will be of relevance for future generations, so we should aim to raise the floor for publishing tools so that all content has the right timeframe associated with it. We are moving from publishing words and pictures on the internet to being able to associate publication with an individual via XFN and OpenID. We can associate place quite well too, the last piece of useful metadata is timeframe. 2008 Gavin Bell gavinbell 2008-12-20T00:00:00+00:00 https://24ways.org/2008/ghosts-on-the-internet/ ux
253 Clip Paths Know No Bounds CSS Shapes are getting a lot of attention as browser support has increased for properties like shape-outside and clip-path. There are a few ways that we can use CSS Shapes, in particular with the clip-path property, that are not necessarily evident at first glance. The basics of a clip path Before we dig into specific techniques to expand on clip paths, we should first take a look at a basic shape and clip-path. Clip paths can apply a CSS Shape such as a circle(), ellipse(), inset(), or the flexible polygon() to any element. Everywhere in the element that is not within the bounds of our shape will be visually removed. Using the polygon shape function, for example, we can create triangles, stars, or other straight-edged shapes as on Bennett Feely’s Clippy. While fixed units like pixels can be used when defining vertices/points (where the sides meet), percentages will give more flexibility to adapt to the element’s dimensions. See the Pen Clip Path Box by Dan Wilson (@danwilson) on CodePen. So for an octagon, we can set eight x, y pairs of percentages to define those points. In this case we start 30% into the width of the box for the first x and at the top of the box for the y and go clockwise. The visible area becomes the interior of the shape made by connecting these points with straight lines. clip-path: polygon( 30% 0%, 70% 0%, 100% 30%, 100% 70%, 70% 100%, 30% 100%, 0% 70%, 0% 30% ); A shape with less vertices than the eye can see It’s reasonable to look at the polygon() function and assume that we need to have one pair of x, y coordinates for every point in our shape. However, we gain some flexibility by thinking outside the box — or more specifically when we think outside the range of 0% - 100%. Our element’s box model will be the ultimate boundary for a clip-path, but we can still define points that exist beyond that natural box for an element. See the Pen CSS Shapes Know No Bounds by Dan Wilson (@danwilson) on CodePen. By going beyond the 0% - 100% range we can turn a polygon with three points into a quadrilateral, a pentagon, or a hexagon. In this example the shapes used are all similar triangles defining three points, but due to exceeding the bounds for our element box we visually see one triangle and two pentagons. Our earlier octagon can similarly be made with only four points. See the Pen Octagon with four points by Dan Wilson (@danwilson) on CodePen. Multiple shapes, one clip path We can lean on this power of going beyond the bounds of our element to also create more than one visual shape with a single polygon(). See the Pen Multiple shapes from one clip-path by Dan Wilson (@danwilson) on CodePen. Depending on how we lay it out we can make each shape directly, but since we know we can move around in the space beyond the element’s box, we can draw extra lines to help us get where we need to go next as needed. It can also help us in slicing an element. Combined with CSS Variables, we can work with overlapping elements and clip each one into alternating strips. This example is two elements, each divided into a few rectangles. See the Pen 24w: Sliced Icon by Dan Wilson (@danwilson) on CodePen. Different shapes with fill rules A polygon() is not just a collection of points. There is one more key piece to its puzzle according to the specification — the Fill Rule. The default value we have been using so far is nonzero, and the second option is evenodd. These two values help determine what is considered inside and outside the shape. See the Pen A Star Multiways by Dan Wilson (@danwilson) on CodePen. As lines intersect we can get into situations where pieces seemingly on the inside can be considered outside the shape boundary. When using the evenodd fill rule, we can determine if a given point is inside or outside the boundary by drawing a ray from the point in any direction. If the ray crosses an even number of the clip path’s lines, the point is considered outside, and if it crosses an odd number the point is inside. Order of operations It is important to note that there are many CSS properties that affect the final composited appearance of an element via CSS Filters, Blend Modes, and more. These compositing effects are applied in the order: CSS Filters (e.g. filter: blur(2px)) Clipping (e.g. what this article is about) Masking (Clipping’s cousin) Blend Modes (e.g. mix-blend-mode: multiply) Opacity This means if we want to have a star shape and blur it, the blur will happen before the clip. And since blurs are most noticeable around the edge of an element box, the effect might be completely lost since we have clipped away the element’s box edges. See the Pen Order of Filter + Clip by Dan Wilson (@danwilson) on CodePen. If we want the edges of the star to be blurred, we do have the option to wrap our clipped element in a blurred parent element. The inner element will be rendered first (with its star clip) and then the parent will blur its contents normally. Revealing content with animation CSS Shapes can be transitioned and animated, allowing us to animate the visual area of our element without affecting the content within. For example, we can start with visually hidden content (fully clipped) and grow the clip path to reveal the content within. The important caveat for polygon() is that the number of points need to be the same for each keyframe, as well as the fill rule. Otherwise the browser will not have enough information to interpolate the intermediate values. See the Pen Clip Path Shape Reveal by Dan Wilson (@danwilson) on CodePen. Don’t keep CSS Shapes in a box Clip paths give us some interesting new possibilities, especially when we think of them as more than just basic shapes. We may be heavily modifying the visual representation of our elements with clip-path, but the underlying content remains unchanged and accessible which makes this property fairly powerful. 2018 Dan Wilson danwilson 2018-12-20T00:00:00+00:00 https://24ways.org/2018/clip-paths-know-no-bounds/ code
76 Giving CSS Animations and Transitions Their Place CSS animations and transitions may not sit squarely in the realm of the behaviour layer, but they’re stepping up into this area that used to be pure JavaScript territory. Heck, CSS might even perform better than its JavaScript equivalents in some cases. That’s pretty serious! With CSS’s new tricks blurring the lines between presentation and behaviour, it can start to feel bloated and messy in our CSS files. It’s an uncomfortable feeling. Here are a pair of methods I’ve found to be pretty helpful in keeping the potential bloat and wire-crossing under control when CSS has its hands in both presentation and behaviour. Same eggs, more baskets Structuring your CSS to have separate files for layout, typography, grids, and so on is a fairly common approach these days. But which one do you put your transitions and animations in? The initial answer, as always, is “it depends”. Small effects here and there will likely sit just fine with your other styles. When you move into more involved effects that require multiple animations and some logic support from JavaScript, it’s probably time to choose none of the above, and create a separate CSS file just for them. Putting all your animations in one file is a huge help for code organization. Even if you opt for a name less literal than animations.css, you’ll know exactly where to go for anything CSS animation related. That saves time and effort when it comes to editing and maintenance. Keeping track of which animations are still currently used is easier when they’re all grouped together as well. And as an added bonus, you won’t have to look at all those horribly unattractive and repetitive prefixed @-keyframe rules unless you actually need to. An animations.css file might look something like the snippet below. It defines each animation’s keyframes and defines a class for each variation of that animation you’ll be using. Depending on the situation, you may also want to include transitions here in a similar way. (I’ve found defining transitions as their own class, or mixin, to be a huge help in past projects for me.) // defining the animation @keyframes catFall { from { background-position: center 0;} to {background-position: center 1000px;} } @-webkit-keyframes catFall { from { background-position: center 0;} to {background-position: center 1000px;} } @-moz-keyframes catFall { from { background-position: center 0;} to {background-position: center 1000px;} } @-ms-keyframes catFall { from { background-position: center 0;} to {background-position: center 1000px;} } … // class that assigns the animation .catsBackground { height: 100%; background: transparent url(../endlessKittens.png) 0 0 repeat-y; animation: catFall 1s linear infinite; -webkit-animation: catFall 1s linear infinite; -moz-animation: catFall 1s linear infinite; -ms-animation: catFall 1s linear infinite; } If we don’t need it, why load it? Having all those CSS animations and transitions in one file gives us the added flexibility to load them only when we want to. Loading a whole lot of things that will never be used might seem like a bit of a waste. While CSS has us impressed with its motion chops, it falls flat when it comes to the logic and fine-grained control. JavaScript, on the other hand, is pretty good at both those things. Chances are the content of your animations.css file isn’t acting alone. You’ll likely be adding and removing classes via JavaScript to manage your CSS animations at the very least. If your CSS animations are so entwined with JavaScript, why not let them hang out with the rest of the behaviour layer and only come out to play when JavaScript is supported? Dynamically linking your animations.css file like this means it will be completely ignored if JavaScript is off or not supported. No JavaScript? No additional behaviour, not even the parts handled by CSS. <script> document.write('<link rel="stylesheet" type="text/css" href="animations.css">'); </script> This technique comes up in progressive enhancement techniques as well, but it can help here to keep your presentation and behaviour nicely separated when more than one language is involved. The aim in both cases is to avoid loading files we won’t be using. If you happen to be doing something a bit fancier – like 3-D transforms or critical animations that require more nuanced fallbacks – you might need something like modernizr to step in to determine support more specifically. But the general idea is the same. Summing it all up Using a couple of simple techniques like these, we get to pick where to best draw the line between behaviour and presentation based on the situation at hand, not just on what language we’re using. The power of when to separate and how to reassemble the individual pieces can be even greater if you use preprocessors as part of your process. We’ve got a lot of options! The important part is to make forward-thinking choices to save your future self, and even your current self, unnecessary headaches. 2012 Val Head valhead 2012-12-08T00:00:00+00:00 https://24ways.org/2012/giving-css-animations-and-transitions-their-place/ code
152 CSS for Accessibility CSS is magical stuff. In the right hands, it can transform the plainest of (well-structured) documents into a visual feast. But it’s 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. Even better, no sexy visuals will be harmed by the use of these techniques. Promise. Nae knickers This is less of an accessibility tip, and more of a reminder to check that you’ve got your body background colour specified. If you’re sitting there wondering why I’m mentioning this, because it’s 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. Forgetting 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. All it needs is the following line to be added to your CSS file: body {background-color: #fff;} If you pair it with color: #000; … you’ll be assured of maintaining contrast for any areas you inadvertently forget to specify, no matter what colour scheme your user needs or prefers. Even better, if you’ve got standard reset CSS you use, make sure that default colours for background and text are specified in it, so you’ll never be caught with your pants down. At the very least, you’ll have a white background and black text that’ll prompt you to change them to your chosen colours. Elbow room Paying attention to your typography is important, but it’s not just about making it look nice. Careful 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. When 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’re reading across. So, a bit of room is good. That 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’ve just read. Using 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. For example: p { font-family: "Lucida Grande", Lucida, Verdana, Helvetica, sans-serif; font-size: 1em; line-height: 1.3; } or if you want to use the shorthand version: p { font: 1em/1.3 "Lucida Grande", Lucida, Verdana, Helvetica, sans-serif; } View some examples of different line-heights, based on default text size of 100%/1em. Further reading on Unitless line-heights from Eric Meyer. Transformers: Initial case in disguise Nobody wants to shout at their users, but there are some occasions when you might legitimately want to use uppercase on your site. Avoid screen-reader pronunciation weirdness (where, for example, CONTACT US would be read out as Contact U S, which is not the same thing – 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. For example: .uppercase { text-transform: uppercase } Don’t overdo it though, as uppercase text is harder to read than normal text, not to mention the whole SHOUTING thing. Linky love When 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. This Christmas, share the accessibility love and light up those links so all of your users can easily find their way around your site. The link outline AKA: the focus ring, or that dotted box that goes around links to show users where they are on the site. The techniques below are intended to supplement this, not take the place of it. You may think it’s ugly and want to get rid of it, especially since you’re going to the effort of tarting up your links. Don’t. Just don’t. The non-underlined underline If you listen to Jacob Nielsen, every link on your site should be underlined so users know it’s a link. You 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’s a couple of pixels away from the text. The underline is still there, but it’s no longer cutting off the bottom of letters with descenders (e.g., g and y) which makes it easier to read. This is illustrated in Examples 1 and 2. You 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. text-decoration: none; border-bottom: 1px #000 solid; padding-bottom: 2px; Standing out from the crowd Whatever 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. A good way of doing this is to reverse the colours when on hover or focus. Well-focused Everyone 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. So 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. Of course, the internets being what they are, it’s not quite that simple, and predictably, Internet Explorer is the culprit once more with it’s frustrating lack of support for :focus. Instead it applies the :active pseudo class whenever an anchor has focus. What 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. Even better, since the look and feel necessarily has to be the same for the last three states, you can combine them into one rule. So 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: a:link { background: #fff; color: #000; font-weight: bold; text-decoration: none; border-bottom: 1px #000 solid; padding-bottom: 2px; } a:visited { background: #fff; color: #800080; font-weight: bold; text-decoration: none; border-bottom: 1px #000 solid; padding-bottom: 2px; } a:focus, a:hover, a:active { background: #000; color: #fff; font-weight: bold; text-decoration: none; border-bottom: 1px #000 solid; padding-bottom: 2px; } Example 3 shows what this looks like in practice. Location, Location, Location To take this example to it’s 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’re currently in. Example navigation using location indicators. and the source code Conclusion All 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 – that’s up to you and whatever visual design you’re using at the time. They’re also not the only things you should be doing to make your site accessible. Above all, remember that accessibility is for life, not just for Christmas. 2007 Ann McMeekin annmcmeekin 2007-12-13T00:00:00+00:00 https://24ways.org/2007/css-for-accessibility/ design
98 Absolute Columns CSS layouts have come quite a long way since the dark ages of web publishing, with all sorts of creative applications of floats, negative margins, and even background images employed in order to give us that most basic building block, the column. As the title implies, we are indeed going to be discussing columns today—more to the point, a handy little application of absolute positioning that may be exactly what you’ve been looking for… Care for a nightcap? If you’ve been developing for the web for long enough, you may be familiar with this little children’s fable, passed down from wizened Shaolin monks sitting atop the great Mt. Geocities: “Once upon a time, multiple columns of the same height could be easily created using TABLES.” Now, though we’re all comfortably seated on the standards train (and let’s be honest: even if you like to think you’ve fallen off, if you’ve given up using tables for layout, rest assured your sleeper car is still reserved), this particular—and as page layout goes, quite basic—trick is still a thorn in our CSSides compared to the ease of achieving the same effect using said Tables of Evil™. See, the orange juice masks the flavor… Creative solutions such as Dan Cederholm’s Faux Columns do a good job of making it appear as though adjacent columns maintain equal height as content expands, using a background image to fill the space that the columns cannot. Now, the Holy Grail of CSS columns behaving exactly how they would as table cells—or more to the point, as columns—still eludes us (cough CSS3 Multi-column layout module cough), but sometimes you just need, for example, a secondary column (say, a sidebar) to match the height of a primary column, without involving the creation of images. This is where a little absolute positioning can save you time, while possibly giving your layout a little more flexibility. Shaken, not stirred You’re probably familiar by now with the concept of Making the Absolute, Relative as set forth long ago by Doug Bowman, but let’s quickly review just in case: an element set to position:absolute will position itself relative to its nearest ancestor set to position:relative, rather than the browser window (see Figure 1). Figure 1. However, what you may not know is that we can anchor more than two sides of an absolutely positioned element. Yes, that’s right, all four sides (top, right, bottom, left) can be set, though in this example we’re only going to require the services of three sides (see Figure 2 for the end result). Figure 2. Trust me, this will make you feel better Our requirements are essentially the same as the standard “absolute-relative” trick—a container <div> set to position:relative, and our sidebar <div> set to position:absolute — plus another <div> that will serve as our main content column. We’ll also add a few other common layout elements (wrapper, header, and footer) so our example markup looks more like a real layout and less like a test case: <div id="wrapper"> <div id="header"> <h2>#header</h2> </div> <div id="container"> <div id="column-left"> <h2>#left</h2> <p>Lorem ipsum dolor sit amet…</p> </div> <div id="column-right"> <h2>#right</h2> </div> </div> <div id="footer"> <h2>#footer</h2> </div> </div> In this example, our main column (#column-left) is only being given a width to fit within the context of the layout, and is otherwise untouched (though we’re using pixels here, this trick will of course work with fluid layouts as well), and our right keeping our styles nice and minimal: #container { position: relative; } #column-left { width: 480px; } #column-right { position: absolute; top: 10px; right: 10px; bottom: 10px; width: 250px; } The trick is a simple one: the #container <div> will expand vertically to fit the content within #column-left. By telling our sidebar <div> (#column-right) to attach itself not only to the top and right edges of #container, but also to the bottom, it too will expand and contract to match the height of the left column (duplicate the “lorem ipsum” paragraph a few times to see it in action). Figure 3. On the rocks “But wait!” I hear you exclaim, “when the right column has more content than the left column, it doesn’t expand! My text runneth over!” Sure enough, that’s exactly what happens, and what’s more, it’s supposed to: Absolutely positioned elements do exactly what you tell them to do, and unfortunately aren’t very good at thinking outside the box (get it? sigh…). However, this needn’t get your spirits down, because there’s an easy way to address the issue: by adding overflow:auto to #column-right, a scrollbar will automatically appear if and when needed: #column-right { position: absolute; top: 10px; right: 10px; bottom: 10px; width: 250px; overflow: auto; } While this may limit the trick’s usefulness to situations where the primary column will almost always have more content than the secondary column—or where the secondary column’s content can scroll with wild abandon—a little prior planning will make it easy to incorporate into your designs. Driving us to drink It just wouldn’t be right to have a friendly, festive holiday tutorial without inviting IE6, though in this particular instance there will be no shaming that old browser into admitting it has a problem, nor an intervention and subsequent 12-step program. That’s right my friends, this tutorial has abstained from IE6-abuse now for 30 days, thanks to the wizard Dean Edwards and his amazingly talented IE7 Javascript library. Simply drop the Conditional Comment and <script> element into the <head> of your document, along with one tiny CSS hack that only IE6 (and below) will ever see, and that browser will be back on the straight and narrow: <!--[if lt IE 7]> <script src="http://ie7-js.googlecode.com/svn/version/2.0(beta3)/IE7.js" type="text/javascript"></script> <style type="text/css" media="screen"> #container { zoom:1; /* helps fix IE6 by initiating hasLayout */ } </style> <![endif]--> Eggnog is supposed to be spiked, right? Of course, this is one simple example of what can be a much more powerful technique, depending on your needs and creativity. Just don’t go coding up your wildest fantasies until you’ve had a chance to sleep off the Christmas turkey and whatever tasty liquids you happen to imbibe along the way… 2008 Dan Rubin danrubin 2008-12-22T00:00:00+00:00 https://24ways.org/2008/absolute-columns/ code
22 The Responsive Hover Paradigm CSS transitions and animations provide web designers with a whole slew of tools to spruce up our designs. Move over ActionScript tweens! The techniques we can now implement with CSS are reminiscent of Flash-based adventures from the pages of web history. Pairing CSS enhancements with our :hover pseudo-class allows us to add interesting events to our websites. We have a ton of power at our fingertips. However, with this power, we each have to ask ourselves: just because I can do something, should I? Why bother? We hear a lot of mantras in the web community. Some proclaim the importance of content; some encourage methods like mobile first to support content; and others warn of the overhead and speed impact of decorative flourishes and visual images. I agree, one hundred percent. At the same time, I believe that content can reign king and still provide a beautiful design with compelling interactions and acceptable performance impacts. Maybe, just maybe, we can even have a little bit of fun when crafting these systems! Yes, a site with pure HTML content and no CSS will load very fast on your mobile phone, but it leaves a lot to be desired. If you went to your local library and every book looked the same, how would you know which one to borrow? Imagine if every book was printed on the same paper stock with the same cover page in the same type size set at a legible point value… how would you know if you were going to purchase a cookbook about wild game or a young adult story about teens fighting to the death? For certain audiences, seeing a site with hip, lively hovers sure beats a stale website concept. I’ve worked on many higher education sites, and setting the interactive options is often a very important factor in engaging potential students, alumni, and donors. The same can go for e-commerce sites: enticing your audience with surprise and delight factors can be the difference between a successful and a lost sale. Knowing your content and audience can help you decide if an intriguing experience is appropriate for your site; if it is, then hover responses can be a real asset. Why hover? We have all these capabilities with CSS properties to create the aforementioned fun interactions, and it would be quite easy to fall back into some old patterns and animation abuse. The world of Flash intros and skip links could be recreated with CSS keyframes. However, I don’t think any of us want to go the route of forcing users into unwanted exchanges and road blocking content. What’s great about utilizing hover to pair with CSS powered actions is that it’s user initiated. It’s a well-established expectation that when a user mouses over an object, something changes. If we can identify that something as a link, then we will expect something to change as we move our mouse over it. By waiting to trigger a CSS-based response until a user chooses to engage with a target makes for a more polished experience (as opposed to barraging our screens with animations all willy-nilly). This makes it the perfect opportunity to add some unique spunk. What about mobile, touch, and responsive? So, you’re on board with this so far, but what about mobile and touch devices? Sure, some devices like the Samsung Galaxy S4 have some hovering capabilities, but certainly most do not. Beyond mobile devices, we also have to worry about desktops with touch capabilities. It’s super difficult to detect if a user is currently using touch or hover. One option we have is to design strictly for touch only and send hover enhancements to the graveyard. However, being that I’m all “fuck yeah hovers!,” I like to explore all options. So, let’s examine four different types of hover patterns and see how they can translate to our touch devices. 1. The essential text hover Changing text color on hover is something we’ve done for a while and it has helped aid in identifying links. To maintain the best accessibility we can achieve, it helps to have a different visual indicator on the default :link state, such as an underline. By making sure all text links have an underline, we won’t have to rely on visual changes during hover to make sure touch device users know that it is a link. For hover-enabled devices, we can add a basic color transition. Doing so creates a nice fade, which makes the change on hover less jarring. Kinda like smooth jazz. The code* to achieve this is quite simple: a { color: #6dd4b1; transition: color 0.25s linear; } a:hover, a:focus { color: #357099; } Browser prefixes are omitted You can see in the final result that, for both touch and hover, everyone wins: See the Pen Most Basic Link Transition by Jenn Lukas (@Jenn) on CodePen 2. Visual background wizardry and animated hovers We can take this a step further by again making changes to our aesthetic on hover, but not making any content changes. Altering image hovers for fun and personality can separate your site from others; that personality is important and can enhance our content. Let’s look at a few sites that do this really well. Scroll down to the judges section of CSS Off and check out the illustrations of the judges. On hover, the illustration fades into a photo of the judge. This provides a realistic alternative to the drawing. Users without the hover can click into the detail page, where they can see the full color picture and learn more about the judges; the information is still available through a different pathway. Going back to the higher education field, let’s visit Delaware Valley College. The school had recently gone through a rebranding that included loop icons as a symbol to connect ideas. These icons are brought into the website on hover of the slideshow arrows (WebKit browsers). The hover reveals a loop animation, tying in overall themes and adding some extra pizzazz that makes me think, “This is a hip place that feels current.” For visitors who can’t access the hover effect, the default arrow state clearly represents a clickable link, and there is swipe functionality on mobile devices to boot. DIY.org’s Frontend Dev page has a bunch of enjoyable hover actions happening, featuring scaling transforms and looping animations. Nothing new is revealed on hover, so touch devices won’t miss anything, but it intrigues the user who is visiting a site about front-end dev doing cool front-end things. It backs up its claim of front-end knowledge by adding this enhancement. The old Cowork Chicago (now redirecting) had a great example, captured here: Coop: Chicago Coworking from Jenn Lukas on Vimeo. The code for the Join areas is quite simple: .join-buttons .daily, .join-buttons .monthly { height: 260px; z-index: 0; margin-top: 30px; transition: height .2s linear,margin .2s linear; } .join-buttons .daily:hover, .join-buttons .monthly:hover { height: 280px; margin-top: 20px; } li.button:hover { z-index: 20; } The slight rotation on the photos, and the change of color and size of the rate options on hover, add to the fun factor. The site attempts to advertise the co-working space by letting bits of their charisma show through with these transitions. They don’t hit the user over the head with animations, but provide a nice addition to make sure visitors know it’s a welcoming place to work. Some text is added on the hover, but the text isn’t essential to determine where the link goes. 3. Image block hovers There have been more designs popping up with large image blocks acting as extensive hit area links to subsequent pages. On hover of these links, text is revealed, letting the user know where the link destination goes. See the Pen Transitioning Max Height by Jenn Lukas (@Jenn) on CodePen This type of link is tough for users on touch as the image might not provide enough context to reveal its target. If you weren’t aware of what my illustrated avatar from 2007 looked like (or even if you did), then how would you know that this is a link to my Twitter page? Instead, if we provide enough context — such as the @jennlukas handle — you could assume the destination. Users who receive the hover can also see the Twitter bio. It won’t break the experience for users that can’t hover, but it will provide a nice interaction and some more information for those that can. See the Pen Transitioning Max Height by Jenn Lukas (@Jenn) on CodePen The Esquire site follows this same pattern, in which the title of the story is shown and the subheading is revealed on hover. Dining at Altitude took the opposite approach, where all text is shown by default and, on hover, you can see more of the image that the text sits atop. This is a nice technique to follow. For touch users, following the link will allow them to see more of the image detail that was revealed on hover. 4. Drop-down navigation menu hovers Main navigation options that rely on hover have come up as a problem for touch. One way to address this is to be sure your top level items are all functional links to somewhere, and not blank anchors to trigger a submenu drop-down. This ensures that, even without the hover-triggered menu, users can still navigate to those top-level pages. From there, they should be able to access the tertiary pages shown in the drop-down. Following this arrangement, drop-down menus act as a quick shortcut and aren’t necessary to the navigational structure. If the top navigation items are your most visited pages, this execution won’t hinder your visitors. If the information within the menu is vital, such as a lone account menu, another option is to show drop-down menus on click instead of hover. This pattern will allow both mouse and touch users to access the drop-downs. Why can’t we just detect hover? This is a really tricky thing to do. Internet Explorer 10 on Windows 8 uses the aria-haspopup attribute to simulate hover on touch devices, but usually our audience stretches beyond that group. There’s been discussion around using Modernizr, but false positives have come with that. A W3C draft for Media Queries Level 4 includes a hover feature, but it’s not supported yet. Since some devices can hover and touch, should you rely on hover effects for those? Arguments have come up that users can be browsing your site with a mouse and then decide to switch to touch, or vice versa. That might be a large concern for you, or it might be an edge case that isn’t vital to your site’s success. For one site, I used mousemove and touchstart JavaScript events in order to detect if a visitor starts to browse the site with a mouse. The design initiates for touch users, showing all text on load, but as soon as a mouse movement occurs, the text becomes hidden and is then revealed on hover. See the Pen Detect Touch devices with mousemove and touchstart by Jenn Lukas (@Jenn) on CodePen One downside to this approach is that the text is viewable until a mouse enters the document, but if the elements are further down the page it might not be noticed. A second downside is if a user on a touch- and hover-enabled device starts browsing with the mouse and then switches back to touch, the hover-centric styles will remain until a new page load. These were acceptable scenarios in the project I worked on, but might not be for every project. Can we give our visitors a choice? I’ve been thinking about how we can combat the concern of not knowing if our customers are using touch or a mouse, not to mention keyboard or Wacom tablets or Minority Report screens. We can cover keyboards with our friend :focus, but that still doesn’t solve our other dilemmas. Remember when we couldn’t rely on browsers to zoom text and we had to use those small A, medium A, big A [AAA] buttons? On selection of one of those options, a different style sheet would load with small, medium, or large text sizes to satisfy our user’s request. We could even set cookies to remember their font choices. What if we offered a similar solution, a hover/touch switcher, for our new predicament? See the Pen cwuJf by Jenn Lukas (@Jenn) on CodePen We could add this switcher to our design. Maybe add it to the header on smaller screens and the footer on larger screens to play the odds. Then be sure to deliver the appropriate touch- or hover-optimized adventure for our guests. How about adding View options in the areas where we’re hiding content until hover? Looking at Delta Cycle, there’s logic in place to switch layouts on some mobile devices. On desktops we can see the layout shows the product and price by default, and the name of the item and an Add to cart button on hover. If you want to keep this hover, but also worry that touch users can’t access it — or even if you are concerned that people might want to view it with more details up front — we could add another view switcher. See the Pen List/Grid Views for Hover or Touch by Jenn Lukas (@Jenn) on CodePen Similar to the list versus grid view we often see in operating systems, a choice here could cover all of our bases. Conclusion There is no one-size-fits-all solution when it comes to hover patterns. Design for your content. If you are providing important information about driving directions or healthcare, you might want to err on the side of designing for touch only. If you are behind an educational site and trying to entice more traffic and sign-ups, or a more immersive e-commerce site selling pies, then hover activity can help support your content and engage your visitors without being a detriment. While content can be our top priority, let’s not forget that our designs and interactions, hovers included, can have a great positive impact on how visitors experience our site. Hover wisely, friends. 2013 Jenn Lukas jennlukas 2013-12-12T00:00:00+00:00 https://24ways.org/2013/the-responsive-hover-paradigm/  
75 A Harder-Working Class Class is only becoming more important. Focusing on its original definition as an attribute for grouping (or classifying) as well as linking HTML to CSS, recent front-end development practices are emphasizing class as a vessel for structured, modularized style packages. These patterns reduce the need for repetitive declarations that can seriously bloat file sizes, and instil human-readable understanding of how the interface, layout, and aesthetics are constructed. In the next handful of paragraphs, we will look at how these emerging practices – such as object-oriented CSS and SMACSS – are pushing the relevance of class. We will also explore how HTML and CSS architecture can be further simplified, performance can be boosted, and CSS utility sharpened by combining class with the attribute selector. A primer on attribute selectors While attribute selectors were introduced in the CSS 2 spec, they are still considered rather exotic. These well-established and well-supported features give us vastly improved flexibility in targeting elements in CSS, and offer us opportunities for smarter markup. With an attribute selector, you can directly style an element based on any of its unique – or uniquely shared – attributes, without the need for an ID or extra classes. Unlike pseudo-classes, pseudo-elements, and other exciting features of CSS3, attribute selectors do not require any browser-specific syntax or prefix, and are even supported in Internet Explorer 7. For example, say we want to target all anchor tags on a page that link to our homepage. Where otherwise we might need to manually identify and add classes to the HTML for these specific links, we could simply write: [href=index.html] { } This selector reads: target every element that has an href attribute of “index.html”. Attribute selectors are more faceted, though, as they also give us some very simple regular expression-like logic that helps further narrow (or widen) a selector’s scope. In our previous example, what if we wanted to also give indicative styles to any anchor tag linking to an external site? With no way to know what the exact href value would be for every external link, we need to use an expression to match a common aspect of those links. In this case, we know that all external links need to start with “http”, so we can use that as a hook: [href^=http] { } The selector here reads: target every element that has an href attribute that begins with “http” (which will also include “https”). The ^= means “starts with”. There are a few other simple expressions that give us a lot of flexibility in targeting elements, and I have found that a deep understanding of these and other selector types to be very useful. The class-attribute selector By matching classes with the attribute selector, CSS can be pushed to accomplish some exciting new feats. What I call a class-attribute selector combines the advantages of classes with attribute selectors by targeting the class attribute, rather than a specific class. Instead of selecting .urgent, you could select [class*=urgent]. The latter may seem like a more verbose way of accomplishing the former, but each would actually match two subtly different groups of elements. Eric Meyer first explored the possibility of using classes with attribute selectors over a decade ago. While his interest in this technique mostly explored the different facets of the syntax, I have found that using class-attribute selectors can have distinct advantages over either using an attribute selector or a straightforward class selector. First, let’s explore some of the subtleties of why we would target class before other attributes: Classes are ubiquitous. They have been supported since the HTML 4 spec was released in 1999. Newer attributes, such as the custom data attribute, have only recently begun to be adopted by browsers. Classes have multiple ways of being targeted. You can use the class selector or attribute selector (.classname or [class=classname]), allowing more flexible specificity than resorting to an ID or !important. Classes are already widely used, so adding more classes will usually require less markup than adding more attributes. Classes were designed to abstractly group and specify elements, making them the most appropriate attribute for styling using object-oriented methods (as we will learn in a moment). Also, as Meyer pointed out, we can use the class-attribute selector to be more strict about class declarations. Of these two elements: <h2 class="very urgent"> <h2 class="urgent"> …only the second h2 would be selected by [class=urgent], while .urgent would select both. The use of = matches any element with the exact class value of “urgent”. Eric explores these nuances further in his series on attribute selectors, but perhaps more dramatic is the added power that class-attribute selectors can bring to our CSS. More object-oriented, more scalable and modular Nicole Sullivan has been pushing abstracted, object-oriented thinking in CSS development for years now. She has shared stacks of knowledge on how behemoth sites have seen impressive gains in maintenance overhead and CSS file sizes by leaning heavier on classes derived from common patterns. Jonathan Snook also speaks, writes and is genuinely passionate about improving our markup by using more stratified and modular class name conventions. With SMACSS, he shows this to be highly useful across sites – both complex and simple – that exhibit repeated design patterns. Sullivan and Snook both push the use of class for styling over other attributes, and many front-end developers are fast advocating such thinking as best practice. With class-attribute selectors, we can further abstract our CSS, pushing its scalability. In his chapter on modules, Snook gives the example of a .pod class that might represent a certain set of styles. A .pod style set might be used in varying contexts, leading to CSS that might normally look like this: .pod { } form .pod { } aside .pod { } According to Snook, we can make these styles more portable by targeting more verbose classes, rather than context: .pod { } .pod-form { } .pod-sidebar { } …resulting in the following HTML: <div class="pod"> <div class="pod pod-form"> <div class="pod pod-sidebar"> This divorces the <div>’s styles from its context, making it applicable to any situation in which it is needed. The markup is clean and portable, and the classes are imbued with meaning as to what module they belong to. Using class-attribute selectors, we can simplify this further: [class*=pod] { } .pod-form { } .pod-sidebar { } The *= tells the browser to look for any element with a class attribute containing “pod”, so it matches “pod”, “pod-form”, “pod-sidebar”, etc. This allows only one class per element, resulting in simpler HTML: <div class="pod"> <div class="pod-form"> <div class="pod-sidebar"> We could further abstract the concept of “form” and “sidebar” adjustments if we knew that each of those alterations would always need the same treatment. /* Modules */ [class*=pod] { } [class*=btn] { } /* Alterations */ [class*=-form] { } [class*=-sidebar] { } In this case, all elements with classes appended “-form” or “-sidebar” would be altered in the same manner, allowing the markup to stay simple: <form> <h2 class="pod-form"> <a class="btn-form" href="#"> <aside> <h2 class="pod-sidebar"> <a class="btn-sidebar" href="#"> 50+ shades of specificity Classes are just powerful enough to override element selectors and default styling, but still leave room to be trumped by IDs and !important styles. This makes them more suitable for object-oriented patterns and helps avoid messy specificity issues that can not only be a pain for developers to maintain, but can also affect a site’s performance. As Sullivan notes, “In almost every case, classes work well and have fewer unintended consequences than either IDs or element selectors”. Proper use of specificity and cascade is crucial in building straightforward, efficient CSS. One interesting aspect of attribute selectors is that they can be compounded for increasing levels of specificity. Attribute selectors are assigned a specificity level of ten, the same as class selectors, but both class and attribute selectors can be chained together, giving them more and more specificity with each link. Some examples: .box { } /* Specificity of 10 */ .box.promo { } /* Specificity of 20 */ [class*=box] { } /* Specificity of 10 */ [class*=box][class*=promo] { } /* Specificity of 20 */ You can chain both types together, too: .box[class*=promo] { } /* Specificity of 20 */ I was amused to find, though, that you can chain the exact same class and attribute selectors for infinite levels of specificity .box { } /* Specificity of 10 */ .box.box { } /* Specificity of 20 */ .box.box.box { } /* Specificity of 30 */ [class*=box] { } /* Specificity of 10 */ [class*=box][class*=box] { } /* Specificity of 20 */ [class*=box][class*=box][class*=box] { } /* Specificity of 30 */ .box[class*=box].box[class*=box] { } /* Specificity of 40 */ To override .box styles for promo, we wouldn’t need to add an ID, change the order of .promo and .box in the CSS, or resort to an !important style. Granted, any issue that might need this fine level of specificity tweaking could probably be better solved with clever cascades, but having options never hurts. Smarter CSS One of the most powerful aspects of the class-attribute selector is its ability to expand the simple logic found in CSS. When developing Gridset (an online tool for building grids and outputting them as CSS), I realized that with the right class name conventions, class-attribute selectors would allow the CSS to be smart enough to automatically adjust for column offsets without the need for extra classes. This imbued the CSS output with logic that other frameworks lacked, and makes a developer’s job much easier. Say you need an element that spans column five (c5) to column six (c6) on your grid, and is preceded by an element spanning column one (c1) to column three (c3). The CSS can anticipate such a scenario: .c1-c3 + .c5-c6 { margin-left: 25%; /* …or the width of column four plus two gutter widths */ } …but to accommodate all of the margin offsets that could span that same gap, we would need to write a rather protracted list for just a six column grid: .c1-c3 + .c5-c6, .c1-c3 + .c5, .c2-c3 + .c5-c6, .c2-c3 + .c5, .c3 + .c5-c6, .c3 + .c5 { margin-left: 25%; } Now imagine how the verbosity compounds when we repeat this type of declaration for every possible margin in a grid. The more columns added to the grid, the longer this selector list would get, too, making the CSS harder for the developer to maintain and slowing the load time. Using class-attribute selectors, though, this can be much simpler: [class*=c3] + [class*=c5] { margin-left: 25%; } I’ve detailed how we extract as much logic as possible from as little CSS as needed on the Gridset blog. More flexible selectors In a recent project, I was working with Drupal-generated classes to change styles for certain special pages on a site. Without being able to change the code base, I was left trying to find some specific aspect of the generated HTML to target. I noticed that every special page was given a prefixed class, unique to the page, resulting in CSS like this: .specialpage-about, .specialpage-contact, .specialpage-info, … …and the list kept growing with each new special page. Such bloat would lead to problems down the line, and add development overhead to editorial decisions, which was a situation we were trying to avoid. I was easily able to fix this, though, with a concise class-attribute selector: [class*=specialpage-] The CSS was now flexible enough to accommodate both the editorial needs of the client, and the development restrictions of the CMS. Selector performance As Snook tells us in his chapter on Selector Performance, selectors are read by the browser from right to left, matching every element that adheres to each rule (or part of the selector). The more specific we can make the right-most rules – and every other part of your selectors – the more performant your CSS will be. So this selector: .home-page .promo .main-header …would be more performant than: .home-page div header …because there are likely many more header and div elements on the page, but not so many elements with those specific classes. Now, the class-attribute selector could be more general than a class selector, but not by much. I ran numerous tests based on the work of Steve Souders (and a few others) to test a class-attribute selector against a normal class selector. Given that Javascript will freeze during style rendering, I created a script that will add, then remove, a stylesheet on a page 5000 times, and measure only the time that elapses during the rendering freeze. The script runs four tests, essentially: one where a class selector and class-attribute Selector match a single element, and one they match multiple elements on the page. After running the test over 100 times and averaging the results, I have not seen a significant difference in rendering times. (As of this writing, the class-attribute selector has been 0.398% slower on average.) View the results here. Given the sheer amount of bytes potentially saved by reducing selector lists, though, I am confident class-attribute selectors could shorten load times on larger sites and, at the very least, save precious development time. Conclusion With its flexibility and broad remit, class has at times been derided as too lenient, allowing CMSes and lazy developers to fill its values with presentational hacks or verbose gibberish. There have even been calls for an early retirement. Class continues, though, to be one of our most crucial tools. Front-end developers are rightfully eager to expand production abilities through innovations such as Sass or LESS, but this should not preclude us from honing the tools we already know as well. Every technique demonstrated in this article was achievable over a decade ago and most of the same thinking could be applied to IDs, rels, or any other attribute (though the reasons listed above give class an edge). The recent advent of methods such as object-oriented CSS and SMACSS shows there is still much room left to expand what simple HTML and CSS can accomplish. Progress may not always be found in the innovation of our tools, but through sharpening our understanding of them. 2012 Nathan Ford nathanford 2012-12-15T00:00:00+00:00 https://24ways.org/2012/a-harder-working-class/ code
206 Getting Hardboiled with CSS Custom Properties Custom Properties are a fabulous new feature of CSS and have widespread support in contemporary browsers. But how do we handle browsers without support for CSS Custom Properties? Do we wait until those browsers are lying dead in a ditch before we use them? Do we tool up and prop up our CSS using a post-processor? Or do we get tough? Do we get hardboiled? Previously only pre-processing tools like LESS and Sass enabled developers to use variables in their stylesheets, but now Custom Properties have brought variables natively to CSS. How do you write a custom property? It’s hardly a mystery. Simply add two dashes to the start of a style rule. Like this: --color-text-default : black; If you’re more the underscore type, try this: --color_text_default : black; Hyphens or underscores are allowed in property names, but don’t be a chump and try to use spaces. Custom property names are also case-sensitive, so --color-text-default and --Color_Text_Default are two distinct properties. To use a custom property in your style rules, var() tells a browser to retrieve the value of a property. In the next example, the browser retrieves the black colour from the color-text-default variable and applies it to the body element: body { color : var(--color-text-default); } Like variables in LESS or Sass, CSS Custom Properties mean you don’t have to be a dumb mug and repeat colour, font, or size values multiple times in your stylesheets. Unlike a preprocessor variable though, CSS Custom Properties use the cascade, can be modified by media queries and other state changes, and can also be manipulated by Javascript. (Serg Hospodarets wrote a fabulous primer on CSS Custom Properties where he dives deeper into the code and possible applications.) Browser support Now it’s about this time that people normally mention browser support. So what about support for CSS Custom Properties? Current versions of Chrome, Edge, Firefox, Opera, and Safari are all good. Internet Explorer 11 and before? Opera Mini? Nasty. Sound familiar? Can I Use css-variables? Data on support for the css-variables feature across the major browsers from caniuse.com. Not to worry, we can manually check for Custom Property support in a browser by using an @support directive, like this: --color-text-default : black; body { color : black; } @supports ((--foo : bar)) { body { color : var(--color-text-default); } } In that example we first set body element text to black and then override that colour with a Custom Property value when the browser supports our fictitious foo bar variable. Substitutions If we reference a variable that hasn’t been defined, that won’t be a problem as browsers are smart enough to ignore the value altogether. If we need a cast iron alibi, use substitutions to specify a fall-back value. body { color : var(--color-text-default, black); } Substitutions are similar to font stacks in that they contain a comma separated list of values. If there’s no value associated with a property, a browser will ignore it and move onto the next value in the list. Post-processing Of course we could use a post-processor plugin to turn Custom Properties into plain CSS, but hang on one goddam minute kiddo. Haven’t we been down this road before? Didn’t we engineer elaborate workarounds to enable us to use ‘advanced’ CSS3 properties like border-radius, CSS columns, and Flexbox in the past? We did what we had to do to get the job done, but came away feeling dirty. I think there’s a better way, one that allows us to enjoy the benefits of CSS Custom Properties in browsers that support them, while providing an appropriate, but not identical experience, for people who use less capable browsers. Guess what, I’ve been down this road before too. 2Tone Stuff & Nonsense When Internet Explorer 6 was the big dumb browser everyone hated, I served two different designs on my website. For the modern browsers of the time, mod arrows and targets were everywhere in glorious red, white, and blue, and I implemented all of them using CSS attribute selectors which were considered advanced at the time: [class="banner"] { background-colour : red; } Internet Explorer 6 ignored any selectors it didn’t understand, so people using that browser saw a simpler black and white, 2Tone-based design that I’d implemented for them using class selectors: .banner { background-colour : black; } [class="banner"] { background-colour : red; } You don’t have to be a detective to find out that most people thought I’d lost my wits, but Microsoft even used my website as a reference when they tested attribute selectors in Internet Explorer 7. They did, as I suggested, “Stomp to da betta browser.” Dumb browsers look the other way So how does this approach relate to tackling any lack of support for CSS Custom Properties? How can we take advantage of them without worrying about browsers with no support and having to implement complex workarounds, or spending hours specifying fallbacks that perfectly match our designs? Turns out, the answer is built into CSS, and always has been, because when browsers don’t know what they’re looking at, they look away. All we have to do is first specify values for a simpler design first, and then follow that up with the values in our CSS Custom Properties: body { color : black; color : var(--color-text-default, black); } All browsers understand the first value (black,) and if they‘re smart enough to understand the second (var(--color-text-default)), they’ll use it and override the first. If they’re too damn stupid to understand the custom property value, they’ll ignore it. Nobody dies. Repeat this for every style that contains a variable, baking an alternative, perhaps simpler design into your stylesheets for people who use less capable browsers, just like I did with Stuff & Nonsense. Conclusion I doubt that anyone agrees with presenting a design that looks broken or unloved—and I’m not advocating for that—but websites need not look the same in every browser. We can use substitutions to present a simpler design to people using less capable browsers. The decision when to start using new CSS properties isn‘t always a technical one. Sometimes a change in attitude about browser support is all that’s required. So get tough with dumb browsers and benefit from all the advantages that CSS Custom Properties offer. Get hardboiled. Resources: It’s Time To Start Using CSS Custom Properties—Smashing Magazine Using CSS variables correctly—Mike Riethmuller Developing Inspired Guides with CSS Custom Properties (variables)—Andy Clarke 2017 Andy Clarke andyclarke 2017-12-13T00:00:00+00:00 https://24ways.org/2017/getting-hardboiled-with-css-custom-properties/ code
205 Why Design Systems Fail Design systems are so hot right now, and for good reason. They promote a modular approach to building a product, and ensure organizational unity and stability via reusable code snippets and utility styles. They make prototyping a breeze, and provide a common language for both designers and developers. A design system is a culmination of several individual components, which can include any or all of the following (and more): Style guide or visual pattern library Design tooling (e.g. Sketch Library) Component library (where the components live in code) Code usage guidelines and documentation Design usage documentation Voice and tone guideline Animation language guideline Design systems are standalone (internal or external) products, and have proven to be very effective means of design-driven development. However, in order for a design system to succeed, everyone needs to get on board. I’d like to go over a few considerations to ensure design system success and what could hinder that success. Organizational Support Put simply, any product, including internal products, needs support. Something as cross-functional as a design system, which spans every vertical project team, needs support from the top and bottom levels of your organization. What I mean by that is that there needs to be top-level support from project managers up through VP’s to see the value of a design system, to provide resources for its implementation, and advocate for its use company-wide. This is especially important in companies where such systems are being put in place on top of existing, crufty codebases, because it may mean there needs to be some time and effort put in the calendar for refactoring work. Support from the bottom-up means that designers and engineers of all levels also need to support this system and feel responsibility for it. A design system is an organization’s product, and everyone should feel confident contributing to it. If your design system supports external clients as well (such as contractors), they too can become valuable teammates. A design system needs support and love to be nurtured and to grow. It also needs investment. Investment To have a successful design system, you need to make a continuous effort to invest resources into it. I like to compare this to working out. You can work out intensely for 3 months and see some gains, but once you stop working out, those will slowly fade away. If you continue to work out, even if its less often than the initial investment, you’ll see yourself maintaining your fitness level at a much higher rate than if you stopped completely. If you invest once in a design system (say, 3 months of overhauling it) but neglect to keep it up, you’ll face the same situation. You’ll see immediate impact, but that impact will fade as it gets out of sync with new designs and you’ll end up with strange, floating bits of code that nobody is using. Your engineers will stop using it as the patterns become outdated, and then you’ll find yourself in for another round of large investment (while dreading going through the process since its fallen so far out of shape). With design systems, small incremental investments over time lead to big gains overall. With this point, I also want to note that because of how they scale, design systems can really make a large impact across the platform, making it extremely important to really invest in things like accessibility and solid architecture from the start. You don’t want to scale a brittle system that’s not easy to use. Take care of your design systems, and keep working on them to ensure their effectiveness. One way to ensure this is to have a dedicated team working on this design system, managing tickets and styling updates that trickle out to the rest of your company. Responsibility With some kind of team to act as an owner of a design system, whether it be the design team, engineering team, or a new team made of both designers and engineers (the best option), your company is more likely to keep a relevant, up-to-date system that doesn’t break. This team is responsible for a few things: Helping others get set up on the system (support) Designing and building components (development) Advocating for overall UI consistency and adherence (evangelism) Creating a rollout plan and update system (product management) As you can see, these are a lot of roles, so it helps to have multiple people on this team, at least part of the time, if you can. One thing I’ve found to be effective in the past is to hold office hours for coworkers to book slots within to help them get set up and to answer any questions about using the system. Having an open Slack channel also helps for this sort of thing, as well as for bringing up bugs/issues/ideas and being an channel for announcements like new releases. Communication Once you have resources and a plan to invest in a design system, its really important that this person or team acts as a bridge between design and engineering. Continuous communication is really important here, and the way you communicate is even more important. Remember that nobody wants to be told what to do or prescribed a solution, especially developers, who are used to a lot of autonomy (usually they get to choose their own tools at work). Despite how much control the other engineers have on the process, they need to feel like they have input, and feel heard. This can be challenging, especially since ultimately, some party needs to be making a final decision on direction and execution. Because it’s a hard balance to strike, having open communication channels and being as transparent as possible as early as possible is a good start. Buy-in For all of the reasons we’ve just looked over, good communication is really important for getting buy-in from your users (the engineers and designers), as well as from product management. Building and maintaining a design system is surprisingly a lot of people-ops work. To get buy-in where you don’t have a previous concensus that this is the right direction to take, you need to make people want to use your design system. A really good way to get someone to want to use a product is to make it the path of least resistance, to show its value. Gather examples and usage wins, because showing is much more powerful than telling. If you can, have developers use your product in a low-stakes situation where it provides clear benefits. Hackathons are a great place to debut your design system. Having a hackathon internally at DigitalOcean was a perfect opportunity to: Evangelize for the design system See what people were using the component library for and what they were struggling with (excellent user testing there) Get user feedback afterward on how to improve it in future iterations Let people experience the benefits of using it themselves These kinds of moments, where people explore on their own are where you can really get people on your side and using the design system, because they can get their hands on it and draw their own conclusions (and if they don’t love it — listen to them on how to improve it so that they do). We don’t always get so lucky as to have this sort of instantaneous user feedback from our direct users. Architecture I briefly mentioned the scalable nature of design systems. This is exactly why it’s important to develop a solid architecture early on in the process. Build your design system with growth and scalability in mind. What happens if your company acquires a new product? What happens when it develops a new market segment? How can you make sure there’s room for customization and growth? A few things we’ve found helpful include: Namespacing Use namespacing to ensure that the system doesn’t collide with existing styles if applying it to an existing codebase. This means prefixing every element in the system to indicate that this class is a part of the design system. To ensure that you don’t break parts of the existing build (which may have styled base elements), you can namespace the entire system inside of a parent class. Sass makes this easy with its nested structure. This kind of namespacing wouldn’t be necessary per se on new projects, but it is definitely useful when integrating new and old styles. Semantic Versioning I’ve used Semantic Versioning on all of the design systems I’ve ever worked on. Semantic versioning uses a system of Major.Minor.Patch for any updates. You can then tag released on Github with versioned updates and ensure that someone’s app won’t break unintentionally when there is an update, if they are anchored to a specific version (which they should be). We also use this semantic versioning as a link with our design system assets at DigitalOcean (i.e. Sketch library) to keep them in sync, with the same version number corresponding to both Sketch and code. Our design system is served as a node module, but is also provided as a series of built assets using our CDN for quick prototyping and one-off projects. For these built assets, we run a deploy script that automatically creates folders for each release, as well as a latest folder if someone wanted the always-up-to-date version of the design system. So, semantic versioning for the system I’m currently building is what links our design system node module assets, sketch library assets, and statically built file assets. The reason we have so many ways of consuming our design system is to make adoption easier and to reduce friction. Friction A while ago, I posed the question of why design systems become outdated and unused, and a major conclusion I drew from the conversation was: “If it’s harder for people to use than their current system, people just won’t use it” You have to make your design system the path of least resistance, lowering cognitive overhead of development, not adding to it. This is vital. A design system is intended to make development much more efficient, enforce a consistent style across sites, and allow for the developer to not worry as much about small decisions like naming and HTML semantics. These are already sorted out for them, meaning they can focus on building product. But if your design system is complicated and over-engineered, they may find it frustrating to use and go back to what they know, even if its not the best solution. If you’re a Sass expert, and base your system on complex mixins and functions, you better hope your user (the developer) is also a Sass expert, or wants to learn. This is often not the case, however. You need to talk to your audience. With the DigitalOcean design system, we provide a few options: Option 1 Users can implement the component library into a development environment and use Sass, select just the components they want to include, and extend the system using a hook-based system. This is the most performant and extensible output. Only the components that are called upon are included, and they can be easily extended using mixins. But as noted earlier, not everyone wants to work this way (including Sass a dependency and potentially needing to set up a build system for it and learn a new syntax). There is also the user who just wants to throw a link onto their page and have it look nice, and thats where our versioned built assets come in. Option 2 With Option 2, users pull in links that are served via a CDN that contain JS, CSS, and our SVG icon library. The code is a bit bigger than the completely customized version, but often this isn’t the aim when people are using Option 2. Reducing friction for adoption should be a major goal of your design system rollout. Conclusion Having a design system is really beneficial to any product, especially as it grows. In order to have an effective system, it’s important to primarily always keep your user in mind and garner support from your entire company. Once you have support and acceptance, this system will flourish and grow. Make sure someone is responsible for it, and make sure its built with a solid foundation from the start which will be carefully maintained toward the future. Good luck, and happy holidays! 2017 Una Kravets unakravets 2017-12-14T00:00:00+00:00 https://24ways.org/2017/why-design-systems-fail/ process
317 Putting the World into "World Wide Web" Despite the fact that the Web has been international in scope from its inception, the predominant mass of Web sites are written in English or another left-to-right language. Sites are typically designed visually for Western culture, and rely on an enormous body of practices for usability, information architecture and interaction design that are by and large centric to the Western world. There are certainly many reasons this is true, but as more and more Web sites realize the benefits of bringing their products and services to diverse, global markets, the more demand there will be on Web designers and developers to understand how to put the World into World Wide Web. Internationalization According to the W3C, Internationalization is: “…the design and development of a product, application or document content that enables easy localization for target audiences that vary in culture, region, or language.” Many Web designers and developers have at least heard, if not read, about Internationalization. We understand that the Web is in fact worldwide, but many of us never have the opportunity to work with Internationalization. Or, when we do, think of it in purely technical terms, such as “which character set do I use?” At first glance, it might seem to many that Internationalization is the act of making Web sites available to international audiences. And while that is in fact true, this isn’t done by broad-stroking techniques and technologies. Instead, it involves a far more narrow understanding of geographical, cultural and linguistic differences in specific areas of the world. This is referred to as localization and is the act of making a Web site make sense in the context of the region, culture and language(s) the people using the site are most familiar with. Internationalization itself includes the following technical tasks: Ensuring no barrier exists to the localization of sites. Of critical importance in the planning stages of a site for Internationalized audiences, the role of the developer is to ensure that no barrier exists. This means being able to perform such tasks as enabling Unicode and making sure legacy character encodings are properly handled. Preparing markup and CSS with Internationalization in mind. The earlier in the site development process this occurs, the better. Issues such as ensuring that you can support bidirectional text, identifying language, and using CSS to support non-Latin typographic features. Enabling code to support local, regional, language or culturally related references. Examples in this category would include time/date formats, localization of calendars, numbering systems, sorting of lists and managing international forms of addresses. Empowering the user. Sites must be architected so the user can easily choose or implement the localized alternative most appropriate to them. Localization According to the W3C, Localization is the: …adaptation of a product, application or document content to meet the language, cultural and other requirements of a specific target market (a “locale”). So here’s where we get down to thinking about the more sociological and anthropological concerns. Some of the primary localization issues are: Numeric formats. Different languages and cultures use numbering systems unlike ours. So, any time we need to use numbers, such as in an ordered list, we have to have a means of representing the accurate numbering system for the locale in question. Money, honey! That’s right. I’ve got a pocketful of ugly U.S. dollars (why is U.S. money so unimaginative?). But I also have a drawer full of Japanese Yen, Australian Dollars, and Great British Pounds. Currency, how it’s calculated and how it’s represented is always a consideration when dealing with localization. Using symbols, icons and colors properly. Using certain symbols or icons on sites where they might offend or confuse is certainly not in the best interest of a site that wants to sell or promote a product, service or information type. Moreover, the colors we use are surprisingly persuasive – or detrimental. Think about colors that represent death, for example. In many parts of Asia, white is the color of death. In most of the Western world, black represents death. For Catholic Europe, shades of purple (especially lavender) have represented Christ on the cross and mourning since at least Victorian times. When Walt Disney World Europe launched an ad campaign using a lot of purple and very glitzy imagery, millions of dollars were lost as a result of this seeming subtle issue. Instead of experiencing joy and celebration at the ads, the European audience, particularly the French, found the marketing to be overly American, aggressive, depressing and basically unappealing. Along with this and other cultural blunders, Disney Europe has become a well-known case study for businesses wishing to become international. By failing to understand localization differences, and how powerful color and imagery act on the human psyche, designers and developers are put to more of a disadvantage when attempting to communicate with a given culture. Choosing appropriate references to objects and ideas. What seems perfectly natural in one culture in terms of visual objects and ideas can get confused in another environment. One of my favorite cases of this has to do with Gerber baby food. In the U.S., the baby food is marketed using a cute baby on the package. Most people in the U.S. culturally do not make an immediate association that what is being represented on the label is what is inside the container. However, when Gerber expanded to Africa, where many people don’t read, and where visual associations are less abstract, people made the inference that a baby on the cover of a jar of food represented what is in fact in the jar. You can imagine how confused and even angry people became. Using such approaches as a marketing ploy in the wrong locale can and will render the marketing a failure. As you can see, the act of localization is one that can have profound impact on the success of a business or organization as it seeks to become available to more and more people across the globe. Rethinking Design in the Context of Culture While well-educated designers and those individuals working specifically for companies that do a lot of localization understand these nuances, most of us don’t get exposed to these ideas. Yet, we begin to see how necessary it becomes to have an awareness of not just the technical aspects of Internationalization, but the socio-cultural ones within localization. What’s more, the bulk of information we have when it comes to designing sites typically comes from studies and work done on sites built in English and promoted to Western culture at large. We’re making a critical mistake by not including diverse languages and cultural issues within our usability and information architecture studies. Consider the following design from the BBC: In this case, we’re dealing with English, which is read left to right. We are also dealing with U.K. cultural norms. Notice the following: Location of of navigation Use of the color red Use of diverse symbols Mix of symbols, icons and photos Location of Search Now look at this design, which is the Arabic version of the BBC News, read right to left, and dealing with cultural norms within the Arabic-speaking world. Notice the following: Location of of navigation (location switches to the right) Use of the color blue (blue is considered the “safest” global color) No use of symbols and icons whatsoever Limitation of imagery to photos In most cases, the photos show people, not objects Location of Search Admittedly, some choices here are more obvious than others in terms of why they were made. But one thing that stands out is that the placement of search is the same for both versions. Is this the result of a specific localization decision, or based on what we believe about usability at large? This is exactly the kind of question that designers working on localization have to seek answers to, instead of relying on popular best practices and belief systems that exist for English-only Web sites. It’s a Wide World Web After All From this brief article on Internationalization, it becomes apparent that the art and science of creating sites for global audiences requires a lot more preparation and planning than one might think at first glance. Developers and designers not working to address these issues specifically due to time or awareness will do well to at least understand the basic process of making sites more culturally savvy, and better prepared for any future global expansion. One thing is certain: We not only are on a dramatic learning curve for designing and developing Web sites as it is, the need to localize sites is going to become more and more a part of the day to day work. Understanding aspects of what makes a site international and local will not only help you expand your skill set and make you more marketable, but it will also expand your understanding of the world and the people within it, how they relate to and use the Web, and how you can help make their experience the best one possible. 2005 Molly Holzschlag mollyholzschlag 2005-12-09T00:00:00+00:00 https://24ways.org/2005/putting-the-world-into-world-wide-web/ ux
107 Using Google App Engine as Your Own Content Delivery Network 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’t 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’t have his own slightly surreal-sounding TLD. And so it will be in the future when people realise with surprise there was a time before affordable content delivery networks. A 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 — Google, Yahoo, Amazon, et al — use CDNs for their sites, but they’ve always been far too expensive for us mere mortals. Until now. There’s a service out there ready for you to use as your very own CDN. You have the company’s blessing, you won’t need to write a line of code, and — best of all — it’s free. The name? Google App Engine. In this article you’ll find out how to set up a CDN on Google App Engine. You’ll 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. Creating your first Google App Engine project Before we do anything else, you’ll need to download the Google App Engine software development kit (SDK). You’ll need Python 2.5 too — you won’t be writing any Python code but the App Engine SDK will need it to run on your computer. If you don’t have Python, App Engine will install it for you (if you use Mac OS X 10.5 or a Linux-based OS you’ll have Python; if you use Windows you won’t). Done that? Excellent, because that’s the hardest step. The rest is plain sailing. You’ll need to choose a unique ‘application id’ — nothing more than a name — for your project. Make sure it consists only of lowercase letters and numbers. For this article I’ll use 24ways2008, but you can choose anything you like. On 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’ll fill with files and serve from your content delivery network. You can have other folders too, if you like. That will leave you with a folder structure like this: 24ways2008/ assets/ css/ images/ javascript/ Now 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’ll include an HTML file, a style sheet, an image, and a Javascript library. In the top-level folder (the one I’ve 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 — I’ve used the silver badge from the App Engine download page. Finally, to fill the JavaScript folder, add in this jQuery library file. If you’ve got the time and the inclination, you can build a page that uses all these elements. So now we should have a set of files and folders that look something like this: 24ways2008/ assets/ index.html css/ core.css images/ appengine-silver-120x30.gif javascript/ jquery-1.2.6.min.js Which leaves us with one last file to create. This is the important one: it tells App Engine what to do with your files. It’s named app.yaml, it sits at the top-level (inside the folder I’ve named 24ways2008), and it needs to include these lines: application: 24ways2008 version: 1 runtime: python api_version: 1 handlers: - url: / static_files: assets/index.html upload: assets/index.html - url: / static_dir: assets You 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’ve created your first App Engine project. If you want it, you can download a zip file containing my project. Testing your project As it stands, your project is ready to be uploaded to App Engine. But we couldn’t call ourselves professionals if we didn’t test it, could we? So, let’s put that downloaded SDK to good use and run the project from your own computer. One of the files you’ll find App Engine installed is named dev_appserver.py, a Python script used to simulate App Engine on your computer. You’ll 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): dev_appserver.py . You’ll 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 ‘Run…’, type ‘cmd‘, and click ‘OK’). Before you run the script you’ll need to make sure you’re in the project folder — in my case, as I saved it to my desktop I can go there by typing cd ~/Desktop/24ways2008 in my Mac’s Terminal app; if you’re using Windows you can type cd "C:\Documents and Settings\username\Desktop\24ways2008" If that’s successful, you’ll see a few lines of output, the last looking something like this: INFO 2008-11-22 14:35:00,830 dev_appserver_main.py] Running application 24ways2008 on port 8080: http://localhost:8080 Now you can power up your favourite browser, point it to http://localhost:8080/, and you’ll see the page you saved as index.html. You’ll 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’re running our own App Engine web server! Note that no-one else will be able to see your files: localhost is a special domain that you can only see from your computer — and once you stop the development server (by pressing Control–C) you’ll not be able to see the files in your browser until you start it again. You 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’s 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’re using version control (e.g. Subversion) there’s no need to keep a copy in your repository. So you’ve tested your project and you’ve 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. Uploading your project If you don’t have a Google account, create one and then sign in to App Engine. Tell Google about your new project by clicking on the ‘Create an Application’ button. Enter your application id, give the application a name, and agree to the terms and conditions. That’s it. All we need do now is upload the files. Open 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): appcfg.py update . Enter your email address and password when prompted, and let App Engine do it’s thing. It’ll 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’s 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’s content delivery network, at no cost to you! Benefits of using Google App Engine The benefits of App Engine as a CDN are obvious: your own server doesn’t suck up the bandwidth, while your visitors will appreciate a faster site. But there are also less obvious benefits. First, once you’ve 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’t make that claim, but with App Engine, you can. App 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 — 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’s made updates, and when. Another 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: version: 1 If 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’s no proper version control system, but it could get you out of a sticky situation. One last thing to note: if you’re not happy using your-application-id.appspot.com as your domain, App Engine will quite happily use any domain you own. The weak points of Google App Engine In the right circumstances, App Engine can be a real boon. I run my own site using the method I’ve discussed above, and I’m very happy with it. But App Engine does have its disadvantages, most notably those discussed by Aral Balkan in his post ‘Why Google App Engine is broken and what Google must do to fix it‘. Aral found the biggest problems while using App Engine as a web application platform; I wouldn’t recommend using it as such either (at least for now) but for our purposes as a CDN for static files, it’s much more worthy. Still, App Engine has two shortcomings you should be aware of. The first is that you can’t 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’re out of luck. The only solution is to stick to smaller files. The second problem is the quota system. Google’s own documentation says you’re 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 — in some cases after inexplicable jumps in Google’s server CPU usage. Aral, who’s 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’t want to worry about uptime, App Engine isn’t for you. That said, for most of us, App Engine offers a fantastic resource: the ability to host files on Google’s own content delivery network, at no charge. Conclusion If you’ve come this far, you’ve seen how to create a Google App Engine project and host your own files on Google’s CDN. You’ve seen the great advantages App Engine offers — 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 — and you’ve come across some of its weaknesses — most importantly the limit on file sizes and the quota system. All that’s left to do is upload those applications — but not before you’ve finished your Christmas shopping. 2008 Matt Riggott mattriggott 2008-12-06T00:00:00+00:00 https://24ways.org/2008/using-google-app-engine-as-your-own-cdn/ process
226 Documentation-Driven Design for APIs Documentation is like gift wrapping. It seems like superfluous fluff, but your family tends to be rather disappointed when their presents arrive in supermarket carrier bags, so you have to feign some sort of attempt at making your gift look enticing. Documentation doesn’t have to be all hard work and sellotaping yourself to a table – you can make it useful and relevant. Documentation gets a pretty rough deal. It tends to get left until the end of a project, when some poor developer is assigned the ‘document project’ ticket and wades through each feature of Whizzy New API 3.0 and needs to recall exactly what each method is meant to do. That’s assuming any time is left for documentation at all. The more common outcome resembles last minute homework scribbled on a post-it note, where just the bare bones of what’s available are put out for your users, and you hope that you’ll spot the inconsistencies and mistakes before they do. Wouldn’t it be nicer for everyone if you could make documentation not only outstanding for your users, but also a valuable tool for your development team – so much so that you couldn’t imagine writing a line of code before you’d documented it? Documentation needs to have three main features: It should have total coverage and document all the features of your project. Private methods should be documented for your developers, and public features need to be available to your users. It should be consistent – a user should know what to expect from your documentation, and terminology should be accurate to your language. It should be current – and that means staying accurate as new versions of your code base are released. But you can also get these bonuses: Act as a suggested specification – a guide that will aid a developer in making something consistent and usable. It can test your API quality. It can enhance the communication skills within your development team. So how do we get our documentation to be rich and full of features, instead of a little worn out like Boxing Day leftovers? Write your documentation first When I say first, I mean first. Not after you’ve started writing the code. Not even after you’ve started writing your unit tests. First. You may or may not have been provided with a decent specification, but the first job should be to turn your requirements for a feature into documentation. It works best when it takes the form of in-code comments. It works even better when your in-code comments take a standard documentation format that you can later use to generate published documentation for your users. This has the benefit of immediately making your docs as version controlled as your code-base, and it saves having to rewrite, copy or otherwise harass your docs into something legible later on. Almost all languages have a self-documentation format these days. My choice of format for JavaScript is JSDocToolkit, and the sort of things I look for are the ability to specify private and public methods, full options object statements (opts as Opts only is a no-no), and the ability to include good examples. So, our example for today will be a new festive feature for a JavaScript API. We’ve been asked to specify a sled for Santa to get around the world to give out toys: Santa needs to be able to travel around the world in one night to deliver toys to children, and he’ll need some reindeer to pull his sled. As documentation, it would look like: /** @name Sled @extends Vehicle @constructor @description Create a new sled to send Santa around the world to deliver toys to good kids. @param {Object} [opts] Options @param {number} [opts.capacity='50'] Set the capacity of the sled @param {string} [opts.pilot='santa'] The pilot of the sled. @example // Create a sled and specify some reindeer. new Sled().reindeer(['Dasher', 'Dancer', 'Prancer', 'Vixen', 'Comet', 'Cupid']); */ By breaking it down as documentation, you can, for example, hand this over to another developer without the need to explain the feature in much depth, and they’ll develop something that has to match this piece of documentation. It specifies everything that is important to this feature – its default values and types, and where it inherits other features from. We know that we need to specify some way of setting reindeer to pull the sled and also some toys to give, and so we can quickly specify extra methods for the sled: /* @name vehicle.Sled#reindeer @function @description Set the reindeer that will pull Santa's sled. @param {string[]} reindeer A list of the reindeer. @example // specifying some reindeer Sled().reindeer(['Dasher', 'Dancer', 'Rudolph', 'Vixen']); */ /* @name vehicle.Sled#toys @function @description Add a list of toys and recipients to the Sled. @param {Object[]} toys A list of toys and who will receive them. @example // Adding toys to the sled Sled().toys([ {name:'Brian', toy:'Fire Engine'}, {name:'Drew', toy:'Roller-skates'}, {name:'Anna', toy:'Play-doh'}, ... ]); */ Job done! You’ve got a specification to share with your team and something useful for your users in the form of full examples, and you didn’t even have to open another text editor. Use your documentation to share knowledge Documentation isn’t just for users. It’s also used by internal developers to explain what they’ve written and how it works. This is especially valuable where the team is large or the code-base sprawling. So, returning to our example, the next step would be to share with the rest of the team (or at least a selection of the team if yours is large) what the documentation looks like. This is useful for two main reasons: They can see if they understand what the documentation says the feature will do. It’s best if they haven’t seen the requirement before. If your fellow developers can’t work out what ‘MagicMethodX’ is going to return from the docs, neither can your users. They can check that the feature accomplishes everything that they expect to, and that it’s consistent with the rest of the functionality. On previous projects, we’ve taken to referring to this stage of the development process as the ‘bun fight’. It’s a chance for everyone to have an honest say and throw a few pies without actually causing anyone to have to rewrite any code. If you can identify at this stage that a feature is over-complicated, lacking or just plain useless, you’ll all be much happier to throw out a few lines of documentation than you may have been to throw out a partial, or even complete, piece of functionality. Documentation has your back The final benefit to working in this way is that your documentation not only remains accurate, it’s always as accurate as your latest release. It can’t fall behind. You can increase the likelihood that your docs will remain up to date by unit testing your examples. Returning to the previous example, we can add a QUnit unit test to the expected output with ease during the build process – we know exactly how the code will look and, with the @example tag, we can identify easily where to find the bits that need testing. If it’s tested it’ll definitely work as you expect it to when a user copy and pastes it. You’re ensuring quality from idea to implementation. As an extra bauble, the best thing about a system like JSDocToolkit is that it’ll take your inline comments and turn them into beautiful sites, as good systems will allow for customised output templates. You’ll be producing full-featured sites for your projects and plugins with almost no extra effort, but all the benefits. 2010 Frances Berriman francesberriman 2010-12-11T00:00:00+00:00 https://24ways.org/2010/documentation-driven-design-for-apis/ process
313 Centered Tabs with CSS Doug Bowman’s Sliding Doors is pretty much the de facto way to build tabbed navigation with CSS, and rightfully so – it is, as they say, rockin’ like Dokken. But since it relies heavily on floats for the positioning of its tabs, we’re constrained to either left- or right-hand navigation. But what if we need a bit more flexibility? What if we need to place our navigation in the center? Styling the li as a floated block does give us a great deal of control over margin, padding, and other presentational styles. However, we should learn to love the inline box – with it, we can create a flexible, centered alternative to floated navigation lists. Humble Beginnings Do an extra shot of ‘nog, because you know what’s coming next. That’s right, a simple unordered list: <div id="navigation"> <ul> <li><a href="#"><span>Home</span></a></li> <li><a href="#"><span>About</span></a></li> <li><a href="#"><span>Our Work</span></a></li> <li><a href="#"><span>Products</span></a></li> <li class="last"><a href="#"><span>Contact Us</span></a></li> </ul> </div> If we were wedded to using floats to style our list, we could easily fix the width of our ul, and trick it out with some margin: 0 auto; love to center it accordingly. But this wouldn’t net us much flexibility: if we ever changed the number of navigation items, or if the user increased her browser’s font size, our design could easily break. Instead of worrying about floats, let’s take the most basic approach possible: let’s turn our list items into inline elements, and simply use text-align to center them within the ul: #navigation ul, #navigation ul li { list-style: none; margin: 0; padding: 0; } #navigation ul { text-align: center; } #navigation ul li { display: inline; margin-right: .75em; } #navigation ul li.last { margin-right: 0; } Our first step is sexy, no? Well, okay, not really – but it gives us a good starting point. We’ve tamed our list by removing its default styles, set the list items to display: inline, and centered the lot. Adding a background color to the links shows us exactly how the different elements are positioned. Now the fun stuff. Inline Elements, Padding, and You So how do we give our links some dimensions? Well, as the CSS specification tells us, the height property isn’t an option for inline elements such as our anchors. However, what if we add some padding to them? #navigation li a { padding: 5px 1em; } I just love leading questions. Things are looking good, but something’s amiss: as you can see, the padded anchors seem to be escaping their containing list. Thankfully, it’s easy to get things back in line. Our anchors have 5 pixels of padding on their top and bottom edges, right? Well, by applying the same vertical padding to the list, our list will finally “contain” its child elements once again. ’Tis the Season for Tabbing Now, we’re finally able to follow the “Sliding Doors” model, and tack on some graphics: #navigation ul li a { background: url("tab-right.gif") no-repeat 100% 0; color: #06C; padding: 5px 0; text-decoration: none; } #navigation ul li a span { background: url("tab-left.gif") no-repeat; padding: 5px 1em; } #navigation ul li a:hover span { color: #69C; text-decoration: underline; } Finally, our navigation’s looking appropriately sexy. By placing an equal amount of padding on the top and bottom of the ul, our tabs are properly “contained”, and we can subsequently style the links within them. But what if we want them to bleed over the bottom-most border? Easy: we can simply decrease the bottom padding on the list by one pixel, like so. A Special Note for Special Browsers The Mac IE5 users in the audience are likely hopping up and down by now: as they’ve discovered, our centered navigation behaves rather annoyingly in their browser. As Philippe Wittenbergh has reported, Mac IE5 is known to create “phantom links” in a block-level element when text-align is set to any value but the default value of left. Thankfully, Philippe has documented a workaround that gets that [censored] venerable browser to behave. Simply place the following code into your CSS, and the links will be restored to their appropriate width: /**//*/ #navigation ul li a { display: inline-block; white-space: nowrap; width: 1px; } /**/ IE for Windows, however, displays an extra kind of crazy. The padding I’ve placed on my anchors is offsetting the spans that contain the left curve of my tabs; thankfully, these shenanigans are easily straightened out: /**/ * html #navigation ul li a { padding: 0; } /**/ And with that, we’re finally finished. All set. And that’s it. With your centered navigation in hand, you can finally enjoy those holiday toddies and uncomfortable conversations with your skeevy Uncle Eustace. 2005 Ethan Marcotte ethanmarcotte 2005-12-08T00:00:00+00:00 https://24ways.org/2005/centered-tabs-with-css/ code
112 User Styling During the recent US elections, Twitter decided to add an ‘election bar’ as part of their site design. You could close it if it annoyed you, but the action wasn’t persistent and the bar would always come back like a bad penny. The solution to common browsing problems like this is CSS. ‘User styling’ (or the creepy ‘skinning’) is the creation of CSS rules to customise and personalise a particular domain. Aside from hiding adverts and other annoyances, there are many reasons for taking the time and effort to do it: Improving personal readability by changing text size and colour Personalising the look of a web app like GMail to look less insipid Revealing microformats Sport! My dreams of site skinning tennis are not yet fully realised, but it’ll be all the rage by next Christmas, believe me. Hopefully you’re now asking “But how? HOW?!”. The process of creating a site skin is roughly as follows: See something you want to change Find out what it’s called, and if any rules already apply to it Write CSS rule(s) to override and/or enhance it. Apply the rules So let’s get stuck in… See something Let’s start small with Multimap.com. Look at that big header – it takes up an awful lot of screen space doesn’t it? No matter, we can fix it. Tools Now we need to find out where that big assed header is in the DOM, and make overriding CSS rules. The best tool I’ve found yet is the Mac OS X app, CSS Edit. It utilises a slick ‘override stylesheets’ function and DOM Inspector. Rather than give you all the usual DOM inspection tools, CSS Edit’s is solely concerned with style. Go into ‘X-Ray’ mode, click an element, and look at the inspector window to see every style rule governing it. Click the selector to be taken to where it lives in the CSS. It really is a user styling dream app. Having said all that, you can achieve all this with free, cross platform tools – namely Firefox with the Firebug and Stylish extensions. We’ll be using them for these examples, so make sure you have them installed if you want to follow along. Using Firebug, we can see that the page is very helpfully marked up, and that whole top area is simply a div with an ID of header. Change Something When you installed Stylish, it added a page and brush icon to your status bar. Click on that, and choose Write Style > for Multimap.com. The other options allow you to only create a style for a particular part of a website or URL, but we want this to apply to the whole of Multimap: The ‘Add Style’ window then pops up, with the @-moz-document query at the top: @namespace url(http://www.w3.org/1999/xhtml); @-moz-document domain("multimap.com") { } All you need to do is add the CSS to hide the header, in between the curly brackets. @namespace url(http://www.w3.org/1999/xhtml); @-moz-document domain("multimap.com") { #header {display: none;} } A click of the preview button shows us that it’s worked! Now the map appears further up the page. The ethics of hiding adverts is a discussion for another time, but let’s face it, when did you last whoop at the sight of a banner? Make Something Better If we’re happy with our modifications, all we need to do is give it a name and save. Whenever you visit Multimap.com, the style will be available. Stylish also allows you to toggle a style on/off via the status bar menu. If you feel you want to share this style with the world, then userstyles.org is the place to do it. It’s a grand repository of customisations that Stylish connects with. Whenever you visit a site, you can see if anyone else has written a style for it, again, via the status bar menu “Find Styles for this Page”. Selecting this with “BBC News” shows that there are plenty of options, ranging from small layout tweaks to redesigns: What’s more, whenever a style is updated, Stylish will notify you, and offer a one-click process to update it. This does only work in Firefox and Flock, so I’ll cover ways of applying site styles to other browsers later. Specific Techniques Important! In the Multimap example there wasn’t a display specified on that element, but it isn’t always going to be that easy. You may have spent most of your CSS life being a good designer and not resorting to adding !important to give your rule priority. There’s no way to avoid this in user styling – if you’re overriding an existing rule it’s a necessity! Be prepared to be typing !important a lot. Star Selector The Universal Selector is a particularly useful way to start a style. For example, if we want to make Flickr use Helvetica before Arial (as they should’ve done!), we can cover all occurrences with just one rule: * {font-family: "Helvetica Neue", Helvetica, sans-serif !important;} You can also use it to select ‘everything within an element’, by placing it after the element name: #content * {font-family: "Helvetica Neue", Helvetica, sans-serif !important;} Swapping Images If you’re changing something a little more complex, such as Google Reader, then at some point you’ll probably want to change an <img>. The technique for replacing an image involves: making your replacement image the background of the <img> tag adding padding top and left to the size of you image to push the ‘top’ image away making the height and width zero. The old image is then pushed out of the way and hidden from view, allowing the replacement in the background to be revealed. Targeting the image may require using an attribute selector: img[src="/reader/ui/3544433079-tree-view-folder-open.gif"] { padding: 16px 0 0 16px; width: 0 !important; height: 0 !important; background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYA AAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAA Bx0RVh0U29mdHdhcmUAQWRvYmUgRmlyZXdvcmtzIENTM5jWRgMAAAAVdE VYdENyZWF0aW9uIFRpbWUAMjkvNi8wOJJ/BVgAAAG3SURBVDiNpZIhb5RBEIaf 2W+vpIagIITSBIHBgsGjEYQaFLYShcITDL+ABIPnh4BFN0GQNFA4Cnf3fbszL2L3 jiuEVLDJbCazu8+8Mzsmif9ZBvDy7bvXlni0HRe8eXL/zuPzABng62J5kFKaAQS QgJAOgHMB9vDZq+d71689Hcyw9LfAZAYdioE10VSJo6OPL/KNvSuHD+7dhU 0vHEsDUUWJChIlYJIjFx5BuMB2mJY/DnMoOJl/R147oBUR0QAm8LAGCOEh3IO ULiAl8jSOy/nPetGsbGRKjktEiBCEHMlQj4loCuu4zCXCi4lUHTNDtGqEiACTqAFSI OgAUAKv4bkWVy2g6tAbJtGy0TNugM3HADmlurKH27dVZSecxjboXggiAsMItR h99wTILdewYRpXVJWtY85k7fPW8e1GpJFJacgesXs6VYYomz9G2yDhwPB7NEB BDAMK7WYJlisYVBCpfaJBeB+eocFyVyAgCaoMCTJSTOOCWSyILrAnaXpSexRsx GGAZ0AR+XT+5fjzyfwSpnUB/1w64xizVI/t6q3b+58+vJ96mWtLf9haxNoc8M v7N3d+AT4XPcFIxghoAAAAAElFTkSuQmCC) no-repeat !important; } Woah boy! What was all that gubbins in the background-image? It was a Data URI, and you can create these easily with Hixie’s online tool. It’s simply the image translated into text so that it can be embedded in the CSS, cutting down on the number of http requests. It’s also a necessity with Mozilla browsers, as they don’t allow user CSS to reference images stored locally. Converting images to URI’s avoids this, as well as making a style easily portable – no images folder to pass around. Don’t forget all your other CSS techniques at your disposal: inserting your own content with :before and :after pseudo classes, make elements semi-transparent with opacity and round box corners without hacking . You can have fun, and for once, enjoy the freedom of not worrying about IE! User styling without Stylish Instead of using the Stylish extension, you can add rules to the userContent.css file, or use @import in that file to load a separate stylesheet. You can find this is in /Library/Application Support/Camino/chrome/ on OS X, or C/Program Files/Mozilla Firefox/Chrome on Windows. This is only way to apply user styles in Camino, but what about other browsers? Opera & Omniweb: Both allow you to specify a custom CSS file as part of the site’s preferences. Opera also allows custom javascript, using the same syntax as Greasemonkey scripts (more on that below) Safari There are a few options here: the PithHelmet and SafariStand haxies both allow custom stylesheets, or alternatively, a Greasemonkey style user script can employed via GreaseKit. The latter is my favoured solution on my Helvetireader theme, as it can allow for more prescriptive domain rules, just like the Mozilla @-moz-document method. User scripts are also the solution supported by the widest range of browsers. What now? Hopefully I’ve given you enough information for you to be able start making your own styles. If you want to go straight in and tackle the ‘Holy Grail’, then off with you to GMail – I get more requests to theme that than anything else! If you’re a site author and want to encourage this sort of tom foolery, a good way is to provide a unique class or ID name with the body tag: <body id="journal" class="hicksdesign-co-uk"> This makes it very easy to write rules that only apply to that particular site. If you wanted to use Safari without any of the haxies mentioned above, this method means you can include rules in a general CSS file (chosen via Preferences > Advanced > Stylesheet) without affecting other sites. One final revelation on user styling – it’s not just for web sites. You can tweak the UI of Firefox itself with the userChrome.css. You’ll need to use the in-built DOM Inspector instead of Firebug to inspect the window chrome, instead of a page. Great if you want to make small tweaks (changing the size of tab text for example) without creating a full blown theme. 2008 Jon Hicks jonhicks 2008-12-03T00:00:00+00:00 https://24ways.org/2008/user-styling/ process
127 Showing Good Form Earlier this year, I forget exactly when (it’s been a good year), I was building a client site that needed widgets which look like this (designed, incidentally, by my erstwhile writing partner, Cameron Adams): Building this was a challenge not just in CSS, but in choosing the proper markup – how should such a widget be constructed? Mmm … markup It seemed to me there were two key issues to deal with: The function of the interface is to input information, so semantically this is a form, therefore we have to find a way of building it using form elements: fieldset, legend, label and input We can’t use a table for layout, even though that would clearly be the easiest solution! Abusing tables for layout is never good – physical layout is not what table semantics mean. But even if this data can be described as a table, we shouldn’t mix forms markup with non-forms markup, because of the behavioral impact this can have on a screen reader: To take a prominent example, the screen reader JAWS has a mode specifically for interacting with forms (cunningly known as “forms mode”). When running in this mode its output only includes relevant elements – legends, labels and form controls themselves. Any other kind of markup – like text in a previous table cell, a paragraph or list in between – is simply ignored. The user in this situation would have to switch continually in and out of forms mode to hear all the content. (For more about this issue and some test examples, there’s a thread at accessify forum which wanders in that direction.) One further issue for screen reader users is implied by the design: the input fields are associated together in rows and columns, and a sighted user can visually scan across and down to make those associations; but a blind user can’t do that. For such a user the row and column header data will need to be there at every axis; in other words, the layout should be more like this: And constructed with appropriate semantic markup to convey those relationships. By this point the selection of elements seems pretty clear: each row is a fieldset, the row header is a legend, and each column header is a label, associated with an input. Here’s what that form looks like with no CSS: And here’s some markup for the first row (with most of the attributes removed just to keep this example succinct): <fieldset> <legend> <span>Match points</span> </legend> <label> <span>Win</span> <input value="3" /> </label> <label> <span>Draw</span> <input value="1" /> </label> <label> <span>Lose</span> <input value="0" /> </label> <label> <span>Played</span> <input value="0" /> </label> </fieldset> The span inside each legend is because legend elements are highly resistant to styling! Indeed they’re one of the most stubborn elements in the browsers’ vocabulary. Oh man … how I wrestled with the buggers … until this obvious alternative occurred to me! So the legend element itself is just a container, while all the styling is on the inner span. Oh yeah, there was some CSS too I’m not gonna dwell too much on the CSS it took to make this work – this is a short article, and it’s all there in the demo [demo page, style sheet] But I do want to touch on the most interesting bit – where we get from a layout with headers on every row, to one where only the top row has headers – or at least, so it appears to graphical browsers. For screen readers, as we noted, we need those headers on every row, so we should employ some cunning CSS to partly negate their visual presence, without removing them from the output. The core styling for each label span is like this: label span { display:block; padding:5px; line-height:1em; background:#423221; color:#fff; font-weight:bold; } But in the rows below the header they have these additional rules: fieldset.body label span { padding:0 5px; line-height:0; position:relative; top:-10000em; } The rendered width of the element is preserved, ensuring that the surrounding label is still the same width as the one in the header row above, and hence a unified column width is preserved all the way down. But the element effectively has no height, and so it’s effectively invisible. The styling is done this way, rather than just setting the height to zero and using overflow:hidden, because to do that would expose an unrelated quirk with another popular screen reader! (It would hide the output from Window Eyes, as shown in this test example at access matters.) The finished widget It’s an intricate beast allright! But after all that we do indeed get the widget we want: Demo page Style sheet It’s not perfect, most notably because the legends have to have a fixed width; this can be in em to allow for text scaling, but it still doesn’t allow the content to break into multiple lines. It also doesn’t look quite right in Safari; and some CSS hacking was needed to make it look right in IE6 and IE7. Still it worked well enough for the purpose, and satisfied the client completely. And most of all it re-assured me in my faith – that there’s never any need to abuse tables for layout. (Unless of course you think this content is a table anyway, but that’s another story!) 2006 James Edwards jamesedwards 2006-12-11T00:00:00+00:00 https://24ways.org/2006/showing-good-form/ ux
330 An Explanation of Ems Ems are so-called because they are thought to approximate the size of an uppercase letter M (and so are pronounced emm), although 1em is actually significantly larger than this. The typographer Robert Bringhurst describes the em thus: The em is a sliding measure. One em is a distance equal to the type size. In 6 point type, an em is 6 points; in 12 point type an em is 12 points and in 60 point type an em is 60 points. Thus a one em space is proportionately the same in any size. To illustrate this principle in terms of CSS, consider these styles: #box1 { font-size: 12px; width: 1em; height: 1em; border:1px solid black; } #box2 { font-size: 60px; width: 1em; height: 1em; border: 1px solid black; } These styles will render like: M and M Note that both boxes have a height and width of 1em but because they have different font sizes, one box is bigger than the other. Box 1 has a font-size of 12px so its width and height is also 12px; similarly the text of box 2 is set to 60px and so its width and height are also 60px. 2005 Richard Rutter richardrutter 2005-12-02T00:00:00+00:00 https://24ways.org/2005/an-explanation-of-ems/ design
51 Blow Your Own Trumpet Even if your own trumpet’s tiny and fell out of a Christmas cracker, blowing it isn’t something that everyone’s good at. Some people find selling themselves and what they do difficult. But, you know what? Boo hoo hoo. If you want people to buy something, the reality is you’d better get good at selling, especially if that something is you. For web professionals, the best place to tell potential business customers or possible employers about what you do is on your own website. You can write what you want and how you want, but that doesn’t make knowing what to write any easier. As a matter of fact, writing for yourself often proves harder than writing for someone else. I spent this autumn thinking about what I wanted to say about Stuff & Nonsense on the website we relaunched recently. While I did that, I spoke to other designers about how they struggled to write about their businesses. If you struggle to write well, don’t worry. You’re not on your own. Here are five ways to hit the right notes when writing about yourself and your work. Be genuine about who you are I’ve known plenty of talented people who run a successful business pretty much single-handed. Somehow they still feel awkward presenting themselves as individuals. They wonder whether describing themselves as a company will give them extra credibility. They especially agonise over using “we” rather than “I” when describing what they do. These choices get harder when you’re a one-man band trading as a limited company or LLC business entity. If you mainly work alone, don’t describe yourself as anything other than “I”. You might think that saying “we” makes you appear larger and will give you a better chance of landing bigger and better work, but the moment a prospective client asks, “How many people are you?” you’ll have some uncomfortable explaining to do. This will distract them from talking about your work and derail your sales process. There’s no need to be anything other than genuine about how you describe yourself. You should be proud to say “I” because working alone isn’t something that many people have the ability, business acumen or talent to do. Explain what you actually do How many people do precisely the same job as you? Hundreds? Thousands? The same goes for companies. If yours is a design studio, development team or UX consultancy, there are countless others saying exactly what you’re saying about what you do. Simply stating that you code, design or – God help me – “handcraft digital experiences” isn’t enough to make your business sound different from everyone else. Anyone can and usually does say that, but people buy more than deliverables. They buy something that’s unique about you and your business. Potentially thousands of companies deliver code and designs the same way as Stuff & Nonsense, but our clients don’t just buy page designs, prototypes and websites from us. They buy our taste for typography, colour and layout, summed up by our “It’s the taste” tagline and bowler hat tip to the PG Tips chimps. We hope that potential clients will understand what’s unique about us. Think beyond your deliverables to what people actually buy, and sell the uniqueness of that. Describe work in progress It’s sad that current design trends have made it almost impossible to tell one website from another. So many designers now demonstrate finished responsive website designs by pasting them onto iMac, MacBook, iPad and iPhone screens that their portfolios don’t fare much better. Every designer brings their own experience, perspective and process to a project. In my experience, it’s understanding those differences which forms a big part of how a prospective client makes a decision about who to work with. Don’t simply show a prospective client the end result of a previous project; explain your process, the development of your thinking and even the wrong turns you took. Traditional case studies, like the one I’ve just written about Stuff & Nonsense’s work for WWF UK, can take a lot of time. That’s probably why many portfolios get out of date very quickly. Designers make new work all the time, so there must be a better way to show more of it more often, to give prospective clients a clearer understanding of what we do. At Stuff & Nonsense our solution was to create a feed where we could post fragments of design work throughout a project. This also meant rewriting our Contract Killer to give us permission to publish work before someone signs it off. Outline a client’s experience Recently a client took me to one side and offered some valuable advice. She told me that our website hadn’t described anything about the experience she’d had while working with us. She said that knowing more about how we work would’ve helped her make her buying decision. When a client chooses your business, they’re hoping for more than a successful outcome. They want their project to run smoothly. They want to feel that they made a correct decision when they chose you. If they work for an organisation, they’ll want their good judgement to be recognised too. Our client didn’t recognise her experience because we hadn’t made our own website part of it. Remember, the challenge of creating a memorable user experience starts with selling to the people paying you for it. Address your ideal client It’s important to understand that a portfolio’s job isn’t to document your work, it’s to attract new work from clients you want. Make sure that work you show reflects the work you want, because what you include in your portfolio often leads to more of the same. When you’re writing for your portfolio and elsewhere on your website, imagine that you’re addressing your ideal client. Picture them sitting opposite and answer the questions they’d ask as you would in conversation. Be direct, funny if that’s appropriate and serious when it’s not. If it helps, ask a friend to read the questions aloud and record what you say in response. This will help make what you write sound natural. I’ve found this technique helps clients write copy too. Toot your own horn Some people confuse expressing confidence in yourself and your work as boastfulness, but in a competitive world the reality is that if you are to succeed, you need to show confidence so that others can show their confidence in you. If you want people to hear you, pick up your trumpet and blow it. 2015 Andy Clarke andyclarke 2015-12-23T00:00:00+00:00 https://24ways.org/2015/blow-your-own-trumpet/ business
62 Being Customer Supportive Every day in customer support is an inbox, a Twitter feed, or a software forum full of new questions. Each is brimming with your customers looking for advice, reassurance, or fixes for their software problems. Each one is an opportunity to take a break from wrestling with your own troublesome tasks and assist someone else in solving theirs. Sometimes the questions are straightforward and can be answered in a few minutes with a short greeting, a link to a help page, or a prewritten bit of text you use regularly: how to print a receipt, reset a password, or even, sadly, close your account. More often, a support email requires you to spend some time unpacking the question, asking for more information, and writing a detailed personal response, tailored to help that particular user on this particular day. Here I offer a few of my own guidelines on how to make today’s email the best support experience for both me and my customer. And even if you don’t consider what you do to be customer support, you might still find the suggestions useful for the next time you need to communicate with a client, to solve a software problem with teammates, or even reach out and ask for help yourself. (All the examples appearing in this article are fictional. Any resemblance to quotes from real, software-using persons is entirely coincidental. Except for the bit about Star Wars. That happened.) Who’s TAHT girl I’ll be honest: I briefly tried making these recommendations into a clever mnemonic like FAST (facial drooping, arm weakness, speech difficulties, time) or PAD (pressure, antiseptic, dressing). But instead, you get TAHT: tone, ask, help, thank. Ah, well. As I work through each message in my support queue, I listen to the tone of the email ask clarifying questions bring in extra help as needed and thank the customer when the problem is solved. Let’s open an email and get started! Leave your message at the sound of the tone With our enthusiasm for emoji, it can be very hard to infer someone’s tone from plain text. How much time have you spent pondering why your friend responded with “Thanks.” instead of “Thanks!”? I mean, why didn’t she :grin: or :wink: too? Our support customers, however, are often direct about how they’re feeling: I’m working against a deadline. Need this fixed ASAP!!!! This hasn’t worked in a week and I am getting really frustrated. I’ve done this ten times before and it’s always worked. I must be missing something simple. They want us to understand the urgency of this from their point of view, just as much as we want to help them in a timely manner. How this information is conveyed gives us an instant sense of whether they are frustrated, angry, or confused—and, just as importantly, how frustrated-angry-confused they are. Listen to this tone before you start writing your reply. Here are two ways I might open an email: “I’m sorry that you ran into trouble with this.” “Sorry you ran into trouble with this!” The content is largely the same, but the tone is markedly different. The first version is a serious, staid reaction to the problem the customer is having; the second version is more relaxed, but no less sincere. Matching the tone to the sender’s is an important first step. Overusing exclamation points or dropping in too-casual language may further upset someone who is already having a crummy time with your product. But to a cheerful user, a formal reply or an impersonal form response can be off-putting, and damage a good relationship. When in doubt, I err on the side of being too formal, rather than sending a reply that may be read as flip or insincere. But whichever you choose, matching your correspondent’s tone will make for a more comfortable conversation. Catch the ball and throw it back Once you’ve got that tone on lock, it’s time to tackle the question at hand. Let’s see what our customer needs help with today: I tried everything in the troubleshooting page but I can’t get it to work again. I am on a Mac. Please help. Hmm, not much information here. Now, if I got this short email after helping five other people with the same problem on Mac OS X, I would be sorely tempted to send this customer that common solution in my first reply. I’ve found it’s important to resist the urge to assume this sixth person needs the same answer as the other five, though: there isn’t enough to connect this email to the ones that came before hers. Instead, ask a few questions to start. Invest some time to see if there are other symptoms in common, like so: I’m sorry that you ran into trouble with this! I’ll need a little more information to see what’s happening here. [questions] Thank you for your help. Those questions are customized for the customer’s issue as much as possible, and can be fairly wide-ranging. They may include asking for log files, getting some screenshots, or simply checking the browser and operating system version she’s using. I’ll ask anything that might make a connection to the previous cases I’ve answered—or, just as importantly, confirm that there isn’t a connection. What’s more, a few well-placed questions may save us both from pursuing the wrong path and building additional frustration. (A note on that closing: “Thank you for your help”–I often end an email this way when I’ve asked for a significant amount of follow up information. After all, I’m imposing on my customer’s time to run any number of tests. It’s a necessary step, but I feel that thanking them is a nice acknowledgment we’re in this together.) Having said that, though, let’s bring tone back into the mix: I tried everything in the troubleshooting but I can’t get it to work again. I am on a Mac. I’m working against a deadline. Need this fixed ASAP!!!! This customer wants answers now. I’ll still ask for more details, but would consider including the solution to the previous problem in my initial reply as well. (But only if doing so can’t make the situation worse!) I’m sorry that you ran into trouble with this! I’ll need a little more information to see what’s happening here. [questions] If you’d like to try something in the meantime, delete the file named xyz.txt. (If this isn’t the cause of the problem, deleting the file won’t hurt anything.) Here’s how to find that file on your computer: [steps] Let me know how it goes! In the best case, the suggestion works and the customer is on her way. If it doesn’t solve the problem, you will get more information in answer to your questions and can explore other options. And you’ve given the customer an opportunity to be involved in fixing the issue, and some new tools which might come in handy again in the future. Bring in help The support software I use counts how many emails the customer and I have exchanged, and reports it in a summary line in my inbox. It’s an easy, passive reminder of how long the customer and I have been working together on a problem, especially first thing in the morning when I’m reacquainting myself with my open support cases. Three is the smallest number I’ll see there: the customer sends the initial question (1 email); I reply with an answer (2 emails); the customer confirms the problem is solved (3 emails). But the most complicated, stickiest tickets climb into double-digit replies, and anything that stretches beyond a dozen is worthy of a cheer in Slack when we finally get to the root of the problem and get it fixed. While an extra round of questions and answers will nudge that number higher, it gives me the chance to feel out the technical comfort level of the person I’m helping. If I ask the customer to send some screenshots or log files and he isn’t sure how to do that, I will use that information to adjust my instructions on next steps. I may still ask him to try running a traceroute on his computer, but I’ll break down the steps into a concise, numbered list, and attach screenshots of each step to illustrate it. If the issue at hand is getting complicated, take note if the customer starts to feel out of their depth technically—either because they tell you so directly or because you sense a shift in tone. If that happens, propose bringing some outside help into the conversation: Do you have a network firewall or do you use any antivirus software? One of those might be blocking a connection that the software needs to work properly; here’s a list of the required connections [link]. If you have an IT department in-house, they should be able to help confirm that none of those are being blocked. or: This error message means you don’t have permission to install the software on your own computer. Is there a systems administrator in the office that may be able to help with this? For email-based support cases, I’ll even offer to add someone from their IT department to the thread, so we can discuss the problem together rather than have the customer relay questions and answers back and forth. Similarly, there are occasionally times when my way of describing things doesn’t fit how the customer understands them. Rather than bang our heads against our keyboards, I will ask one of my support colleagues to join the conversation from our side, and see if he can explain things more clearly than I’ve been able to do. We appreciate your business. Please call again And then, o frabjous day, you get your reward: the reply which says the problem has been solved. That worked!! Thank you so much for saving my day! I wish I could send you some cookies! If you were here, I would give you my tickets to Star Wars. [Reply is an animated gif.] Sometimes the reply is a bit more understated: That fixed it. Thanks. Whether the customer is elated, satisfied, or frankly happy to be done with emailing support, I like to close longer email threads or short, complicated issues with a final thanks and reminder that we’re here to help: Thank you for the update; I’m glad to hear that solved the problem for you! I hope everything goes smoothly for you now, but feel free to email us again if you run into any other questions or problems. Best, Then mark that support case closed, and move on to the next question. Because even with the most thoughtfully designed software product, there will always be customers with questions for your capable support team to answer. Tone, ask, help, thank So there you have it: TAHT. Pay attention to tone; ask questions; bring in help; thank your customer. (Lack of) catchy mnemonics aside, good customer support is about listening, paying attention, and taking care in your replies. I think it can be summed up beautifully by this quote from Pamela Marie (as tweeted by Chris Coyier): Golden rule asking a question: imagine trying to answer it Golden rule in answering: imagine getting your answer You and your teammates are applying a variation of this golden rule in every email you write. You’re the software ambassadors to your customers and clients. You get the brunt of the problems and complaints, but you also get to help fix them. You write the apologies, but you also have the chance to make each person’s experience with your company or product a little bit better for next time. I hope that your holidays are merry and bright, and may all your support inboxes be light. 2015 Elizabeth Galle elizabethgalle 2015-12-02T00:00:00+00:00 https://24ways.org/2015/being-customer-supportive/ process
249 Fast Autocomplete Search for Your Website Every website deserves a great search engine - but building a search engine can be a lot of work, and hosting it can quickly get expensive. I’m going to build a search engine for 24 ways that’s fast enough to support autocomplete (a.k.a. typeahead) search queries and can be hosted for free. I’ll be using wget, Python, SQLite, Jupyter, sqlite-utils and my open source Datasette tool to build the API backend, and a few dozen lines of modern vanilla JavaScript to build the interface. Try it out here, then read on to see how I built it. First step: crawling the data The first step in building a search engine is to grab a copy of the data that you plan to make searchable. There are plenty of potential ways to do this: you might be able to pull it directly from a database, or extract it using an API. If you don’t have access to the raw data, you can imitate Google and write a crawler to extract the data that you need. I’m going to do exactly that against 24 ways: I’ll build a simple crawler using wget, a command-line tool that features a powerful “recursive” mode that’s ideal for scraping websites. We’ll start at the https://24ways.org/archives/ page, which links to an archived index for every year that 24 ways has been running. Then we’ll tell wget to recursively crawl the website, using the --recursive flag. We don’t want to fetch every single page on the site - we’re only interested in the actual articles. Luckily, 24 ways has nicely designed URLs, so we can tell wget that we only care about pages that start with one of the years it has been running, using the -I argument like this: -I /2005,/2006,/2007,/2008,/2009,/2010,/2011,/2012,/2013,/2014,/2015,/2016,/2017 We want to be polite, so let’s wait for 2 seconds between each request rather than hammering the site as fast as we can: --wait 2 The first time I ran this, I accidentally downloaded the comments pages as well. We don’t want those, so let’s exclude them from the crawl using -X "/*/*/comments". Finally, it’s useful to be able to run the command multiple times without downloading pages that we have already fetched. We can use the --no-clobber option for this. Tie all of those options together and we get this command: wget --recursive --wait 2 --no-clobber -I /2005,/2006,/2007,/2008,/2009,/2010,/2011,/2012,/2013,/2014,/2015,/2016,/2017 -X "/*/*/comments" https://24ways.org/archives/ If you leave this running for a few minutes, you’ll end up with a folder structure something like this: $ find 24ways.org 24ways.org 24ways.org/2013 24ways.org/2013/why-bother-with-accessibility 24ways.org/2013/why-bother-with-accessibility/index.html 24ways.org/2013/levelling-up 24ways.org/2013/levelling-up/index.html 24ways.org/2013/project-hubs 24ways.org/2013/project-hubs/index.html 24ways.org/2013/credits-and-recognition 24ways.org/2013/credits-and-recognition/index.html ... As a quick sanity check, let’s count the number of HTML pages we have retrieved: $ find 24ways.org | grep index.html | wc -l 328 There’s one last step! We got everything up to 2017, but we need to fetch the articles for 2018 (so far) as well. They aren’t linked in the /archives/ yet so we need to point our crawler at the site’s front page instead: wget --recursive --wait 2 --no-clobber -I /2018 -X "/*/*/comments" https://24ways.org/ Thanks to --no-clobber, this is safe to run every day in December to pick up any new content. We now have a folder on our computer containing an HTML file for every article that has ever been published on the site! Let’s use them to build ourselves a search index. Building a search index using SQLite There are many tools out there that can be used to build a search engine. You can use an open-source search server like Elasticsearch or Solr, a hosted option like Algolia or Amazon CloudSearch or you can tap into the built-in search features of relational databases like MySQL or PostgreSQL. I’m going to use something that’s less commonly used for web applications but makes for a powerful and extremely inexpensive alternative: SQLite. SQLite is the world’s most widely deployed database, even though many people have never even heard of it. That’s because it’s designed to be used as an embedded database: it’s commonly used by native mobile applications and even runs as part of the default set of apps on the Apple Watch! SQLite has one major limitation: unlike databases like MySQL and PostgreSQL, it isn’t really designed to handle large numbers of concurrent writes. For this reason, most people avoid it for building web applications. This doesn’t matter nearly so much if you are building a search engine for infrequently updated content - say one for a site that only publishes new content on 24 days every year. It turns out SQLite has very powerful full-text search functionality built into the core database - the FTS5 extension. I’ve been doing a lot of work with SQLite recently, and as part of that, I’ve been building a Python utility library to make building new SQLite databases as easy as possible, called sqlite-utils. It’s designed to be used within a Jupyter notebook - an enormously productive way of interacting with Python code that’s similar to the Observable notebooks Natalie described on 24 ways yesterday. If you haven’t used Jupyter before, here’s the fastest way to get up and running with it - assuming you have Python 3 installed on your machine. We can use a Python virtual environment to ensure the software we are installing doesn’t clash with any other installed packages: $ python3 -m venv ./jupyter-venv $ ./jupyter-venv/bin/pip install jupyter # ... lots of installer output # Now lets install some extra packages we will need later $ ./jupyter-venv/bin/pip install beautifulsoup4 sqlite-utils html5lib # And start the notebook web application $ ./jupyter-venv/bin/jupyter-notebook # This will open your browser to Jupyter at http://localhost:8888/ You should now be in the Jupyter web application. Click New -> Python 3 to start a new notebook. A neat thing about Jupyter notebooks is that if you publish them to GitHub (either in a regular repository or as a Gist), it will render them as HTML. This makes them a very powerful way to share annotated code. I’ve published the notebook I used to build the search index on my GitHub account. ​ Here’s the Python code I used to scrape the relevant data from the downloaded HTML files. Check out the notebook for a line-by-line explanation of what’s going on. from pathlib import Path from bs4 import BeautifulSoup as Soup base = Path("/Users/simonw/Dropbox/Development/24ways-search") articles = list(base.glob("*/*/*/*.html")) # articles is now a list of paths that look like this: # PosixPath('...24ways-search/24ways.org/2013/why-bother-with-accessibility/index.html') docs = [] for path in articles: year = str(path.relative_to(base)).split("/")[1] url = 'https://' + str(path.relative_to(base).parent) + '/' soup = Soup(path.open().read(), "html5lib") author = soup.select_one(".c-continue")["title"].split( "More information about" )[1].strip() author_slug = soup.select_one(".c-continue")["href"].split( "/authors/" )[1].split("/")[0] published = soup.select_one(".c-meta time")["datetime"] contents = soup.select_one(".e-content").text.strip() title = soup.find("title").text.split(" ◆")[0] try: topic = soup.select_one( '.c-meta a[href^="/topics/"]' )["href"].split("/topics/")[1].split("/")[0] except TypeError: topic = None docs.append({ "title": title, "contents": contents, "year": year, "author": author, "author_slug": author_slug, "published": published, "url": url, "topic": topic, }) After running this code, I have a list of Python dictionaries representing each of the documents that I want to add to the index. The list looks something like this: [ { "title": "Why Bother with Accessibility?", "contents": "Web accessibility (known in other fields as inclus...", "year": "2013", "author": "Laura Kalbag", "author_slug": "laurakalbag", "published": "2013-12-10T00:00:00+00:00", "url": "https://24ways.org/2013/why-bother-with-accessibility/", "topic": "design" }, { "title": "Levelling Up", "contents": "Hello, 24 ways. Iu2019m Ashley and I sell property ins...", "year": "2013", "author": "Ashley Baxter", "author_slug": "ashleybaxter", "published": "2013-12-06T00:00:00+00:00", "url": "https://24ways.org/2013/levelling-up/", "topic": "business" }, ... My sqlite-utils library has the ability to take a list of objects like this and automatically create a SQLite database table with the right schema to store the data. Here’s how to do that using this list of dictionaries. import sqlite_utils db = sqlite_utils.Database("/tmp/24ways.db") db["articles"].insert_all(docs) That’s all there is to it! The library will create a new database and add a table to it called articles with the necessary columns, then insert all of the documents into that table. (I put the database in /tmp/ for the moment - you can move it to a more sensible location later on.) You can inspect the table using the sqlite3 command-line utility (which comes with OS X) like this: $ sqlite3 /tmp/24ways.db sqlite> .headers on sqlite> .mode column sqlite> select title, author, year from articles; title author year ------------------------------ ------------ ---------- Why Bother with Accessibility? Laura Kalbag 2013 Levelling Up Ashley Baxte 2013 Project Hubs: A Home Base for Brad Frost 2013 Credits and Recognition Geri Coady 2013 Managing a Mind Christopher 2013 Run Ragged Mark Boulton 2013 Get Started With GitHub Pages Anna Debenha 2013 Coding Towards Accessibility Charlie Perr 2013 ... <Ctrl+D to quit> There’s one last step to take in our notebook. We know we want to use SQLite’s full-text search feature, and sqlite-utils has a simple convenience method for enabling it for a specified set of columns in a table. We want to be able to search by the title, author and contents fields, so we call the enable_fts() method like this: db["articles"].enable_fts(["title", "author", "contents"]) Introducing Datasette Datasette is the open-source tool I’ve been building that makes it easy to both explore SQLite databases and publish them to the internet. We’ve been exploring our new SQLite database using the sqlite3 command-line tool. Wouldn’t it be nice if we could use a more human-friendly interface for that? If you don’t want to install Datasette right now, you can visit https://search-24ways.herokuapp.com/ to try it out against the 24 ways search index data. I’ll show you how to deploy Datasette to Heroku like this later in the article. If you want to install Datasette locally, you can reuse the virtual environment we created to play with Jupyter: ./jupyter-venv/bin/pip install datasette This will install Datasette in the ./jupyter-venv/bin/ folder. You can also install it system-wide using regular pip install datasette. Now you can run Datasette against the 24ways.db file we created earlier like so: ./jupyter-venv/bin/datasette /tmp/24ways.db This will start a local webserver running. Visit http://localhost:8001/ to start interacting with the Datasette web application. If you want to try out Datasette without creating your own 24ways.db file you can download the one I created directly from https://search-24ways.herokuapp.com/24ways-ae60295.db Publishing the database to the internet One of the goals of the Datasette project is to make deploying data-backed APIs to the internet as easy as possible. Datasette has a built-in command for this, datasette publish. If you have an account with Heroku or Zeit Now, you can deploy a database to the internet with a single command. Here’s how I deployed https://search-24ways.herokuapp.com/ (running on Heroku’s free tier) using datasette publish: $ ./jupyter-venv/bin/datasette publish heroku /tmp/24ways.db --name search-24ways -----> Python app detected -----> Installing requirements with pip -----> Running post-compile hook -----> Discovering process types Procfile declares types -> web -----> Compressing... Done: 47.1M -----> Launching... Released v8 https://search-24ways.herokuapp.com/ deployed to Heroku If you try this out, you’ll need to pick a different --name, since I’ve already taken search-24ways. You can run this command as many times as you like to deploy updated versions of the underlying database. Searching and faceting Datasette can detect tables with SQLite full-text search configured, and will add a search box directly to the page. Take a look at http://search-24ways.herokuapp.com/24ways-b607e21/articles to see this in action. ​ SQLite search supports wildcards, so if you want autocomplete-style search where you don’t need to enter full words to start getting results you can add a * to the end of your search term. Here’s a search for access* which returns articles on accessibility: http://search-24ways.herokuapp.com/24ways-ae60295/articles?_search=acces%2A A neat feature of Datasette is the ability to calculate facets against your data. Here’s a page showing search results for svg with facet counts calculated against both the year and the topic columns: http://search-24ways.herokuapp.com/24ways-ae60295/articles?_search=svg&_facet=year&_facet=topic Every page visible via Datasette has a corresponding JSON API, which can be accessed using the JSON link on the page - or by adding a .json extension to the URL: http://search-24ways.herokuapp.com/24ways-ae60295/articles.json?_search=acces%2A Better search using custom SQL The search results we get back from ../articles?_search=svg are OK, but the order they are returned in is not ideal - they’re actually being returned in the order they were inserted into the database! You can see why this is happening by clicking the View and edit SQL link on that search results page. This exposes the underlying SQL query, which looks like this: select rowid, * from articles where rowid in ( select rowid from articles_fts where articles_fts match :search ) order by rowid limit 101 We can do better than this by constructing a custom SQL query. Here’s the query we will use instead: select snippet(articles_fts, -1, 'b4de2a49c8', '8c94a2ed4b', '...', 100) as snippet, articles_fts.rank, articles.title, articles.url, articles.author, articles.year from articles join articles_fts on articles.rowid = articles_fts.rowid where articles_fts match :search || "*" order by rank limit 10; You can try this query out directly - since Datasette opens the underling SQLite database in read-only mode and enforces a one second time limit on queries, it’s safe to allow users to provide arbitrary SQL select queries for Datasette to execute. There’s a lot going on here! Let’s break the SQL down line-by-line: select snippet(articles_fts, -1, 'b4de2a49c8', '8c94a2ed4b', '...', 100) as snippet, We’re using snippet(), a built-in SQLite function, to generate a snippet highlighting the words that matched the query. We use two unique strings that I made up to mark the beginning and end of each match - you’ll see why in the JavaScript later on. articles_fts.rank, articles.title, articles.url, articles.author, articles.year These are the other fields we need back - most of them are from the articles table but we retrieve the rank (representing the strength of the search match) from the magical articles_fts table. from articles join articles_fts on articles.rowid = articles_fts.rowid articles is the table containing our data. articles_fts is a magic SQLite virtual table which implements full-text search - we need to join against it to be able to query it. where articles_fts match :search || "*" order by rank limit 10; :search || "*" takes the ?search= argument from the page querystring and adds a * to the end of it, giving us the wildcard search that we want for autocomplete. We then match that against the articles_fts table using the match operator. Finally, we order by rank so that the best matching results are returned at the top - and limit to the first 10 results. How do we turn this into an API? As before, the secret is to add the .json extension. Datasette actually supports multiple shapes of JSON - we’re going to use ?_shape=array to get back a plain array of objects: JSON API call to search for articles matching SVG The HTML version of that page shows the time taken to execute the SQL in the footer. Hitting refresh a few times, I get response times between 2 and 5ms - easily fast enough to power a responsive autocomplete feature. A simple JavaScript autocomplete search interface I considered building this using React or Svelte or another of the myriad of JavaScript framework options available today, but then I remembered that vanilla JavaScript in 2018 is a very productive environment all on its own. We need a few small utility functions: first, a classic debounce function adapted from this one by David Walsh: function debounce(func, wait, immediate) { let timeout; return function() { let context = this, args = arguments; let later = () => { timeout = null; if (!immediate) func.apply(context, args); }; let callNow = immediate && !timeout; clearTimeout(timeout); timeout = setTimeout(later, wait); if (callNow) func.apply(context, args); }; }; We’ll use this to only send fetch() requests a maximum of once every 100ms while the user is typing. Since we’re rendering data that might include HTML tags (24 ways is a site about web development after all), we need an HTML escaping function. I’m amazed that browsers still don’t bundle a default one of these: const htmlEscape = (s) => s.replace( />/g, '&gt;' ).replace( /</g, '&lt;' ).replace( /&/g, '&' ).replace( /"/g, '&quot;' ).replace( /'/g, '&#039;' ); We need some HTML for the search form, and a div in which to render the results: <h1>Autocomplete search</h1> <form> <p><input id="searchbox" type="search" placeholder="Search 24ways" style="width: 60%"></p> </form> <div id="results"></div> And now the autocomplete implementation itself, as a glorious, messy stream-of-consciousness of JavaScript: // Embed the SQL query in a multi-line backtick string: const sql = `select snippet(articles_fts, -1, 'b4de2a49c8', '8c94a2ed4b', '...', 100) as snippet, articles_fts.rank, articles.title, articles.url, articles.author, articles.year from articles join articles_fts on articles.rowid = articles_fts.rowid where articles_fts match :search || "*" order by rank limit 10`; // Grab a reference to the <input type="search"> const searchbox = document.getElementById("searchbox"); // Used to avoid race-conditions: let requestInFlight = null; searchbox.onkeyup = debounce(() => { const q = searchbox.value; // Construct the API URL, using encodeURIComponent() for the parameters const url = ( "https://search-24ways.herokuapp.com/24ways-866073b.json?sql=" + encodeURIComponent(sql) + `&search=${encodeURIComponent(q)}&_shape=array` ); // Unique object used just for race-condition comparison let currentRequest = {}; requestInFlight = currentRequest; fetch(url).then(r => r.json()).then(d => { if (requestInFlight !== currentRequest) { // Avoid race conditions where a slow request returns // after a faster one. return; } let results = d.map(r => ` <div class="result"> <h3><a href="${r.url}">${htmlEscape(r.title)}</a></h3> <p><small>${htmlEscape(r.author)} - ${r.year}</small></p> <p>${highlight(r.snippet)}</p> </div> `).join(""); document.getElementById("results").innerHTML = results; }); }, 100); // debounce every 100ms There’s just one more utility function, used to help construct the HTML results: const highlight = (s) => htmlEscape(s).replace( /b4de2a49c8/g, '<b>' ).replace( /8c94a2ed4b/g, '</b>' ); This is what those unique strings passed to the snippet() function were for. Avoiding race conditions in autocomplete One trick in this code that you may not have seen before is the way race-conditions are handled. Any time you build an autocomplete feature, you have to consider the following case: User types acces Browser sends request A - querying documents matching acces* User continues to type accessibility Browser sends request B - querying documents matching accessibility* Request B returns. It was fast, because there are fewer documents matching the full term The results interface updates with the documents from request B, matching accessibility* Request A returns results (this was the slower of the two requests) The results interface updates with the documents from request A - results matching access* This is a terrible user experience: the user saw their desired results for a brief second, and then had them snatched away and replaced with those results from earlier on. Thankfully there’s an easy way to avoid this. I set up a variable in the outer scope called requestInFlight, initially set to null. Any time I start a new fetch() request, I create a new currentRequest = {} object and assign it to the outer requestInFlight as well. When the fetch() completes, I use requestInFlight !== currentRequest to sanity check that the currentRequest object is strictly identical to the one that was in flight. If a new request has been triggered since we started the current request we can detect that and avoid updating the results. It’s not a lot of code, really And that’s the whole thing! The code is pretty ugly, but when the entire implementation clocks in at fewer than 70 lines of JavaScript, I honestly don’t think it matters. You’re welcome to refactor it as much you like. How good is this search implementation? I’ve been building search engines for a long time using a wide variety of technologies and I’m happy to report that using SQLite in this way is genuinely a really solid option. It scales happily up to hundreds of MBs (or even GBs) of data, and the fact that it’s based on SQL makes it easy and flexible to work with. A surprisingly large number of desktop and mobile applications you use every day implement their search feature on top of SQLite. More importantly though, I hope that this demonstrates that using Datasette for an API means you can build relatively sophisticated API-backed applications with very little backend programming effort. If you’re working with a small-to-medium amount of data that changes infrequently, you may not need a more expensive database. Datasette-powered applications easily fit within the free tier of both Heroku and Zeit Now. For more of my writing on Datasette, check out the datasette tag on my blog. And if you do build something fun with it, please let me know on Twitter. 2018 Simon Willison simonwillison 2018-12-19T00:00:00+00:00 https://24ways.org/2018/fast-autocomplete-search-for-your-website/ code
123 Fast and Simple Usability Testing Everyone knows by now that they should test the usability of their applications, but still hardly anybody actually does it. In this article I’ll share some tips I’ve picked up for doing usability tests quickly and effectively. Relatively recent tools like Django and Ruby on Rails allow us to develop projects faster and to make significant changes later in the project timeline. Usability testing methods should now be adapted to fit this modern approach to development. When to test In an ideal world usability tests would be carried out frequently from an early stage of the project. Time and budget constraints lead this to be impractical; usability is often the first thing to get dropped from the project plan. If you can only test at one stage in the project, whatever the size, the most valuable time is before your first public beta — leaving long enough to fix issues and not so late that you can’t rethink your scope. There are three main categories of usability test: Testing design mockups Testing a new working application Testing established applications Each category requires a slightly different approach. For small modern web projects you are most likely to be testing a new working application. You will of course have already done functional tests so you won’t be worried about the user breaking things. The main differences between the categories apply in how you word The Script. Testing an established application is the most fun in my opinion. Humans are remarkably adaptable and rapidly develop coping strategies to work around usability issues in software they are forced to use. Uncovering these strategies may lead you to understand previously unspoken needs of your users. Often small changes to the application will have a dramatic affect on their everyday lives. Who to test When you have built a project to scratch your own itch, your intended audience will be people just like you. Test subjects in this case should be easy to find – friends, co-workers etc. This is not always the case; your users may not be like you at all. When they are not, it’s all the more important to run usability tests. Testing on friends, family and co-workers is better than not doing usability tests at all, but it can’t be compared to testing on actual samples of your intended audience. People who would use the system will provide more genuine feedback and deeper insight. Never let your test subjects put themselves in the shoes of your ‘actual’ users. For example, you should discourage comments like “Well, I would do this BUT if I was a bus driver I’d do that”. Users are not qualified to put themselves in the position of others. Inaccurate data is often worse than no data. Aim for five or six test subjects: any more and you probably won’t learn anything new; any less and you’re likely to be overwhelmed by issues stemming from people’s individual personalities. The Script The Script is a single side of A4 (or letter) paper, consisting of questions for your testers and reminders for yourself. Have a balance of task-based questions and expectation analysis. This helps maintain consistency across tests. Expectation analysis is more important for testing designs and new applications: “Where would you find X?”, “What would you expect to happen if you clicked on Y?”. In an established system users will probably know where these things are though it can still be illuminating to ask these questions though phrased slightly differently. Task-based questions involve providing a task for the user to complete. If you are testing an established system it is a good idea to ask users to bring in tasks that they would normally perform. This is because the user will be more invested in the outcome of the task and will behave in a more realistic fashion. When designing tasks for new systems and designs ensure you only provide loose task details for the same reason. Don’t tell testers to enter “Chantelle”; have them use their own name instead. Avoid introducing bias with the way questions are phrased. It’s a good idea to ask for users’ first impressions at the beginning of the test, especially when testing design mockups. “What are the main elements on the page?” or “What strikes you first?”. You script should run for a maximum of 45 minutes. 30-35 minutes is better; after this you are likely to lose their attention. Tests on established systems can take longer as there is more to learn from them. When scheduling the test you will need to leave yourself 5 minutes between each one to collate your notes and prepare for the next. Be sure to run through the script beforehand. Your script should be flexible. It is possible that during the test a trend will come to light that opens up whole new avenues of possible questioning. For example, during one initial test of an established system I noticed that the test subject had been printing off items from the application and placing them in a folder in date order (the system ordered alphabetically). I changed the script to ask future participants in that run, if they ever used external tools to help them with tasks within the system. This revealed a number of interesting issues that otherwise would not have been found. Running the tests Treat your test subjects like hedgehogs. Depending on your target audience they probably feel a little nervous and perhaps even scared of you. So make them a little nest out of straw, stroke their prickles and give them some cat food. Alternatively, reassure them that you are testing the system and that they can’t give a wrong answer. Reward them with a doughnut or jam tart at the end. Try to ensure the test environment is relaxed and quiet, but also as close as possible to the situation where they would actually use the system. Have your subjects talk out loud is very important as you can’t read their minds, but it is a very unnatural process. To loosen up your subjects and get them talking in the way you want them to, try the Stapler Trick. Give them a stapler or similar item and ask them to open it, take the staples out, replace them, shut the stapler and staple some paper – talking all the time about what they see, what they expect to happen, what actually happens and how that matches up. Make them laugh at you. Say how long the test will take up front, and tell your subject why you are doing it. After the test has been completed, conclude by thanking them for their time and assuring them that they were very useful. Then give them the sugary treat. What to look for Primarily, you should look out for incidents where the user stops concentrating on her tasks and starts thinking about the tool and how she is going to use it. For example, when you are hammering in a nail you don’t think about how to use a hammer; good software should be the same. Words like ‘it’ and ‘the system’ and are good indications that the test subject has stopped thinking about the task in hand. Note questioning words, especially where testers question their own judgement, “why can’t I find …”, “I expected to see …” etc. as this indicates that the work flow for the task may have broken down. Also keep an eye on occasions where the user completely fails to do a task. They may need some prompting to unstick them, but you should be careful not to bias the test. These should be the highest priority issues for you to fix. If users recover from getting stuck, make a note of how they recovered. Prolonged periods of silence from the test subject may also require prompting as they should be talking all the time. Ask them what they are thinking or looking for but avoid words like ‘try’ (e.g. ‘what are you trying to do?’) as this implies that they are currently failing. Be wary of users’ opinions on aesthetics and be prepared to bring them back to the script if they get side-tracked. Writing it up Even if you are the only developer it’s important to summarise the key issues that emerged during testing: your notes won’t make much sense to you a week or so after the test. If you are writing for other people, include a summary no longer than two pages; this can consist of a list or table of the issues including recommendations and their priorities. Remember to anonymise the users in the report. In team situations, you may be surprised at how many people are interested in the results of the usability test even if it doesn’t relate directly to something that they can fix. To conclude… Some usability testing is better than none at all, even for small projects or those with strict deadlines. Make the most of the time and resources available. Choose your users carefully, make them comfortable, summarise your report and don’t forget to leave a doughnut for yourself! 2006 Natalie Downe nataliedowne 2006-12-16T00:00:00+00:00 https://24ways.org/2006/fast-and-simple-usability-testing/ process
145 The Neverending (Background Image) Story Everyone likes candy for Christmas, and there’s none better than eye candy. Well, that, and just more of the stuff. Today we’re going to combine both of those good points and look at how to create a beautiful background image that goes on and on… forever! Of course, each background image is different, so instead of agonising over each and every pixel, I’m going to concentrate on five key steps that you can apply to any of your own repeating background images. In this example, we’ll look at the Miami Beach background image used on the new FOWA site, which I’m afraid is about as un-festive as you can get. 1. Choose your image wisely I find there are three main criteria when judging photos you’re considering for repetition manipulation (or ‘repetulation’, as I like to say)… simplicity (beware of complex patterns) angle and perspective (watch out for shadows and obvious vanishing points) consistent elements (for easy cloning) You might want to check out this annotated version of the image, where I’ve highlighted elements of the photo that led me to choose it as the right one. The original image purchased from iStockPhoto. The Photoshopped version used on the FOWA site. 2. The power of horizontal lines With 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 ‘template’ on which to work over. It doesn’t matter which side you choose, although you might find it beneficial to use the one with the simplest spread of colour and complex elements. Click and hold on the marquee tool in the toolbar and select the ‘single column marquee tool’, 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. A one-pixel-wide selection stretched out to the entire width of the canvas. 3. Cloning It 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’s important to be fairly loose with it. Always clone on to a new layer so that you’ve 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’t have to worry about getting your clones right first time. In 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. The edge of the shadow is cut off and needs to be ‘made’ from a pre-existing element. The successful clone completes the missing shadow. The two elements are obviously very similar but it doesn’t look like a clone because the majority of the shape is ‘genuine’ and only a small part is a duplicate. Also, after cloning I transformed the duplicate, erased parts of it, used gradients, and — ooh, did someone mention gradients? 4. Never underestimate a gradient For 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. Several of the gradients and brushes that make up the ‘customised’ part of the image, visible when the main photograph layer is hidden. The full composite. Gradients 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. Speaking of which… 5. Sewing the seams No 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 ‘loop’ point. Fret ye not, however, for there’s 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. The seam is usually easy to spot because it’s a blank area with not much detail or colour variation, so in order to disguise it, go against the rule: put something across it! This isn’t quite as challenging as it may sound, because if we intentionally make our own ‘object’ 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! A sky with no clouds in an unhappy one. A simple soft white brush creates a cloud-like formation in the sky. After taking the cloud’s 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. Finally, 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. And 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. Thanks for reading, folks. Have a great Christmas! 2007 Elliot Jay Stocks elliotjaystocks 2007-12-03T00:00:00+00:00 https://24ways.org/2007/the-neverending-background-image-story/ code
143 Marking Up a Tag Cloud Everyone’s doing it. The problem is, everyone’s doing it wrong. Harsh words, you might think. But the crimes against decent markup are legion in this area. You see, I’m something of a markup and semantics junkie. So I’m going to analyse some of the more well-known tag clouds on the internet, explain what’s wrong, and then show you one way to do it better. del.icio.us I think the first ever tag cloud I saw was on del.icio.us. Here’s how they mark it up. <div class="alphacloud"> <a href="/tag/.net" class="lb s2">.net</a> <a href="/tag/advertising" class=" s3">advertising</a> <a href="/tag/ajax" class=" s5">ajax</a> ... </div> Unfortunately, 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’s author hasn’t described it that way in the markup. It isn’t a list of tags, just a bunch of anchors in a <div>. This is also inaccessible because a screenreader will not pause between adjacent links, and in some configurations will not announce the individual links, but rather all of the tags will be read as just one link containing a whole bunch of words. Markup crime number one. Flickr Ah, Flickr. The darling photo sharing site of the internet, and the biggest blind spot in every standardista’s vision. Forgive it for having atrocious markup and sometimes confusing UI because it’s just so much damn fun to use. Let’s see what they do. <p id="TagCloud">  <a href="/photos/tags/06/" style="font-size: 14px;">06</a>   <a href="/photos/tags/africa/" style="font-size: 12px;">africa</a>   <a href="/photos/tags/amsterdam/" style="font-size: 14px;">amsterdam</a>  ... </p> Again 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’s so far away from the goal of separating style from content, they might as well use a <font> tag. You could theoretically parse that to extract the information, but you have more work to guess what the pixel sizes represent. Markup crime number two (and extra jail time for using non-breaking spaces purely for visual spacing purposes.) Technorati Ah, now. Here, you’d expect something decent. After all, the Overlord of microformats and King of Semantics Tantek Çelik works there. Surely we’ll see something decent here? <ol class="heatmap"> <li><em><em><em><em><a href="/tag/Britney+Spears">Britney Spears</a></em></em></em></em></li> <li><em><em><em><em><em><em><em><em><em><a href="/tag/Bush">Bush</a></em></em></em></em></em></em></em></em></em></li> <li><em><em><em><em><em><em><em><em><em><em><em><em><em><a href="/tag/Christmas">Christmas</a></em></em></em></em></em></em></em></em></em></em></em></em></em></li> ... <li><em><em><em><em><em><em><a href="/tag/SEO">SEO</a></em></em></em></em></em></em></li> <li><em><em><em><em><em><em><em><em><em><em><em><em><em><em><em><a href="/tag/Shopping">Shopping</a></em></em></em></em></em></em></em></em></em></em></em></em></em></em></em></li> ... </ol> Unfortunately it turns out not to be that decent, and stop calling me Shirley. It’s not exactly terrible code. It does recognise that a tag cloud is a list of links. And, since they’re in alphabetical order, that it’s an ordered list of links. That’s nice. However … fifteen nested <em> tags? FIFTEEN? That’s emphasis for you. Yes, it is parse-able, but it’s also something of a strange way of looking at emphasis. The HTML spec states that <em> is emphasis, and <strong> is for stronger emphasis. Nesting <em> tags seems counter to the idea that different tags are used for different levels of emphasis. Plus, if you had a screen reader that stressed the voice for emphasis, what would it do? Shout at you? Markup crime number three. So what should it be? As 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. A 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’m going to take some of my favourite flickr tags and put them into a cloud which communicates the relative frequency of each tag. To 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’ll 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: The items need to be displayed next to each other, rather than one-per-line The context information should be hidden from display (but not from screen readers) The tag should link to the page of items with that tag Displaying the items next to each other simply means setting the display of the list elements to inline. The context can be hidden by wrapping it in a <span> and then using the off-left method to hide it. And the link just means adding an anchor (with rel="tag" for some extra microformats bonus points). So, now we have a simple collection of links in our second example. The 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’ll 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. 2006 Mark Norman Francis marknormanfrancis 2006-12-09T00:00:00+00:00 https://24ways.org/2006/marking-up-a-tag-cloud/ code
74 Should We Be Reactive? Evolution Looking at the evolution of the web and the devices we use should help remind us that the times we’re adjusting to are just another step on a journey. These times seem to be telling us that we need to embrace flexibility. Imagine an HTML file containing nothing but text. It’s viewable on any web-capable device and reasonably readable: the notion of the universality of the web was very much a founding principle. Right from the beginning, browser vendors understood that we’d want text to reflow (why wouldn’t we?), so I consider the first websites to have been fluid. As we attempted to exert more control through our designs in the early days of the web, debates about whether we should produce fixed or fluid sites raged. We could create fluid designs using tables, but what we didn’t have then was a wide range of web capable devices or the ability to control this fluidity. The biggest changes occurred when stats showed enough people using a different screen resolution we could cater for. To me, the techniques of responsive web design provide the control we were missing. Combining new approaches to layout and images with media queries empowered us to learn how to embrace the inherent flexibility of the web in ways to suit our work and the devices used by our audience. Perhaps another kind of flexibility might be found in how we use context to affect how we present our content; to consider how we might use the information we can access from people, browsers and devices to provide web experiences – effectively creating sites that react to initial or changing circumstances in the relationship between people and our content. Embracing flexibility So what is context? Put simply, you could think of it as a secondary piece of information that helps clarify the meaning of the first. It helps set a scene or describe circumstances. I think that Cennydd Bowles has summed it up really well through talks he’s given recently, in which he’s arrived at the acronym DETAILS (Device, Environment, Time, Activity, Individual, Location, Social) – I encourage you to keep an eye out for his next book due in the new year where he’ll explore this idea much further. This clarity over what context could mean in terms of what we do on the web is fundamental, directing us towards ways we might use it. When you stop to think about it, we’ve been using some basic pieces of this information right from the beginning, like bits of JavaScript or Java applets that serve an appropriate greeting to your site’s visitors, or show their location, or even local weather. But what if we think of this from the beginning of our projects? We should think about our content first. Once we know this and have a direction, perhaps then we can think about what context, or even multiple contexts, might help us to communicate more effectively. The real world There’s always been a disconnect between the real world and the web, which is to be expected. But the world around us is a sea of data; every fundamental building block: people, places, events and things have information waiting to be explored. For sites based around physical objects or locations, this divide is really apparent. We don’t ordinarily take the time to describe in code the properties of a place, or consider whether your relationship to the place in the real world should have any impact on your relationship with a site about it. When I think about local businesses, they have such rich properties to draw on and yet we don’t really explore them in any meaningful way, even through something as simple as opening hours. Now we have data… We’ve long had access to the current time both on server- and client-sides. The use of geolocation is easier than ever, but when we look at the range of information we could glean to help us make some choices, maybe there’s some help on the horizon from projects like the W3C Device APIs Working Group. This might prove useful to help make us aware of network and battery conditions of a device, along with the potential to gain data from other sensors, which could tell us about lighting conditions, ambient noise levels and temperature depending on the capabilities of the device. It may be that our sites have some form of login or access to your profile from another site. Along with data from our devices and browsers, this should give us a sense of how best to talk to our audience in certain situations. We don’t necessarily need to know any personal details, just enough to make decisions about how to present our sites. The reactive web? So why reactive web design? I’m hoping that a name might help us to have a common vocabulary not only about what we mean when we talk about context, but how it could be considered through our projects, right from the early stages. How could this manifest itself? A simple example might be a location-aware panel on your site. Perhaps the space is a little down in your content hierarchy but serves a perfectly valid purpose by default. To visitors outside the country perhaps this works fine, but within your country maybe this panel could be used to communicate more effectively. Further still, if we knew the visitors were in the vicinity, we could talk to them more directly. What if both time and location were relevant? This space could work as before but you could consider how time could intersect with your local audience. If you know they’re local and it’s a certain time of day, you could communicate directly with them. This example isn’t beyond what banner ads often do and uses easily accessible information. There are more unusual combinations we may be able to find, such as movement and presence. Perhaps a site that tells a story, which changes design and content based on whether you’re moving, how long you’ve been on the site and how far you’ve travelled. This isn’t what we typically expect from websites, but we should bear in mind that what websites are now will not be what they become in the future. You could do much of this contextual presentation through native apps, of course. The Silent History, an app novel written and designed for iPad and iPhone, uses an exploration element, providing “hundreds of location-based stories across the U.S. and around the world. These can be read only when your device’s GPS matches the coordinates of the specified location.” But considering the universality of the web, we could redefine what web-based experiences should be like. Not all methods would work well on the web, but that’s a decision that has to be made for a specific project. By thinking more broadly about any web-capable device, we can use what we know to provide relevant experiences for our site’s visitors. We need to be sure what we mean by relevant, of course! Reality bites While there are incredible possibilities, from a simple panel on a site to something bordering on living sites that evolve and change with our circumstances, we need to act with a degree of pragmatism and understand how much of what we could do is based on assumptions and the bias of our own experiences. We could go wild with changing the way our content is presented based on contextual information, but if we’re not careful what we end up with confuses and could provide a very fractured experience. As much as possible we need to think more ethnographically, observe and question people in the situations we think may be relevant, and test our assumptions as early as we can. Even on small projects, there may be ways we can validate our assumptions and test with our audience. The key to applying contextual content or cues is not to break the experience between contextual views (as I think we now wouldn’t when hiding content on a mobile view). It’s another instance of progressive enhancement – as we know certain pieces of information, we can enhance the experience. Also, if you do change content, how can you not make a more cumbersome experience for your visitors? It’s all about communication Content is at the core of what we do, but if we consider context we need to understand the impact on that. The effect could be as subtle as an altered hierarchy, involve swapping out panels of content, or in extreme instances perhaps all of your content might change. In some ways, this extends the notion of adaptive content that Karen McGrane has been talking about, to how we write and store the content we create. Thinking about the the impact of context may require us to re-evaluate our site structure, too. Whatever we decide, we have to be clear what will happen and manage the expectations of our users. The bottom line What I’m proposing isn’t that we go crazy and end up with a confused, disjointed set of experiences across the web. What I hope is that starting right from the beginning of a project, we think about what context is and could be, and see what relevance it might have to what we’re trying to communicate. This strategic process leads us to think about design. We are slowly adapting to what it means to be flexible through responsive and adaptive processes. What does thinking about contextual states mean to us (or designing for state in general)? Does this highlight again how difficult it’ll be for our tools to keep up with our processes and output? In terms of code, the vast majority of this data comes from the client-side through JavaScript. While we can progressively enhance, this could lead to a lot of code bloat through feature or capability detection, and potentially a lot of conditional loading of scripts. It’s a real shame we don’t get much we can rely on from the server-side – we know how unreliable user agents are! We need to understand why we’d do this. Are we trying to communicate well and be useful, or doing it to show off? Underneath it all, what do we base our decisions on? Do we have actual insight or are we proceeding from our assumptions and the bias of our own experiences? Scott Jenson summed it up best for me: (to paraphrase) the pain we put people through has to be greatly outweighed by the value we offer. I see that this could be another potential step in our evolution on the web; continuing this exploration of the flexibility the web allows us. It’s amazing we can do such incredible things from what is essentially a set of disparate, linked documents. 2012 Dan Donald dandonald 2012-12-09T00:00:00+00:00 https://24ways.org/2012/should-we-be-reactive/ design
204 Cascading Web Design with Feature Queries Feature queries, also known as the @supports rule, were introduced as an extension to the CSS2 as part of the CSS Conditional Rules Module Level 3, which was first published as a working draft in 2011. It is a conditional group rule that tests if the browser’s user agent supports CSS property:value pairs, and arbitrary conjunctions (and), disjunctions (or), and negations (not) of them. The motivation behind this feature was to allow authors to write styles using new features when they were supported but degrade gracefully in browsers where they are not. Even though the nature of CSS already allows for graceful degradation, for example, by ignoring unsupported properties or values without disrupting other styles in the stylesheet, sometimes we need a bit more than that. CSS is ultimately a holistic technology, in that, even though you can use properties in isolation, the full power of CSS shines through when used in combination. This is especially evident when it comes to building web layouts. Having native feature detection in CSS makes it much more convenient to build with cutting-edge CSS for the latest browsers while supporting older browsers at the same time. Browser support Opera first implemented feature queries in November 2012, both Chrome and Firefox had it since May 2013. There have been several articles about feature queries written over the years, however, it seems that awareness of its broad support isn’t that well-known. Much of the earlier coverage on feature queries was not written in English, and perhaps that was a limiting factor. @supports ― CSSのFeature Queries by Masataka Yakura, August 8 2012 Native CSS Feature Detection via the @supports Rule by Chris Mills, December 21 2012 CSS @supports by David Walsh, April 3 2013 Responsive typography with CSS Feature Queries by Aral Balkan, April 9 2013 How to use the @supports rule in your CSS by Lea Verou, January 31 2014 CSS Feature Queries by Amit Tal, June 2 2014 Coming Soon: CSS Feature Queries by Adobe Web Platform Team, August 21 2014 CSS feature queries mittels @supports by Daniel Erlinger, November 27 2014 As of December 2017, all current major browsers and their previous 2 versions support feature queries. Feature queries are also supported on Opera Mini, UC Browser and Samsung Internet. The only browsers that do not support feature queries are Internet Explorer and Blackberry Mobile, but that may be less of an issue than you might think. Can I Use css-featurequeries? Data on support for the css-featurequeries feature across the major browsers from caniuse.com. Granted, there is still a significant number of organisations that require support of Internet Explorer. Microsoft still continues to support IE11 for the life-cycle of Windows 7, 8 and 10. They have, however, stopped supporting older versions since January 12, 2016. It is inevitable that there will be organisations that, for some reason or another, make it mandatory to support IE, but as time goes on, this number will continue to shrink. Jen Simmons wrote an extensive article called Using Feature Queries in CSS which discussed a matrix of potential situations when it comes to the usage of feature queries. The following image is a summary of the aforementioned matrix. The most tricky situation we have to deal with is the box in the top-left corner, which are “browsers that don’t support feature queries, yet do support the feature in question”. For cases like those, it really depends on the specific CSS feature you want to use and a subsequent evaluation of the pros and cons of not including that feature in spite of the fact the browser (most likely Internet Explorer) supports it. The basics of feature queries As with any conditional, feature queries operate on boolean logic, in other words, if the query resolves to true, apply the CSS properties within the block, or else just ignore the entire block altogether. The syntax of a simple feature query is as follows: .selector { /* Styles that are supported in old browsers */ } @supports (property:value) { .selector { /* Styles for browsers that support the specified property */ } } Note that the parentheses around the property:value pair are mandatory and the rule is invalid without them. Styles that apply to older browsers, i.e. fallback styles, should come first, followed by the newer properties, which are contained within the @supports conditional. Because of the cascade, fallback styles will be overridden by the newer properties in the modern browsers that support them. main { background-color: red; } @supports (display:grid) { main { background-color: green; } } In this example, browsers that support CSS grid will have a main element with a green background colour because the conditional resolves to true, while browsers that do not support grid will have a main element with a red background colour. The implication of such behaviour means that we can layer on enhanced styles based on the features we want to use and these styles will show up in browsers that support them. But for those that do not, they will get a more basic look that still works anyway. And that will be our approach moving forward. Boolean operators for feature queries The and operator allows us to test for support of multiple properties within a single conditional. This would be useful for cases where the desired output requires multiple cutting-edge features to be supported at the same time to work. All the property:value pairs listed in the conditional must resolve to true for the styles within the rule to be applied. @supports (transform: rotate(45deg)) and (writing-mode: vertical-rl) { /* Some CSS styles */ } The or operator allows us to list multiple property:value pairs in the conditional and as long as one of them resolves to true, the styles within the block will be applied. A relevant use-case would be for properties with vendor-prefixes. @supports (background: -webkit-gradient(linear, left top, left bottom, from(white), to(black))) or (background: -o-linear-gradient(top, white, black)) or (background: linear-gradient(to bottom, white, black)) { /* Some CSS styles */ } The not operator negates the resolution of the property:value pair in the conditional, resolving to false when the property is supported and vice versa. This is useful when there are two distinct sets of styles to be applied depending on the support of a specific feature. However, we do need to keep in mind the case where a browser does not support feature queries, and handle the styles for those browsers accordingly. @supports not (shape-outside: polygon(100% 80%,20% 0,100% 0)) { /* Some CSS styles */ } To avoid confusion between and and or, these operators must be explicitly declared as opposed to using commas or spaces. To prevent confusion caused by precedence rules, and, or and not operators cannot be mixed without a layer of parentheses. This rule is not valid and the styles within the block will be ignored. @supports (transition-property: background-color) or (animation-name: fade) and (transform: scale(1.5)) { /* Some CSS styles */ } To make it work, parentheses must be added either around the two properties adjacent to the or or the and operator like so: @supports ((transition-property: background-color) or (animation-name: fade)) and (transform: scale(1.5)) { /* Some CSS styles */ } @supports (transition-property: background-color) or ((animation-name: fade) and (transform: scale(1.5))) { /* Some CSS styles */ } The current specification states that whitespace is required after a not and on both sides of an and or or, but this may change in a future version of the specification. It is acceptable to add extra parentheses even when they are not needed, but omission of parentheses is considered invalid. Cascading web design I’d like to introduce the concept of cascading web design, an approach made possible with feature queries. Browser update cycles are much shorter these days, so new features and bug fixes are being pushed out a lot more frequently as compared to the early days of the web. With the maturation of web standards, browser behaviour is less unpredictable than before, but each browser will still have their respective quirks. Chances are, the latest features will not ship across all browsers at the same time. But you know what? That’s perfectly fine. If we accept this as a feature of the web, instead of a bug, we’ve just opened up a lot more web design possibilities. The following example is a basic, responsive grid layout of items laid out with flexbox, as viewed on IE11. We can add a block of styles within an @supports rule to apply CSS grid properties for browsers that support them to enhance this layout, like so: The web is not a static medium. It is dynamic and interactive and we manipulate this medium by writing code to tell the browser what we want it to do. Rather than micromanaging the pixels in our designs, maybe it’s time we cede control of our designs to the browsers that render them. This means being okay with your designs looking different across browsers and devices. As mentioned earlier, CSS works best when various properties are combined. It’s one of those things whose whole is greater than the sum of its parts. So feature queries, when combined with media queries, allow us to design layouts that are most effective in the environment they have to perform in. Such an approach requires interpolative thinking, on multiple levels. As web designers and developers, we don’t just think in one fixed dimension, we get to think about how our design will morph on a narrow screen, or on an older browser, in addition to how it will appear on a browser with the latest features. In the following example, the layout on the left is what IE11 users will see, the one in the middle is what Firefox users will see, because Firefox doesn’t support CSS shapes yet, but once it does, it will then look like the layout on the right, which is what Chrome users see now. With the release of CSS Grid this year, we’ve hit another milestone in the evolution of the web as a medium. The beauty of the web is its backwards compatibility and generous fault tolerance. Browser features are largely additive, holding onto the good parts and building on top of them, while deprecating the bits that didn’t work well. Feature queries allow us to progressively enhance our CSS, establishing a basic level of user experience across the widest range of browsers, while building in more advanced functionality for browsers who can use them. And hopefully, this will allow more of us to create designs that truly embrace the nature of the web. 2017 Chen Hui Jing chenhuijing 2017-12-01T00:00:00+00:00 https://24ways.org/2017/cascading-web-design/ code
183 Designing For The Switch For a long time on the web, we’ve been typographically spoilt. Yes, you heard me correctly. Think about it: our computers come with web fonts already installed; fonts that have been designed specifically to work well online and at small size; and fonts that we can be sure other people have too. Yes, we’ve been spoilt. We don’t need to think about using Verdana, Arial, Georgia or Cambria. Yet, for a long time now, designers have felt we needed more. We want to choose whatever typeface we feel necessary for our designs. We did bad things along the way in pursuit of this goal such as images for text. Smart people dreamt up tools to help us such as sIFR, or Cufón. Only fairly recently, @font-face is supported in most browsers. The floodgates are opening. It really is the dawn of a new typographic era on the web. And we must tread carefully. The New Typesetters Many years ago, before the advent of desktop publishing, if you wanted words set in a particular typeface, you had to go to a Typesetter. A Typesetter, or Compositor, as they were sometimes called, was a person whose job it was to take the written word (in the form of a document or manuscript) and ‘set’ the type in the desired typeface. The designer would chose what typeface they wanted – and all the ligatures, underlines, italics and whatnot – and then scribble all over the manuscript so the typesetter could set the correct type. Then along came Desktop Publishing and every Tom, Dick and Harry could choose type on their computer and an entire link in the typographic chain was removed within just a few years. Well, that’s progress I guess. That was until six months ago when Typesetting was reborn on the web in the guise of a font service: Typekit. Typekit – and services like Typekit such as Typotheque, Kernest and the upcoming Fontdeck – are typesetting services for the web. You supply them with your content, in the form of a webpage, and they provide you with some JavaScript to render that webpage in the typeface you’ve specified simply by adding the font name in your CSS file. Thanks to services like these, font foundries are now talking to create licensing structures to allow us to embed fonts into our web pages legally – which has always been a sticking point in the past. So, finally, us designers can get what we want: whatever typeface we want on the web. Yes, but… there are hurdles. One of which is the subject of this article. The differences between Web Fonts and other fonts Web fonts are different to normal fonts. They differ in a whole bunch of ways, from loose letter spacing to larger x-heights. But perhaps the most notable practical difference is file size. Let’s take a look at one of Typekit’s latest additions from the FontFont library, Meta. Meta Roman weighs in at 42 KB. This is a fairly typical file size for a single weight of a good font. Now, let’s have a look at Verdana. Verdana is 186 KB. For one weight. The four weight family for Verdana weighs in at 686 KB. Four weights for half a megabyte!? Why so huge? Well, Verdana has a lot of information packed into its 186 KB. It has the largest hinting data table of any typeface (the information carried by a font that tells it how to align itself to the pixels on your screen). As it has been shipped with Microsoft products since 1996, it has had time to grow to support many, many languages. Along with its cousin, Georgia (283 KB), Verdana was a new breed of typeface. And it’s grown fat. If really serious web typography takes off – and by that I mean typefaces specifically designed for the screen – then we’re going to see more fonts increase in file size as the font files include more data. So, if you’re embedding a font weighing in at 100 KB, what happens? The Flash of Unstyled Text We all remember the Flash of Unstyled Content bug on Internet Explorer, right? That annoying bug that caused a momentary flash of unstyled HTML page. Well, the same thing can happen with embedding fonts using @font-face. An effect called The Flash of Unstyled Text (FOUT), first coined by Paul Irish. Personally, I prefer to call it the Flash of UnTypeset Text (still FOUT), as the text is styled, just not with what you want. If you embed a typeface in your CSS, then the browser will download that typeface. Typically, browsers differ in the way they handle this procedure. Firefox and Opera will render the text using the next font in your font stack until the first (embedded) font is loaded. It will then switch to the embedded font. Webkit takes the approach that you asked for that font so it will wait until it’s completely loaded before showing it you. In Opera and Firefox, you get a FOUT. In Webkit, you don’t. You wait. Hang on there. Didn’t I say that good web fonts weigh in considerably more than ‘normal’ fonts? And whilst the browser is downloading the font, the user gets what to look at? Some pictures, background colours and whatever else isn’t HTML? I believe Webkit’s handling of font embedding – as deliberate as it is – is damaging to the practice of font embedding. Why? Well, we can design to a switch in typeface (as jarring as that is for the user), but we can’t design to blank space. Let’s have a closer look at how we can design to FOUT. More considered font stacks We all know that font stacks in CSS are there for when a user doesn’t have a font; the browser will jump to the next one in the stack. Adding embedded fonts into the font stack means that because of FOUT (in gecko and Opera), the user can see a switch, and depending on their connection that switch could happen well into any reading that the user may be doing. The practicalities of this are that a user could be reading and be towards the end of a line when the paragraph they are reading changes shape. The word they were digesting suddenly changes to three lines down. It’s the online equivalent of someone turning the page for you when you least expect it. So, how can we think about our font stacks slightly differently so we can minimise the switch? Two years ago, Richard Rutter wrote on this very site about increasing our font stacks. By increasing the font stacks (by using his handy matrix) we can begin to experiment with different typefaces. However, when we embed a typeface, we must look very carefully at the typefaces in the font stack and the relationship between them. Because, previously, the user would not see a switch from one typeface to another, they’d just get either one or the other. Not both. With FOUT, the user sees two typefaces. By carefully looking at the characteristics of the typefaces you choose, you can minimise the typographic ‘distance’ between the type down the stack. In doing so, you minimise the jarring effect of the switch. Let’s take a look at an example of how to go about this. Micro Typography to build better font stacks Let’s say I want to use a recent edition to Typekit – Meta Serif Book – as my embedded font. My font stack would start like this: font-family: 'Meta Serif Bold'; Where do you go from here? Well, first, familiarise yourself with Richard’s Font Matrix so you get an idea of what fonts are available for different people. Then start by looking closely at the characters of the embedded font and then compare them to different fonts from the matrix. When I do this, I’m looking to match type characteristics such as x-height, contrast (the thickness and thinness of strokes), the stress (the angle of contrast) and the shape of the serifs (if the typeface has any). Using just these simple comparative metrics means you can get to a ‘best fit’ reasonably quickly. And remember, you’re not after an ideal match. You’re after a match that means the switch is less painful for the reader, but also a typeface that carries similar characteristics so your design doesn’t change too much. Building upon my choice of embedded font, I can quickly build up a stack by comparing letters. This then creates my ‘best fit’ stack. This translates to the CSS as: font-family: 'Meta Serif Bold', 'Lucida Bright', Cambria, Georgia, serif Following this process, and ending up with considered font stacks, means that we can design to the Flash of UnTypeset Content and ensure that our readers don’t get a diminished experience. 2009 Mark Boulton markboulton 2009-12-16T00:00:00+00:00 https://24ways.org/2009/designing-for-the-switch/ design
97 Making Modular Layout Systems For all of the advantages the web has with distribution of content, I’ve always lamented the handiness of the WYSIWYG design tools from the print publishing world. When I set out to redesign my personal website, I wanted to have some of the same abilities that those tools have, laying out pages how I saw fit, and that meant a flexible system for dealing with imagery. Building on some of the CSS that Eric Meyer employed a few years back on the A List Apart design, I created a set of classes to use together to achieve the variety I was after. Employing multiple classes isn’t a new technique, but most examples aren’t coming at this from strictly editorial and visual perspectives; I wanted to have options to vary my layouts depending on content. If you want to skip ahead, you can view the example first. Laying the Foundation We need to be able to map out our page so that we have predictable canvas, and then create a system of image sizes that work with it. For the sake of this article, let’s use a simple uniform 7-column grid, consisting of seven 100px-wide columns and 10px of space between each column, though you can use any measurements you want as long as they remain constant. All of our images will have a width that references the grid column widths (in our example, 100px, 210px, 320px, 430px, 540px, 650px, or 760px), but the height can be as large as needed. Once we know our images will all have one of those widths, we can setup our CSS to deal with the variations in layout. In the most basic form, we’re going to be dealing with three classes: one each that represent an identifier, a size, and a placement for our elements. This is really a process of abstracting the important qualities of what you would do with a given image in a layout into separate classes, allowing you to quickly customize their appearance by combining the appropriate classes. Rather than trying to serve up a one-size-fits-all approach to styling, we give each class only one or two attributes and rely on the combination of classes to get us there. Identifier This specifies what kind of element we have: usually either an image (pic) or some piece of text (caption). Size Since we know how our grid is constructed and the potential widths of our images, we can knock out a space equal to the width of any number of columns. In our example, that value can be one, two, three, four, five, six, or seven. Placement This tells the element where to go. In our example we can use a class of left or right, which sets the appropriate floating rule. Additions I created a few additions that be tacked on after the “placement” in the class stack: solo, for a bit more space beneath images without captions, frame for images that need a border, and inset for an element that appears inside of a block of text. Outset images are my default, but you could easily switch the default concept to use inset images and create a class of outset to pull them out of the content columns. The CSS /* I D E N T I F I E R */ .pic p, .caption { font-size: 11px; line-height: 16px; font-family: Verdana, Arial, sans-serif; color: #666; margin: 4px 0 10px; } /* P L A C E M E N T */ .left {float: left; margin-right: 20px;} .right {float: right; margin-left: 20px;} .right.inset {margin: 0 120px 0 20px;} /* img floated right within text */ .left.inset {margin-left: 230px;} /* img floated left within text */ /* S I Z E */ .one {width: 100px;} .two {width: 210px;} .three {width: 320px;} .four {width: 430px;} .five {width: 540px;} .six {width: 650px;} .seven {width: 760px;} .eight {width: 870px;} /* A D D I T I O N S */ .frame {border: 1px solid #999;} .solo img {margin-bottom: 20px;} In Use You can already see how powerful this approach can be. If you want an image and a caption on the left to stretch over half of the page, you would use: <div class="pic four left"> <img src="image.jpg" /> <p>Caption goes here.</p> </div> Or, for that same image with a border and no caption: <img src="image.jpg" class="pic four left frame solo"/> You just tack on the classes that contain the qualities you need. And because we’ve kept each class so simple, we can apply these same stylings to other elements too: <p class="caption two left">Caption goes here.</p> Caveats Obviously there are some potential semantic hang-ups with these methods. While classes like pic and caption stem the tide a bit, others like left and right are tougher to justify. This is something that you have to decide for yourself; I’m fine with the occasional four or left class because I think there’s a good tradeoff. Just as a fully semantic solution to this problem would likely be imperfect, this solution is imperfect from the other side of the semantic fence. Additionally, IE6 doesn’t understand the chain of classes within a CSS selector (like .right.inset). If you need to support IE6, you may have to write a few more CSS rules to accommodate any discrepancies. Opportunities This is clearly a simple example, but starting with a modular foundation like this leaves the door open for opportunity. We’ve created a highly flexible and human-readable system for layout manipulation. Obviously, this is something that would need to be tailored to the spacing and sizes of your site, but the systematic approach is very powerful, especially for editorial websites whose articles might have lots of images of varying sizes. It may not get us fully to the flexibility of WYSIWYG print layouts, but methods like this point us in a direction of designs that can adapt to the needs of the content. View the example: without grid and with grid. 2008 Jason Santa Maria jasonsantamaria 2008-12-15T00:00:00+00:00 https://24ways.org/2008/making-modular-layout-systems/ process
279 Design the Invisible to Tell Better Stories on the Web For design to be meaningful we need to tell stories. We need to design the invisible, the cues, the messages and the extra detail hidden beneath the aesthetics. It’s all about the story. From verbal exchanges around the campfire to books, the web and everything in between, storytelling allows us to share, organize and process information more efficiently. It helps us understand our surroundings and make emotional connections to people, places and experiences. Web design lends itself perfectly to the conventions of storytelling, a universal process. However, the stories vary because they’re defined by culture, society, politics and religion. All of which need considering if you are to design stories that are relevant to your target audience. The benefits of approaching design with storytelling in mind from the very start of the project is that we are creating considered design that allows users to quickly gather meaning from the website. They do this by reading between the lines and drawing on the wealth of knowledge they have acquired about the associations between colours, typyefaces and signs. With so much recognition and analysis happening subconsciously you have to consider how design communicates on this level. This invisible layer has a significant impact on what you say, how you say it and who you say it to. How can we design something that’s invisible? By researching and making conscious decisions about exactly what you are communicating, you can make the invisible visible. As is often quoted, good design is like air, you only notice it when it’s bad. So by designing the invisible the aim is to design stories that the audience receive subliminally, so that they go somewhat unnoticed, like good air. Storytelling strands To share these stories through design, you can break it down into several strands. Each strand tells a story on its own, but when combined they may start to tell a different story altogether. These strands are colour, typefaces, branding, tone of voice and symbols. All are literal and visible but the invisible element is the meaning behind them – meaning that you can extract and share. In this article I want to focus on colour, typefaces and tone of voice and on how combining story strands can change the meaning. Colour Let’s start with colour. Red represents emotions such as love but can also signify war. Green is commonly used for all things environmental and purple is a colour that connotes wealth and royalty. These associations between colour and emotion or value have been learned over time and are continually reinforced through media and culture. With this knowledge come expectations from your users. For example, they will expect Valentine’s Day sites to be red and kids’ sites to be bright and colourful. This is true in the same way audiences have expectations of certain genres of film or music. These conventions help savvy audiences decode texts and read between the lines or, rather, to draw meaning from the invisible. It’s practically an innate skill. This is why you need to design the invisible: because users will quickly deduce meaning from your site and fill in the story’s gaps, it’s important to give them as much of that story to begin with. A story relevant to their culture. Of all the ways you can tell stories through web design, colour is the most fascinating and important. Not only does it evoke emotions in users but its meaning varies significantly between cultures. In the west, for example, white is a colour associated with weddings, and black is the colour of mourning. This is signified by the traditions of brides wearing white and those in mourning wearing black. In other cultures the meanings are reversed, as black is a colour that represents good luck and white is a colour that signifies mourning. If you assume the same values are true in all cultures then you risk offending the very people you are targeting. When colours combine, the story being told can change. If you design using red, white and blue then it’s going to be difficult to shake off patriotic connotations because this colour combination is so ingrained as being American or British or French thanks largely to their flags. This extends to politics too. Each party has its own representative colour. In the UK, the Conservatives are blue and Labour is red so it would be inappropriate storytelling to design a Labour-related website in blue as there would be a conflict between the content and the design, a conflict that would result in a poor user experience. Conflicts become more of an issue when you start to combine story strands. I once saw a No VAT advert use the symbol on the left: There’s a complete conflict in storytelling here between the sign and its colour. The prohibition sign was used over the word VAT to mean no VAT; that makes sense. But this is a symbol that is used to communicate to people that something is being prohibited or prevented, it mustn’t continue. So to use green contradicts the message of the sign itself; green is used as a colour to say yes, go, proceed, enter. The same would be true if we had a tick in red and a cross in green. Bad design here means the story is flawed and the user experience is compromised. Typefaces Typefaces also tell stories. They are so much more than the words that are written with them because they connote different values. Here are a few: Serif fonts are more formal and are associated with tradition, sophistication and high-end values. Sans serif fonts, on the other hand, are synonymous with modernity, informality and friendliness. These perceptions are again reinforced through more traditional media such as newspaper mastheads, where the serious news-focused broadsheets have serif titles, and the showbiz and gossip-led tabloids have sans serif titles. This translates to the web as well. With these associations already familiar to users, they may see copy and focus on the words, but if the way that copy is displayed jars with the context then we are back to having conflicting stories like the No VAT sign earlier. Let’s take official institutions, for example. The White House, the monarchy, 10 Downing Street and other government departments are formal, traditional and important organisations. If the copy on their websites were written in a typeface like Cooper Black, it would erase any authority and respect that they were due. They need people to take them seriously and trust them, and part of the way to do this is to have a typeface that represents those values. It works both ways though. If Innocent, Threadless or other fun companies used traditional typefaces, they wouldn’t be accurate reflections of their core values, brand and personality. They are better positioned to use friendly, informal and modern typefaces. But still never Comic Sans. Tone of voice Closely tied to this is tone of voice, my absolute bugbear on the web. Tone of voice isn’t what is said but, rather, how it is said. When we interact with others in person we don’t just listen to the words they say, but we also draw meaning from their body language, and pitch and tone of voice. Just because the web removes that face-to-face interaction with your audience it doesn’t mean you can’t have a tone of voice. Innocent pioneered the informal chatty tone of voice that so many others have since emulated, but unless it is representative of your company, then it’s not appropriate. It works for Innocent because the tone of voice is consistent across all the company’s materials, both online and offline. Ben and Jerry’s takes the same approach, as does Threadless, but maybe you need a more formal or corporate tone of voice. It really depends on what your business or service is and who it is for, and that is why I think LoveFilm has it all wrong. LoveFilm offers a film and game rental service, something fun for people in their downtime. While they aren’t particularly stuffy, neither is their tone of voice very friendly or informal, which is what I would expect from a service like theirs. The reason they have it wrong is in the language they use and the way their sentences are constructed. This is the first time we’ve discussed language because, on the whole, designing the invisible isn’t concerned with language at all. But that doesn’t mean that these strands can’t still elicit an emotional response in users. Jon Tan quoted Dr Mazviita Chirimuuta in his New Adventures in Web Design talk in January 2011: Although there is no absolute separation between language and emotion, there will still be countless instances where you have emotional response without verbal input or linguistic cognition. In general language is not necessary for emotion. This is even more pertinent when the emotions evoked are connected to people’s culture, surroundings and way of life. It makes design personal, something that audiences can connect with at more than just face value but, rather, on a subliminal or, indeed, invisible level. It also means that when you are asked the inevitable question of why – why is blue the dominant colour? why have you used that typeface? why don’t we sound like Innocent? – you will have a rationale behind each design decision that can explain what story you are telling, how you discovered the story and how it is targeted at the core audience. Research This is where research plays a vital role in the project cycle. If you don’t know and understand your audience then you don’t know what story to design. Every project lends itself to some level of research, but how in-depth and what methods are most appropriate will be dictated by project requirements and budget restrictions – but do your research. Even if you think you know your audience, it doesn’t hurt to research and reaffirm that because cultures and society do change, albeit slowly, but they can change. So ask questions at the start of the project during the research phase: What do different colours mean for your audience’s culture? Do the typeface and tone of voice appeal to the demographic? Does the brand identity represent the values and personality of your service? Are there any social, political or religious significances associated with your audience that you need to take into consideration so you don’t offend them? Ask questions, understand your audience, design your story based on these insights, and create better user experiences in context that have good, solid storytelling at their heart. Major hat tip to Gareth Strange for the beautiful graphics used within this article. 2011 Robert Mills robertmills 2011-12-14T00:00:00+00:00 https://24ways.org/2011/design-the-invisible/ design
188 Don't Lose Your :focus For many web designers, accessibility conjures up images of blind users with screenreaders, and the difficulties in making sites accessible to this particular audience. Of course, accessibility covers a wide range of situations that go beyond the extreme example of screenreader users. And while it’s true that making a complex site accessible can often be a daunting prospect, there are also many small things that don’t take anything more than a bit of judicious planning, are very easy to test (without having to buy expensive assistive technology), and can make all the difference to certain user groups. In this short article we’ll focus on keyboard accessibility and how careless use of CSS can potentially make your sites completely unusable. Keyboard Access Users who for whatever reason can’t use a mouse will employ a keyboard (or keyboard-like custom interface) to navigate around web pages. By default, they will use TAB and SHIFT + TAB to move from one focusable element (links, form controls and area) of a page to the next. Note: in OS X, you’ll first need to turn on full keyboard access under System Preferences > Keyboard and Mouse > Keyboard Shortcuts. Safari under Windows needs to have the option Press Tab to highlight each item on a webpage in Preferences > Advanced enabled. Opera is the odd one out, as it has a variety of keyboard navigation options – the most relevant here being spatial navigation via Shift+Down, Shift+Up, Shift+Left, and Shift+Right). But I Don’t Like Your Dotted Lines… To show users where they are within a page, browsers place an outline around the element that currently has focus. The “problem” with these default outlines is that some browsers (Internet Explorer and Firefox) also display them when a user clicks on a focusable element with the mouse. Particularly on sites that make extensive use of image replacement on links with “off left” techniques this can create very unsightly outlines that stretch from the replaced element all the way to the left edge of the browser. Outline bleeding off to the left (image-replacement example from carsonified.com) There is a trivial workaround to prevent outlines from “spilling over” by adding a simple overflow:hidden, which keeps the outline in check around the clickable portion of the image-replaced element itself. Outline tamed with overflow:hidden But for many designers, even this is not enough. As a final solution, many actively suppress outlines altogether in their stylesheets. Controversially, even Eric Meyer’s popular reset.css – an otherwise excellent set of styles that levels the playing field of varying browser defaults – suppresses outlines. html, body, div, span, applet, object, iframe ... { ... outline: 0; ... } /* remember to define focus styles! */ :focus { outline: 0; } Yes, in his explanation (and in the CSS itself) Eric does remind designers to define relevant styles for :focus… but judging by the number of sites that seem to ignore this (and often remove the related comment from the stylesheet altogether), the message doesn’t seem to have sunk in. Anyway… hurrah! No more unsightly dotted lines on our lovely design. But what about keyboard users? Although technically they can still TAB from one element to the next, they now get no default cue as to where they are within the page (one notable exception here is Opera, where the outline is displayed regardless of stylesheets)… and if they’re Safari users, they won’t even get an indication of a link’s target in the status bar, like they would if they hovered over it with the mouse. Only Suppress outline For Mouse Users Is there a way to allow users navigating with the keyboard to retain the standard outline behaviour they’ve come to expect from their browser, while also ensuring that it doesn’t show display for mouse users? Testing some convoluted style combinations After playing with various approaches (see Better CSS outline suppression for more details), the most elegant solution also seemed to be the simplest: don’t remove the outline on :focus, do it on :active instead – after all, :active is the dynamic pseudo-class that deals explicitly with the styles that should be applied when a focusable element is clicked or otherwise activated. a:active { outline: none; } The only minor issues with this method: if a user activates a link and then uses the browser’s back button, the outline becomes visible. Oh, and old versions of Internet Explorer notoriously get confused by the exact meaning of :focus, :hover and :active, so this method fails in IE6 and below. Personally, I can live with both of these. Note: at the last minute before submitting this article, I discovered a fatal flaw in my test. It appears that outline still manages to appear in the time between activating a link and the link target loading (which in hindsight is logical – after activation, the link does indeed receive focus). As my test page only used in-page links, this issue never came up before. The slightly less elegant solution is to also suppress the outline on :hover. a:hover, a:active { outline: none; } In Conclusion Of course, many web designers may argue that they know what’s best, even for their keyboard-using audience. Maybe they’ve removed the default outline and are instead providing some carefully designed :focus styles. If they know for sure that these custom styles are indeed a reliable alternative for their users, more power to them… but, at the risk of sounding like Jakob “blue underlined links” Nielsen, I’d still argue that sometimes the default browser behaviours are best left alone. Complemented, yes (and if you’re already defining some fancy styles for :hover, by all means feel free to also make them display on :focus)… but not suppressed. 2009 Patrick Lauke patricklauke 2009-12-09T00:00:00+00:00 https://24ways.org/2009/dont-lose-your-focus/ code
50 Make a Comic For something slightly different over Christmas, why not step away from your computer and make a comic? Definitely not the author working on a comic in the studio, with the desk displaying some of the things you need to make a comic on paper. Why make a comic? First of all, it’s truly fun and it’s not that difficult. If you’re a designer, you can use skills you already have, so why not take some time to indulge your aesthetic whims and make something for yourself, rather than for a client or your company. And you can use a computer – or not. If you’re an interaction designer, it’s likely you’ve already made a storyboard or flow, or designed some characters for personas. This is a wee jump away from that, to the realm of storytelling and navigating human emotions through characters who may or may not be human. Similar medium and skills, different content. It’s not a client deliverable but something that stands by itself, and you’ve nobody’s criteria to meet except those that exist in your imagination! Thanks to your brain and the alchemy of comics, you can put nearly anything in a sequence and your brain will find a way to make sense of it. Scott McCloud wrote about the non sequitur in comics: “There is a kind of alchemy at work in the space between panels which can help us find meaning or resonance in even the most jarring of combinations.” Here’s an example of a non sequitur from Scott McCloud’s Understanding Comics – the images bear no relation to one another, but since they’re in a sequence our brains do their best to understand it: Once you know this it takes the pressure off somewhat. It’s a fun thing to keep in mind and experiment with in your comics! Materials needed A4 copy/printing paper HB pencil for light drawing Dip pen and waterproof Indian ink Bristol board (or any good quality card with a smooth, durable surface) Step 1: Get ideas You’d be surprised where you can take a small grain of an idea and develop it into an interesting comic. Think about a funny conversation you had, or any irrational fears, habits, dreams or anything else. Just start writing and drawing. Having ideas is hard, I know, but you will get some ideas when you start working. One way to keep track of ideas is to keep a sketch diary, capturing funny conversations and other events you could use in comics later. You might want to just sketch out the whole comic very roughly if that helps. I tend to sketch the story first, but it usually changes drastically during step 2. Step 2: Edit your story using thumbnails How thumbnailing works. Why use thumbnails? You can move them around or get rid of them! Drawings are harder and much slower to edit than words, so you need to draw something very quick and very rough. You don’t have to care about drawing quality at this point. You might already have a drafted comic from the previous step; now you can split each panel up into a thumbnail like the image above. Get an A4 sheet of printing paper and tear it up into squares. A thumbnail equals a comic panel. Start drawing one panel per thumbnail. This way you can move scenes and parts of the story around as you work on the pacing. It’s an extremely useful tip if you want to expand a moment in time or draw out a dialogue, or if you want to just completely cut scenes. Step 3: Plan a layout So you’ve got the story more or less down: you now need to know how they’ll look on the page. Sketch a layout and arrange the thumbnails into the layout. The simplest way to do this is to divide an A4 page into equal panels — say, nine. But if you want, you can be more creative than that. The Gigantic Beard That Was Evil by Stephen Collins is an excellent example of the scope for using page layout creatively. You can really push the form: play with layout, scale, story and what you think of as a comic. Step 4: Draw the comic I recommend drawing on A4 Bristol board paper since it has a smooth surface, can tolerate a lot of rubbing out and holds ink well. You can get it from any art shop. Using your thumbnails for reference, draw the comic lightly using an HB pencil. Don’t make the line so heavy that it can’t be erased (since you’ll ink over the lines later). Step 5: Ink the comic Image before colour was added. You’ve drawn your story. Well done! Now for the fun part. I recommend using a dip pen and some waterproof ink. Why waterproof? If you want, you can add an ink wash later, or even paint it. If you don’t have a dip pen, you could also use any quality pen. Carefully go over your pencilled lines with the pen, working from top left to right and down, to avoid smudging it. It’s unfortunately easy to smudge the ink from the dip pen, so I recommend practising first. You’ve made a comic! Step 6: Adding colour Comics traditionally had a limited colour palette before computers (here’s an in-depth explanation if you’re curious). You can actually do a huge amount with a restricted colour palette. Ellice Weaver’s comics show how very nicely how you can paint your work using a restricted palette. So for the next step, resist the temptation to add ALL THE COLOURS and consider using a limited palette. Once the ink is completely dry, erase the pencilled lines and you’ll be left with a beautiful inked black and white drawing. You could use a computer for this part. You could also photocopy it and paint straight on the copy. If you’re feeling really brave, you could paint straight on the original. But I’d suggest not doing this if it’s your first try at painting! What follows is an extremely basic guide for painting using Photoshop, but there are hundreds of brilliant articles out there and different techniques for digital painting. How to paint your comic using Photoshop Scan the drawing and open it in Photoshop. You can adjust the levels (Image → Adjustments → Levels) to make the lines darker and crisper, and the paper invisible. At this stage, you can erase any smudges or mistakes. With a Wacom tablet, you could even completely redraw parts! Computers are just amazing. Keep the line art as its own layer. Add a new layer on top of the lines, and set the layer state from normal to multiply. This means you can paint your comic without obscuring your lines. Rename the layer something else, so you can keep track. Start blocking in colour. And once you’re happy with that, experiment with adding tone and texture. Christmas comic challenge! Why not challenge yourself to make a short comic over Christmas? If you make one, share it in the comments. Or show me on Twitter — I’d love to see it. Credit: Many of these techniques were learned on the Royal Drawing School’s brilliant ‘Drawing the Graphic Novel’ course. 2015 Rebecca Cottrell rebeccacottrell 2015-12-20T00:00:00+00:00 https://24ways.org/2015/make-a-comic/ design
103 Recession Tips For Web Designers 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’s focus on the rest. I 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’re 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. Bad 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. Thin is in If 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. If the one-person entrepreneur model isn’t you, it’s no problem. Form a virtual agency with colleagues who complement your creative, technical, and business skills. Athletics is a Brooklyn-based multi-disciplinary “art and design collective.” Talk about low overhead: they don’t have a president, a payroll, or a pension plan. But that hasn’t stopped clients like adidas, Nike, MTV, HBO, Disney, DKNY, and Sundance Channel from knocking on their (virtual) doors. Running a traditional business is like securing a political position in Chicago: it costs a fortune. That’s why bad times crush so many companies. But you are a creature of the internets. You don’t 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’t care. Keep it lean: if you can budget your incoming freelance money, you don’t 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.) Getting gigs Web 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’re doing. Best practice: focus the email on wishing them a happy holiday and asking how they’re doing. Let your email signature file tell them you’re 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’s not exactly a sure-fire project getter. The 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?) Don’t be shy about sharing your story, but don’t 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’s About pages, and spend some quality time with Google. Most importantly, go to the meeting knowing how much you don’t 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’t just keep grinding through your Keynote presentation. If 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’re 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. “Nervous” 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’ll listen. Did I mention that? Give it time Securing 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’m 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’s garbage can. As 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’ll be a captain of our industry. And talented people will be emailing to ask you for a job. 2008 Jeffrey Zeldman jeffreyzeldman 2008-12-24T00:00:00+00:00 https://24ways.org/2008/recession-tips-for-web-designers/ business
179 Have a Field Day with HTML5 Forms Forms are usually seen as that obnoxious thing we have to markup and style. I respectfully disagree: forms (on a par with tables) are the most exciting thing we have to work with. Here we’re going to take a look at how to style a beautiful HTML5 form using some advanced CSS and latest CSS3 techniques. I promise you will want to style your own forms after you’ve read this article. Here’s what we’ll be creating: The form. (Icons from Chalkwork Payments) Meaningful markup We’re going to style a simple payment form. There are three main sections on this form: The person’s details The address details The credit card details We are also going to use some of HTML5’s new input types and attributes to create more meaningful fields and use less unnecessary classes and ids: email, for the email field tel, for the telephone field number, for the credit card number and security code required, for required fields placeholder, for the hints within some of the fields autofocus, to put focus on the first input field when the page loads There are a million more new input types and form attributes on HTML5, and you should definitely take a look at what’s new on the W3C website. Hopefully this will give you a good idea of how much more fun form markup can be. A good foundation Each section of the form will be contained within its own fieldset. In the case of the radio buttons for choosing the card type, we will enclose those options in another nested fieldset. We will also be using an ordered list to group each label / input pair. This will provide us with a (kind of) semantic styling hook and it will also make the form easier to read when viewing with no CSS applied: The unstyled form So here’s the markup we are going to be working with: <form id=payment> <fieldset> <legend>Your details</legend> <ol> <li> <label for=name>Name</label> <input id=name name=name type=text placeholder="First and last name" required autofocus> </li> <li> <label for=email>Email</label> <input id=email name=email type=email placeholder="example@domain.com" required> </li> <li> <label for=phone>Phone</label> <input id=phone name=phone type=tel placeholder="Eg. +447500000000" required> </li> </ol> </fieldset> <fieldset> <legend>Delivery address</legend> <ol> <li> <label for=address>Address</label> <textarea id=address name=address rows=5 required></textarea> </li> <li> <label for=postcode>Post code</label> <input id=postcode name=postcode type=text required> </li> <li> <label for=country>Country</label> <input id=country name=country type=text required> </li> </ol> </fieldset> <fieldset> <legend>Card details</legend> <ol> <li> <fieldset> <legend>Card type</legend> <ol> <li> <input id=visa name=cardtype type=radio> <label for=visa>VISA</label> </li> <li> <input id=amex name=cardtype type=radio> <label for=amex>AmEx</label> </li> <li> <input id=mastercard name=cardtype type=radio> <label for=mastercard>Mastercard</label> </li> </ol> </fieldset> </li> <li> <label for=cardnumber>Card number</label> <input id=cardnumber name=cardnumber type=number required> </li> <li> <label for=secure>Security code</label> <input id=secure name=secure type=number required> </li> <li> <label for=namecard>Name on card</label> <input id=namecard name=namecard type=text placeholder="Exact name as on the card" required> </li> </ol> </fieldset> <fieldset> <button type=submit>Buy it!</button> </fieldset> </form> Making things look nice First things first, so let’s start by adding some defaults to our form by resetting the margins and paddings of the elements and adding a default font to the page: html, body, h1, form, fieldset, legend, ol, li { margin: 0; padding: 0; } body { background: #ffffff; color: #111111; font-family: Georgia, "Times New Roman", Times, serif; padding: 20px; } Next we are going to style the form element that is wrapping our fields: form#payment { background: #9cbc2c; -moz-border-radius: 5px; -webkit-border-radius: 5px; border-radius: 5px; padding: 20px; width: 400px; } We will also remove the border from the fieldset and apply some bottom margin to it. Using the :last-of-type pseudo-class, we remove the bottom margin of the last fieldset — there is no need for it: form#payment fieldset { border: none; margin-bottom: 10px; } form#payment fieldset:last-of-type { margin-bottom: 0; } Next we’ll make the legends big and bold, and we will also apply a light-green text-shadow, to add that little extra special detail: form#payment legend { color: #384313; font-size: 16px; font-weight: bold; padding-bottom: 10px; text-shadow: 0 1px 1px #c0d576; } Our legends are looking great, but how about adding a clear indication of how many steps our form has? Instead of adding that manually to every legend, we can use automatically generated counters. To add a counter to an element, we have to use either the :before or :after pseudo-elements to add content via CSS. We will follow these steps: create a counter using the counter-reset property on the form element call the counter with the content property (using the same name we’ve created before) with the counter-incremet property, indicate that for each element that matches our selector, that counter will be increased by 1 form#payment > fieldset > legend:before { content: "Step " counter(fieldsets) ": "; counter-increment: fieldsets; } Finally, we need to change the style of the legend that is part of the radio buttons group, to make it look like a label: form#payment fieldset fieldset legend { color: #111111; font-size: 13px; font-weight: normal; padding-bottom: 0; } Styling the lists For our list elements, we’ll just add some nice rounded corners and semi-transparent border and background. Because we are using RGBa colors, we should provide a fallback for browsers that don’t support them (that comes before the RBGa color). For the nested lists, we will remove these properties because they would be overlapping: form#payment ol li { background: #b9cf6a; background: rgba(255,255,255,.3); border-color: #e3ebc3; border-color: rgba(255,255,255,.6); border-style: solid; border-width: 2px; -moz-border-radius: 5px; -webkit-border-radius: 5px; border-radius: 5px; line-height: 30px; list-style: none; padding: 5px 10px; margin-bottom: 2px; } form#payment ol ol li { background: none; border: none; float: left; } Form controls Now we only need to style our labels, inputs and the button element. All our labels will look the same, with the exception of the one for the radio elements. We will float them to the left and give them a width. For the credit card type labels, we will add an icon as the background, and override some of the properties that aren’t necessary. We will be using the attribute selector to specify the background image for each label — in this case, we use the for attribute of each label. To add an extra user-friendly detail, we’ll add a cursor: pointer to the radio button labels on the :hover state, so the user knows that he can simply click them to select that option. form#payment label { float: left; font-size: 13px; width: 110px; } form#payment fieldset fieldset label { background:none no-repeat left 50%; line-height: 20px; padding: 0 0 0 30px; width: auto; } form#payment label[for=visa] { background-image: url(visa.gif); } form#payment label[for=amex] { background-image: url(amex.gif); } form#payment label[for=mastercard] { background-image: url(mastercard.gif); } form#payment fieldset fieldset label:hover { cursor: pointer; } Almost there! Now onto the input elements. Here we want to match all inputs, except for the radio ones, and the textarea. For that we will use the negation pseudo-class (:not()). With it we can target all input elements except for the ones with type of radio. We will also make sure to add some :focus styles and add the appropriate styling for the radio inputs: form#payment input:not([type=radio]), form#payment textarea { background: #ffffff; border: none; -moz-border-radius: 3px; -webkit-border-radius: 3px; -khtml-border-radius: 3px; border-radius: 3px; font: italic 13px Georgia, "Times New Roman", Times, serif; outline: none; padding: 5px; width: 200px; } form#payment input:not([type=submit]):focus, form#payment textarea:focus { background: #eaeaea; } form#payment input[type=radio] { float: left; margin-right: 5px; } And finally we come to our submit button. To it, we will just add some nice typography and text-shadow, align it to the center of the form and give it some background colors for its different states: form#payment button { background: #384313; border: none; -moz-border-radius: 20px; -webkit-border-radius: 20px; -khtml-border-radius: 20px; border-radius: 20px; color: #ffffff; display: block; font: 18px Georgia, "Times New Roman", Times, serif; letter-spacing: 1px; margin: auto; padding: 7px 25px; text-shadow: 0 1px 1px #000000; text-transform: uppercase; } form#payment button:hover { background: #1e2506; cursor: pointer; } And that’s it! See the completed form. This form will not look the same on every browser. Internet Explorer and Opera don’t support border-radius (at least not for now); the new input types are rendered as just normal inputs on some browsers; and some of the most advanced CSS, like the counter, :last-of-type or text-shadow are not supported on some browsers. But that doesn’t mean you can’t use them right now, and simplify your development process. My gift to you! 2009 Inayaili de León Persson inayailideleon 2009-12-03T00:00:00+00:00 https://24ways.org/2009/have-a-field-day-with-html5-forms/ code
191 CSS Animations Friend: You should learn how to write CSS! Me: … Friend: CSS; Cascading Style Sheets. If you’re serious about web design, that’s the next thing you should learn. Me: What’s wrong with <font> tags? That was 8 years ago. Thanks to the hard work of Jeffrey, Andy, Andy, Cameron, Colly, Dan and many others, learning how to decently markup a website and write lightweight stylesheets was surprisingly easy. They made it so easy even a complete idiot (OH HAI) was able to quickly master it. And then… nothing. For a long time, it seemed like there wasn’t happening anything in the land of CSS, time stood still. Once you knew the basics, there wasn’t anything new to keep up with. It looked like a great band split, but people just kept re-releasing their music in various “Best Of!” or “Remastered!” albums. Fast forward a couple of years to late 2006. On the official WebKit blog Surfin’ Safari, there’s an article about something called CSS animations. Great new stuff to play with, but only supported by nightly builds (read: very, very beta) of WebKit. In the following months, they release other goodies, like CSS gradients, CSS reflections, CSS masks, and even more CSS animation sexiness. Whoa, looks like the band got back together, found their second youth, and went into overdrive! The problem was that if you wanted to listen to their new albums, you had to own some kind of new high-tech player no one on earth (besides some early adopters) owned. Back in the time machine. It is now late 2009, close to Christmas. Things have changed. Browsers supporting these new toys are widely available left and right. Even non-techies are using these advanced browsers to surf the web on a daily basis! Epic win? Almost, but at least this gives us enough reason to start learning how we could use all this new CSS voodoo. On Monday, Natalie Downe showed you a good tutorial on Going Nuts with CSS Transitions. Today, I’m taking it one step further… Howto: A basic spinner No matter how fast internet tubes or servers are, we’ll always need spinners to indicate something’s happening behind the scenes. Up until now, people would go to some site, pick one of the available templates, customize their foreground and background colors, and download a beautiful GIF image. There are some downsides to this though: It’s only _semi_-transparent: If you change your mind and pick a slightly different background color, you need to go back to the site, set all the parameters again, and replace your current image. There isn’t even a way to pick an image or gradient as background. Limited number of frames, probable to keep the file-size as small as possible (don’t forget this thing needs to be loaded before whatever process is finished in the background), and you don’t have that 24 frames per second smoothness. This is just too fucking easy. As a front-end code geek, there must be a “cooler” way to do this! What do we need to make a spinner with CSS animations? One image, and one element on our webpage we can hook on to. Yes, that’s it. I created a simple transparent PNG that looks it might be a spinner, and for the element on the page, I wrote this piece of genius HTML: <p id="spinner">Please wait while we do what we do best.</p> Looks semantic enough to me! Here’s the basic HTML I’m using to position the element in the center of the screen, and make the text inside it disappear: #spinner { position: absolute; top: 50%; left: 50%; margin: -100px 0 0 -100px; height: 200px; width: 200px; text-indent: 250px; white-space: nowrap; overflow: hidden; } Cool, but now we don’t see anything. Let’s pull rabbit number one out of the hat: -webkit-mask-image (accompanied by the previously mentioned transparent PNG image): #spinner { ... -webkit-mask-image: url(../img/spinner.png); } By now you should be feeling like a magician already. Oh, wait, we still have a blank screen, looks like we left something in the hat (tip: not rabbit droppings): #spinner { ... -webkit-mask-image: url(../img/spinner.png); background-color: #000; } Nice! What we’ve done right here is telling the element to clip onto the PNG. It’s a lot like clipping layers in Photoshop. So, spinners, they move, right? Into the hat again, and look what we pull out this time: CSS animations! #spinner { ... -webkit-mask-image: url(../img/spinner.png); background-color: #000; -webkit-animation-name: spinnerRotate; -webkit-animation-duration: 2s; -webkit-animation-iteration-count: infinite; -webkit-animation-timing-function: linear; } Some explanation: -webkit-animation-name: Name of the animation we’ll be defining later. -webkit-animation-duration: The timespan of the animation. -webkit-animation-iteration-count: Repeat once, a defined number of times or infinitely? -webkit-animation-timing-function: Linear is the one you’ll be using mostly. Other options are ease-in, ease-out, ease-in-out… Let’s define spinnerRotate: @-webkit-keyframes spinnerRotate { from { -webkit-transform:rotate(0deg); } to { -webkit-transform:rotate(360deg); } } En Anglais: Rotate #spinner starting at 0 degrees, ending at 360 degrees, over a timespan of 2 seconds, at a constant speed, and keep repeating this animation forever. That’s it! See it in action on the demo page. Note: these examples only work when you’re using a WebKit-based browser like Safari, Mobile Safari or Google Chrome. I’m confident though that Mozilla and Opera will try their very best catching up with all this new CSS goodness soon. When looking at this example, you see the possibilities are endless. Another advantage is you can change the look of it entirely by only changing a couple of lines of CSS, instead of re-creating and re-downloading the image from some website smelling like web 2.0 gone bad. I made another demo that shows how great it is to be able to change background and foreground colors (even on the fly!). So there you have it, a smoothly animated, fully transparent and completely customizable spinner. Cool? I think so. (Ladies?) But you can do a lot more with CSS animations than just create pretty spinners. Since I was fooling around with it anyway, I decided to test how far you can push this, space is the final limit, right? Conclusion CSS has never been more exciting than it is right now. I’m even prepared to say CSS is “cool” again, both for the more experienced front-end developers as for the new designers discovering CSS every day now. But… Remember when Javascript became popular? Remember when Flash became popular? Every time we’re been given new toys, some people aren’t ashamed to use it in a way you can barely call constructive. I’m thinking of Geocities websites, loaded with glowing blocks of text, moving images, bad color usage… In the wise words of Stan Lee: With great power there must also come great responsibility! A sprinkle of CSS animations is better than a bucket load. Apply with care. 2009 Tim Van Damme timvandamme 2009-12-15T00:00:00+00:00 https://24ways.org/2009/css-animations/ code
18 Grunt for People Who Think Things Like Grunt are Weird and Hard Front-end developers are often told to do certain things: Work in as small chunks of CSS and JavaScript as makes sense to you, then concatenate them together for the production website. Compress your CSS and minify your JavaScript to make their file sizes as small as possible for your production website. Optimize your images to reduce their file size without affecting quality. Use Sass for CSS authoring because of all the useful abstraction it allows. That’s not a comprehensive list of course, but those are the kind of things we need to do. You might call them tasks. I bet you’ve heard of Grunt. Well, Grunt is a task runner. Grunt can do all of those things for you. Once you’ve got it set up, which isn’t particularly difficult, those things can happen automatically without you having to think about them again. But let’s face it: Grunt is one of those fancy newfangled things that all the cool kids seem to be using but at first glance feels strange and intimidating. I hear you. This article is for you. Let’s nip some misconceptions in the bud right away Perhaps you’ve heard of Grunt, but haven’t done anything with it. I’m sure that applies to many of you. Maybe one of the following hang-ups applies to you. I don’t need the things Grunt does You probably do, actually. Check out that list up top. Those things aren’t nice-to-haves. They are pretty vital parts of website development these days. If you already do all of them, that’s awesome. Perhaps you use a variety of different tools to accomplish them. Grunt can help bring them under one roof, so to speak. If you don’t already do all of them, you probably should and Grunt can help. Then, once you are doing those, you can keep using Grunt to do more for you, which will basically make you better at doing your job. Grunt runs on Node.js — I don’t know Node You don’t have to know Node. Just like you don’t have to know Ruby to use Sass. Or PHP to use WordPress. Or C++ to use Microsoft Word. I have other ways to do the things Grunt could do for me Are they all organized in one place, configured to run automatically when needed, and shared among every single person working on that project? Unlikely, I’d venture. Grunt is a command line tool — I’m just a designer I’m a designer too. I prefer native apps with graphical interfaces when I can get them. But I don’t think that’s going to happen with Grunt1. The extent to which you need to use the command line is: Navigate to your project’s directory. Type grunt and press Return. After set-up, that is, which again isn’t particularly difficult. OK. Let’s get Grunt installed Node is indeed a prerequisite for Grunt. If you don’t have Node installed, don’t worry, it’s very easy. You literally download an installer and run it. Click the big Install button on the Node website. You install Grunt on a per-project basis. Go to your project’s folder. It needs a file there named package.json at the root level. You can just create one and put it there. package.json at root The contents of that file should be this: { "name": "example-project", "version": "0.1.0", "devDependencies": { "grunt": "~0.4.1" } } Feel free to change the name of the project and the version, but the devDependencies thing needs to be in there just like that. This is how Node does dependencies. Node has a package manager called NPM (Node packaged modules) for managing Node dependencies (like a gem for Ruby if you’re familiar with that). You could even think of it a bit like a plug-in for WordPress. Once that package.json file is in place, go to the terminal and navigate to your folder. Terminal rubes like me do it like this: Terminal rube changing directories Then run the command: npm install After you’ve run that command, a new folder called node_modules will show up in your project. Example of node_modules folder The other files you see there, README.md and LICENSE are there because I’m going to put this project on GitHub and that’s just standard fare there. The last installation step is to install the Grunt CLI (command line interface). That’s what makes the grunt command in the terminal work. Without it, typing grunt will net you a “Command Not Found”-style error. It is a separate installation for efficiency reasons. Otherwise, if you had ten projects you’d have ten copies of Grunt CLI. This is a one-liner again. Just run this command in the terminal: npm install -g grunt-cli You should close and reopen the terminal as well. That’s a generic good practice to make sure things are working right. Kinda like restarting your computer after you install a new application was in the olden days. Let’s make Grunt concatenate some files Perhaps in our project there are three separate JavaScript files: jquery.js – The library we are using. carousel.js – A jQuery plug-in we are using. global.js – Our authored JavaScript file where we configure and call the plug-in. In production, we would concatenate all those files together for performance reasons (one request is better than three). We need to tell Grunt to do this for us. But wait. Grunt actually doesn’t do anything all by itself. Remember Grunt is a task runner. The tasks themselves we will need to add. We actually haven’t set up Grunt to do anything yet, so let’s do that. The official Grunt plug-in for concatenating files is grunt-contrib-concat. You can read about it on GitHub if you want, but all you have to do to use it on your project is to run this command from the terminal (it will henceforth go without saying that you need to run the given commands from your project’s root folder): npm install grunt-contrib-concat --save-dev A neat thing about doing it this way: your package.json file will automatically be updated to include this new dependency. Open it up and check it out. You’ll see a new line: "grunt-contrib-concat": "~0.3.0" Now we’re ready to use it. To use it we need to start configuring Grunt and telling it what to do. You tell Grunt what to do via a configuration file named Gruntfile.js2 Just like our package.json file, our Gruntfile.js has a very special format that must be just right. I wouldn’t worry about what every word of this means. Just check out the format: module.exports = function(grunt) { // 1. All configuration goes here grunt.initConfig({ pkg: grunt.file.readJSON('package.json'), concat: { // 2. Configuration for concatinating files goes here. } }); // 3. Where we tell Grunt we plan to use this plug-in. grunt.loadNpmTasks('grunt-contrib-concat'); // 4. Where we tell Grunt what to do when we type "grunt" into the terminal. grunt.registerTask('default', ['concat']); }; Now we need to create that configuration. The documentation can be overwhelming. Let’s focus just on the very simple usage example. Remember, we have three JavaScript files we’re trying to concatenate. We’ll list file paths to them under src in an array of file paths (as quoted strings) and then we’ll list a destination file as dest. The destination file doesn’t have to exist yet. It will be created when this task runs and squishes all the files together. Both our jquery.js and carousel.js files are libraries. We most likely won’t be touching them. So, for organization, we’ll keep them in a /js/libs/ folder. Our global.js file is where we write our own code, so that will be right in the /js/ folder. Now let’s tell Grunt to find all those files and squish them together into a single file named production.js, named that way to indicate it is for use on our real live website. concat: { dist: { src: [ 'js/libs/*.js', // All JS in the libs folder 'js/global.js' // This specific file ], dest: 'js/build/production.js', } } Note: throughout this article there will be little chunks of configuration code like above. The intention is to focus in on the important bits, but it can be confusing at first to see how a particular chunk fits into the larger file. If you ever get confused and need more context, refer to the complete file. With that concat configuration in place, head over to the terminal, run the command: grunt and watch it happen! production.js will be created and will be a perfect concatenation of our three files. This was a big aha! moment for me. Feel the power course through your veins. Let’s do more things! Let’s make Grunt minify that JavaScript We have so much prep work done now, adding new tasks for Grunt to run is relatively easy. We just need to: Find a Grunt plug-in to do what we want Learn the configuration style of that plug-in Write that configuration to work with our project The official plug-in for minifying code is grunt-contrib-uglify. Just like we did last time, we just run an NPM command to install it: npm install grunt-contrib-uglify --save-dev Then we alter our Gruntfile.js to load the plug-in: grunt.loadNpmTasks('grunt-contrib-uglify'); Then we configure it: uglify: { build: { src: 'js/build/production.js', dest: 'js/build/production.min.js' } } Let’s update that default task to also run minification: grunt.registerTask('default', ['concat', 'uglify']); Super-similar to the concatenation set-up, right? Run grunt at the terminal and you’ll get some deliciously minified JavaScript: Minified JavaScript That production.min.js file is what we would load up for use in our index.html file. Let’s make Grunt optimize our images We’ve got this down pat now. Let’s just go through the motions. The official image minification plug-in for Grunt is grunt-contrib-imagemin. Install it: npm install grunt-contrib-imagemin --save-dev Register it in the Gruntfile.js: grunt.loadNpmTasks('grunt-contrib-imagemin'); Configure it: imagemin: { dynamic: { files: [{ expand: true, cwd: 'images/', src: ['**/*.{png,jpg,gif}'], dest: 'images/build/' }] } } Make sure it runs: grunt.registerTask('default', ['concat', 'uglify', 'imagemin']); Run grunt and watch that gorgeous squishification happen: Squished images Gotta love performance increases for nearly zero effort. Let’s get a little bit smarter and automate What we’ve done so far is awesome and incredibly useful. But there are a couple of things we can get smarter on and make things easier on ourselves, as well as Grunt: Run these tasks automatically when they should Run only the tasks needed at the time For instance: Concatenate and minify JavaScript when JavaScript changes Optimize images when a new image is added or an existing one changes We can do this by watching files. We can tell Grunt to keep an eye out for changes to specific places and, when changes happen in those places, run specific tasks. Watching happens through the official grunt-contrib-watch plugin. I’ll let you install it. It is exactly the same process as the last few plug-ins we installed. We configure it by giving watch specific files (or folders, or both) to watch. By watch, I mean monitor for file changes, file deletions or file additions. Then we tell it what tasks we want to run when it detects a change. We want to run our concatenation and minification when anything in the /js/ folder changes. When it does, we should run the JavaScript-related tasks. And when things happen elsewhere, we should not run the JavaScript-related tasks, because that would be irrelevant. So: watch: { scripts: { files: ['js/*.js'], tasks: ['concat', 'uglify'], options: { spawn: false, }, } } Feels pretty comfortable at this point, hey? The only weird bit there is the spawn thing. And you know what? I don’t even really know what that does. From what I understand from the documentation it is the smart default. That’s real-world development. Just leave it alone if it’s working and if it’s not, learn more. Note: Isn’t it frustrating when something that looks so easy in a tutorial doesn’t seem to work for you? If you can’t get Grunt to run after making a change, it’s very likely to be a syntax error in your Gruntfile.js. That might look like this in the terminal: Errors running Grunt Usually Grunt is pretty good about letting you know what happened, so be sure to read the error message. In this case, a syntax error in the form of a missing comma foiled me. Adding the comma allowed it to run. Let’s make Grunt do our preprocessing The last thing on our list from the top of the article is using Sass — yet another task Grunt is well-suited to run for us. But wait? Isn’t Sass technically in Ruby? Indeed it is. There is a version of Sass that will run in Node and thus not add an additional dependency to our project, but it’s not quite up-to-snuff with the main Ruby project. So, we’ll use the official grunt-contrib-sass plug-in which just assumes you have Sass installed on your machine. If you don’t, follow the command line instructions. What’s neat about Sass is that it can do concatenation and minification all by itself. So for our little project we can just have it compile our main global.scss file: sass: { dist: { options: { style: 'compressed' }, files: { 'css/build/global.css': 'css/global.scss' } } } We wouldn’t want to manually run this task. We already have the watch plug-in installed, so let’s use it! Within the watch configuration, we’ll add another subtask: css: { files: ['css/*.scss'], tasks: ['sass'], options: { spawn: false, } } That’ll do it. Now, every time we change any of our Sass files, the CSS will automaticaly be updated. Let’s take this one step further (it’s absolutely worth it) and add LiveReload. With LiveReload, you won’t have to go back to your browser and refresh the page. Page refreshes happen automatically and in the case of CSS, new styles are injected without a page refresh (handy for heavily state-based websites). It’s very easy to set up, since the LiveReload ability is built into the watch plug-in. We just need to: Install the browser plug-in Add to the top of the watch configuration: . watch: { options: { livereload: true, }, scripts: { /* etc */ Restart the browser and click the LiveReload icon to activate it. Update some Sass and watch it change the page automatically. Live reloading browser Yum. Prefer a video? If you’re the type that likes to learn by watching, I’ve made a screencast to accompany this article that I’ve published over on CSS-Tricks: First Moments with Grunt Leveling up As you might imagine, there is a lot of leveling up you can do with your build process. It surely could be a full time job in some organizations. Some hardcore devops nerds might scoff at the simplistic setup we have going here. But I’d advise them to slow their roll. Even what we have done so far is tremendously valuable. And don’t forget this is all free and open source, which is amazing. You might level up by adding more useful tasks: Running your CSS through Autoprefixer (A+ Would recommend) instead of a preprocessor add-ons. Writing and running JavaScript unit tests (example: Jasmine). Build your image sprites and SVG icons automatically (example: Grunticon). Start a server, so you can link to assets with proper file paths and use services that require a real URL like TypeKit and such, as well as remove the need for other tools that do this, like MAMP. Check for code problems with HTML-Inspector, CSS Lint, or JS Hint. Have new CSS be automatically injected into the browser when it ever changes. Help you commit or push to a version control repository like GitHub. Add version numbers to your assets (cache busting). Help you deploy to a staging or production environment (example: DPLOY). You might level up by simply understanding more about Grunt itself: Read Grunt Boilerplate by Mark McDonnell. Read Grunt Tips and Tricks by Nicolas Bevacqua. Organize your Gruntfile.js by splitting it up into smaller files. Check out other people’s and projects’ Gruntfile.js. Learn more about Grunt by digging into its source and learning about its API. Let’s share I think some group sharing would be a nice way to wrap this up. If you are installing Grunt for the first time (or remember doing that), be especially mindful of little frustrating things you experience(d) but work(ed) through. Those are the things we should share in the comments here. That way we have this safe place and useful resource for working through those confusing moments without the embarrassment. We’re all in this thing together! 1 Maybe someday someone will make a beautiful Grunt app for your operating system of choice. But I’m not sure that day will come. The configuration of the plug-ins is the important part of using Grunt. Each plug-in is a bit different, depending on what it does. That means a uniquely considered UI for every single plug-in, which is a long shot. Perhaps a decent middleground is this Grunt DevTools Chrome add-on. 2 Gruntfile.js is often referred to as Gruntfile in documentation and examples. Don’t literally name it Gruntfile — it won’t work. 2013 Chris Coyier chriscoyier 2013-12-11T00:00:00+00:00 https://24ways.org/2013/grunt-is-not-weird-and-hard/ code
276 Your jQuery: Now With 67% Less Suck Fun fact: more websites are now using jQuery than Flash. jQuery is an amazing tool that’s made JavaScript accessible to developers and designers of all levels of experience. However, as Spiderman taught us, “with great power comes great responsibility.” The unfortunate downside to jQuery is that while it makes it easy to write JavaScript, it makes it easy to write really really f*&#ing bad JavaScript. Scripts that slow down page load, unresponsive user interfaces, and spaghetti code knotted so deep that it should come with a bottle of whiskey for the next sucker developer that has to work on it. This becomes more important for those of us who have yet to move into the magical fairy wonderland where none of our clients or users view our pages in Internet Explorer. The IE JavaScript engine moves at the speed of an advancing glacier compared to more modern browsers, so optimizing our code for performance takes on an even higher level of urgency. Thankfully, there are a few very simple things anyone can add into their jQuery workflow that can clear up a lot of basic problems. When undertaking code reviews, three of the areas where I consistently see the biggest problems are: inefficient selectors; poor event delegation; and clunky DOM manipulation. We’ll tackle all three of these and hopefully you’ll walk away with some new jQuery batarangs to toss around in your next project. Selector optimization Selector speed: fast or slow? Saying that the power behind jQuery comes from its ability to select DOM elements and act on them is like saying that Photoshop is a really good tool for selecting pixels on screen and making them change color – it’s a bit of a gross oversimplification, but the fact remains that jQuery gives us a ton of ways to choose which element or elements in a page we want to work with. However, a surprising number of web developers are unaware that all selectors are not created equal; in fact, it’s incredible just how drastic the performance difference can be between two selectors that, at first glance, appear nearly identical. For instance, consider these two ways of selecting all paragraph tags inside a <div> with an ID. $("#id p"); $("#id").find("p"); Would it surprise you to learn that the second way can be more than twice as fast as the first? Knowing which selectors outperform others (and why) is a pretty key building block in making sure your code runs well and doesn’t frustrate your users waiting for things to happen. There are many different ways to select elements using jQuery, but the most common ways can be basically broken down into five different methods. In order, roughly, from fastest to slowest, these are: $("#id"); This is without a doubt the fastest selector jQuery provides because it maps directly to the native document.getElementbyId() JavaScript method. If possible, the selectors listed below should be prefaced with an ID selector in conjunction with jQuery’s .find() method to limit the scope of the page that has to be searched (as in the $("#id").find("p") example shown above). $("p");, $("input");, $("form"); and so on Selecting elements by tag name is also fast, since it maps directly to the native document.getElementsByTagname() method. $(".class"); Selecting by class name is a little trickier. While still performing very well in modern browsers, it can cause some pretty significant slowdowns in IE8 and below. Why? IE9 was the first IE version to support the native document.getElementsByClassName() JavaScript method. Older browsers have to resort to using much slower DOM-scraping methods that can really impact performance. $("[attribute=value]"); There is no native JavaScript method for this selector to use, so the only way that jQuery can perform the search is by crawling the entire DOM looking for matches. Modern browsers that support the querySelectorAll() method will perform better in certain cases (Opera, especially, runs these searches much faster than any other browser) but, generally speaking, this type of selector is Slowey McSlowersons. $(":hidden"); Like attribute selectors, there is no native JavaScript method for this one to use. Pseudo-selectors can be painfully slow since the selector has to be run against every element in your search space. Again, modern browsers with querySelectorAll() will perform slightly better here, but try to avoid these if at all possible. If you must use one, try to limit the search space to a specific portion of the page: $("#list").find(":hidden"); But, hey, proof is in the performance testing, right? It just so happens that said proof is sitting right here. Be sure to notice the class selector numbers beside IE7 and 8 compared to other browsers and then wonder how the people on the IE team at Microsoft manage to sleep at night. Yikes. Chaining Almost all jQuery methods return a jQuery object. This means that when a method is run, its results are returned and you can continue executing more methods on them. Rather than writing out the same selector multiple times over, just making a selection once allows multiple actions to be run on it. Without chaining $("#object").addClass("active"); $("#object").css("color","#f0f"); $("#object").height(300); With chaining $("#object").addClass("active").css("color", "#f0f").height(300); This has the dual effect of making your code shorter and faster. Chained methods will be slightly faster than multiple methods made on a cached selector, and both ways will be much faster than multiple methods made on non-cached selectors. Wait… “cached selector”? What is this new devilry? Caching Another easy way to speed up your code that seems to be a mystery to developers is the idea of caching your selectors. Think of how many times you end up writing the same selector over and over again in any project. Every $(".element") selector has to search the entire DOM each time, regardless of whether or not that selector had been previously run. Running the selection once and then storing the results in a variable means that the DOM only has to be searched once. Once the results of a selector have been cached, you can do anything with them. First, run your search (here we’re selecting all of the <li> elements inside <ul id="blocks">): var blocks = $("#blocks").find("li"); Now, you can use the blocks variable wherever you want without having to search the DOM every time. $("#hideBlocks").click(function() { blocks.fadeOut(); }); $("#showBlocks").click(function() { blocks.fadeIn(); }); My advice? Any selector that gets run more than once should be cached. This jsperf test shows just how much faster a cached selector runs compared to a non-cached one (and even throws some chaining love in to boot). Event delegation Event listeners cost memory. In complex websites and apps it’s not uncommon to have a lot of event listeners floating around, and thankfully jQuery provides some really easy methods for handling event listeners efficiently through delegation. In a bit of an extreme example, imagine a situation where a 10×10 cell table needs to have an event listener on each cell; let’s say that clicking on a cell adds or removes a class that defines the cell’s background color. A typical way that this might be written (and something I’ve often seen during code reviews) is like so: $('table').find('td').click(function() { $(this).toggleClass('active'); }); jQuery 1.7 has provided us with a new event listener method, .on(). It acts as a utility that wraps all of jQuery’s previous event listeners into one convenient method, and the way you write it determines how it behaves. To rewrite the above .click() example using .on(), we’d simply do the following: $('table').find('td').on('click',function() { $(this).toggleClass('active'); }); Simple enough, right? Sure, but the problem here is that we’re still binding one hundred event listeners to our page, one to each individual table cell. A far better way to do things is to create one event listener on the table itself that listens for events inside it. Since the majority of events bubble up the DOM tree, we can bind a single event listener to one element (in this case, the <table>) and wait for events to bubble up from its children. The way to do this using the .on() method requires only one change from our code above: $('table').on('click','td',function() { $(this).toggleClass('active'); }); All we’ve done is moved the td selector to an argument inside the .on() method. Providing a selector to .on() switches it into delegation mode, and the event is only fired for descendants of the bound element (table) that match the selector (td). With that one simple change, we’ve gone from having to bind one hundred event listeners to just one. You might think that the browser having to do one hundred times less work would be a good thing and you’d be completely right. The difference between the two examples above is staggering. (Note that if your site is using a version of jQuery earlier than 1.7, you can accomplish the very same thing using the .delegate() method. The syntax of how you write the function differs slightly; if you’ve never used it before, it’s worth checking the API docs for that page to see how it works.) DOM manipulation jQuery makes it very easy to manipulate the DOM. It’s trivial to create new nodes, insert them, remove other ones, move things around, and so on. While the code to do this is simple to write, every time the DOM is manipulated, the browser has to repaint and reflow content which can be extremely costly. This is no more evident than in a long loop, whether it be a standard for() loop, while() loop, or jQuery $.each() loop. In this case, let’s say we’ve just received an array full of image URLs from a database or Ajax call or wherever, and we want to put all of those images in an unordered list. Commonly, you’ll see code like this to pull this off: var arr = [reallyLongArrayOfImageURLs]; $.each(arr, function(count, item) { var newImg = '<li><img src="'+item+'"></li>'; $('#imgList').append(newImg); }); There are a couple of problems with this. For one (which you should have already noticed if you’ve read the earlier part of this article), we’re making the $("#imgList") selection once for each iteration of our loop. The other problem here is that each time the loop iterates, it’s adding a new <li> to the DOM. Each of those insertions is going to be costly, and if our array is quite large then this could lead to a massive slowdown or even the dreaded ‘A script is causing this page to run slowly’ warning. var arr = [reallyLongArrayOfImageURLs], tmp = ''; $.each(arr, function(count, item) { tmp += '<li><img src="'+item+'"></li>'; }); $('#imgList').append(tmp); All we’ve done here is create a tmp variable that each <li> is added to as it’s created. Once our loop has finished iterating, that tmp variable will contain all of our list items in memory, and can be appended to our <ul> all in one go. Browsers work much faster when working with objects in memory rather than on screen, so this is a much faster, more CPU-cycle-friendly method of building a list. Wrapping up These are far from being the only ways to make your jQuery code run better, but they are among the simplest ones to implement. Though each individual change may only make a few milliseconds of difference, it doesn’t take long for those milliseconds to add up. Studies have shown that the human eye can discern delays of as few as 100ms, so simply making a few changes sprinkled throughout your code can very easily have a noticeable effect on how well your website or app performs. Do you have other jQuery optimization tips to share? Leave them in the comments and help make us all better. Now go forth and make awesome! 2011 Scott Kosman scottkosman 2011-12-13T00:00:00+00:00 https://24ways.org/2011/your-jquery-now-with-less-suck/ code
322 Introduction to Scriptaculous Effects Gather around kids, because this year, much like in that James Bond movie with Denise Richards, Christmas is coming early… in the shape of scrumptuous smooth javascript driven effects at your every whim. Now what I’m going to do, is take things down a notch. Which is to say, you don’t need to know much beyond how to open a text file and edit it to follow this article. Personally, I for instance can’t code to save my life. Well, strictly speaking, that’s not entirely true. If my life was on the line, and the code needed was really simple and I wasn’t under any time constraints, then yeah maybe I could hack my way out of it But my point is this: I’m not a programmer in the traditional sense of the word. In fact, what I do best, is scrounge code off of other people, take it apart and then put it back together with duct tape, chewing gum and dumb blind luck. No, don’t run! That happens to be a good thing in this case. You see, we’re going to be implementing some really snazzy effects (which are considerably more relevant than most people are willing to admit) on your site, and we’re going to do it with the aid of Thomas Fuchs’ amazing Script.aculo.us library. And it will be like stealing candy from a child. What Are We Doing? I’m going to show you the very basics of implementing the Script.aculo.us javascript library’s Combination Effects. These allow you to fade elements on your site in or out, slide them up and down and so on. Why Use Effects at All? Before get started though, let me just take a moment to explain how I came to see smooth transitions as something more than smoke and mirror-like effects included for with little more motive than to dazzle and make parents go ‘uuh, snazzy’. Earlier this year, I had the good fortune of meeting the kind, gentle and quite knowledgable Matt Webb at a conference here in Copenhagen where we were both speaking (though I will be the first to admit my little talk on Open Source Design was vastly inferior to Matt’s talk). Matt held a talk called Fixing Broken Windows (based on the Broken Windows theory), which really made an impression on me, and which I have since then referred back to several times. You can listen to it yourself, as it’s available from Archive.org. Though since Matt’s session uses many visual examples, you’ll have to rely on your imagination for some of the examples he runs through during it. Also, I think it looses audio for a few seconds every once in a while. Anyway, one of the things Matt talked a lot about, was how our eyes are wired to react to movement. The world doesn’t flickr. It doesn’t disappear or suddenly change and force us to look for the change. Things move smoothly in the real world. They do not pop up. How it Works Once the necessary files have been included, you trigger an effect by pointing it at the ID of an element. Simple as that. Implementing the Effects So now you know why I believe these effects have a place in your site, and that’s half the battle. Because you see, actually getting these effects up and running, is deceptively simple. First, go and download the latest version of the library (as of this writing, it’s version 1.5 rc5). Unzip itand open it up. Now we’re going to bypass the instructions in the readme file. Script.aculo.us can do a bunch of quite advanced things, but all we really want from it is its effects. And by sidestepping the rest of the features, we can shave off roughly 80KB of unnecessary javascript, which is well worth it if you ask me. As with Drew’s article on Easy Ajax with Prototype, script.aculo.us also uses the Prototype framework by Sam Stephenson. But contrary to Drew’s article, you don’t have to download Prototype, as a version comes bundled with script.aculo.us (though feel free to upgrade to the latest version if you so please). So in the unzipped folder, containing the script.aculo.us files and folder, go into ‘lib’ and grab the ‘prototype.js’ file. Move it to whereever you want to store the javascript files. Then fetch the ‘effects.js’ file from the ‘src’ folder and put it in the same place. To make things even easier for you to get this up and running, I have prepared a small javascript snippet which does some checking to see what you’re trying to do. The script.aculo.us effects are all either ‘turn this off’ or ‘turn this on’. What this snippet does, is check to see what state the target currently has (is it on or off?) and then use the necessary effect. You can either skip to the end and download the example code, or copy and paste this code into a file manually (I’ll refer to that file as combo.js): Effect.OpenUp = function(element) { element = $(element); new Effect.BlindDown(element, arguments[1] || {}); } Effect.CloseDown = function(element) { element = $(element); new Effect.BlindUp(element, arguments[1] || {}); } Effect.Combo = function(element) { element = $(element); if(element.style.display == 'none') { new Effect.OpenUp(element, arguments[1] || {}); }else { new Effect.CloseDown(element, arguments[1] || {}); } } Currently, this code uses the BlindUp and BlindDown code, which I personally like, but there’s nothing wrong with you changing the effect-type into one of the other effects available. Now, include the three files in the header of your code, like so: <script src="prototype.js" type="text/javascript"></script> <script src="effects.js" type="text/javascript"></script> <script src="combo.js" type="text/javascript"></script> Now insert the element you want to use the effect on, like so: <div id="content" style="display: none;">Lorem ipsum dolor sit amet.</div> The above element will start out invisible, and when triggered will be revealed. If you want it to start visible, simply remove the style parameter. And now for the trigger <a href="javascript:Effect.Combo('content');">Click Here</a> And that, is pretty much it. Clicking the link should unfold the DIV targeted by the effect, in this case ‘content’. Effect Options Now, it gets a bit long-haired though. The documentation for script.aculo.us is next to non-existing, and because of that you’ll have to do some digging yourself to appreciate the full potentialof these effects. First of all, what kind of effects are available? Well you can go to the demo page and check them out, or you can open the ‘effects.js’ file and have a look around, something I recommend doing regardlessly, to gain an overview of what exactly you’re dealing with. If you dissect it for long enough, you can even distill some of the options available for the various effects. In the case of the BlindUp and BlindDown effect, which we’re using in our example (as triggered from combo.js), one of the things that would be interesting to play with would be the duration of the effect. If it’s too long, it will feel slow and unresponsive. Too fast and it will be imperceptible. You set the options like so: <a href="javascript:Effect.Combo('content', {duration: .2});">Click Here</a> The change from the previous link being the inclusion of , {duration: .2}. In this case, I have lowered the duration to 0.2 second, to really make it feel snappy. You can also go all-out and turn on all the bells and whistles of the Blind effect like so (slowed down to a duration of three seconds so you can see what’s going on): <a href="javascript:Effect.Combo('content', {duration: 3, scaleX: true, scaleContent: true});">Click Here</a> Conclusion And that’s pretty much it. The rest is a matter of getting to know the rest of the effects and their options as well as finding out just when and where to use them. Remember the ancient Chinese saying: Less is more. Download Example I have prepared a very basic example, which you can download and use as a reference point. 2005 Michael Heilemann michaelheilemann 2005-12-12T00:00:00+00:00 https://24ways.org/2005/introduction-to-scriptaculous-effects/ code
169 Incite A Riot 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’t have explicit HTML elements for those patterns. Suppose we want to mark up a short conversation: Alice: I think Eve is watching. Bob: This isn’t a cryptography tutorial …we’re in the wrong example! A note in the the HTML 4.01 spec says it’s okay to use a definition list: Another application of DL, for example, is for marking up dialogues, with each DT naming a speaker, and each DD containing his or her words. That would give us: <dl> <dt>Alice</dt>: <dd>I think Eve is watching.</dd> <dt>Bob</dt>: <dd>This isn't a cryptography tutorial ...we're in the wrong example!</dd> </dl> This usage of a definition list is proof that writing W3C specifications and smoking crack are not mutually exclusive activities. “I think Eve is watching” is not a definition of “Alice.” If you (ab)use a definition list in this way, Norm will hunt you down. The conversation problem was revisited in HTML5. What if dt and dd didn’t always mean “definition title” and “definition description”? A new element was forged: dialog. Now the the “d” in dt and dd doesn’t stand for “definition”, it stands for “dialog” (or “dialogue” if you can spell): <dialog> <dt>Alice</dt>: <dd>I think Eve is watching.</dd> <dt>Bob</dt>: <dd>This isn't a cryptography tutorial ...we're in the wrong example!</dd> </dialog> Problem solved …except 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—it starts with a “d”) and figure (…um). At the same time as the content model of details and figure were being updated, the completely-unrelated dialog element was dropped. Back to the drawing board, or in this case, the HTML 4.01 specification. The spec defines the cite element thusly: Contains a citation or a reference to other sources. Perfect! There’s even an example showing how this can applied when attributing quotes to people: As <CITE>Harry S. Truman</CITE> said, <Q lang="en-us">The buck stops here.</Q> For 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: <ol> <li><cite>Alice</cite>: <q>I think Eve is watching.</q></li> <li><cite>Bob</cite>: <q>This isn't a cryptography tutorial ...we're in the wrong example!</q></li> </ol> Problem solved …except that the cite element has been redefined in the HTML5 spec: The cite element represents the title of a work … A person’s name is not the title of a work … and the element must therefore not be used to mark up people’s names. HTML5 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: Given that: titles of works are often italicised and given that: people’s names are not often italicised and given that: most browsers italicise the contents of the cite element, therefore: the cite element should not be used to mark up people’s names. In other words, the default browser styling is now dictating semantic meaning. The tail is wagging the dog. Not to worry, the HTML5 spec tells us how we can mark up names in conversations without using the cite element: In some cases, the b element might be appropriate for names I believe the colloquial response to this is a combination of the letters W, T and F, followed by a question mark. The non-normative note continues: In other cases, if an element is really needed, the span element can be used. This is not a joke. We are seriously being told to use semantically meaningless elements to mark up content that is semantically meaningful. We don’t have to take it. Firstly, any conformance checker—that’s the new politically correct term for “validator”—cannot possibly check every instance of the cite element to see if it’s 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. Secondly, 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: In case of conflict, consider users over authors over implementors over specifiers over theoretical purity. That places us—authors—above browser makers. If we resolutely refuse to implement part of the HTML5 spec, then the spec becomes fiction. Join 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’s ensure that bad advice remains fictitious. Tantek has set up a page on the WHATWG wiki to document usage of the cite element for conversations. Please contribute to it. 2009 Jeremy Keith jeremykeith 2009-12-11T00:00:00+00:00 https://24ways.org/2009/incite-a-riot/ code
225 Good Ideas Grow on Paper Great designers have one thing in common: their design process is centred on ideas; ideas that are more often than not developed on paper. Though it’s often tempting to take the path of least resistance, turning to the computer in the headlong rush to complete a project (often in the face of formidable client pressure), resist the urge and – for a truly great idea – start first on paper. The path of least resistance is often characterised by cliché and overused techniques – one per cent noise, border-radius, text-shadow – the usual suspects – techniques that are ten-a-penny at the gallery sites. Whilst all are useful, and technique and craft are important, great design isn’t about technique alone – it’s about technique in the service of good ideas. But how do we generate those ideas? Inspiration can certainly come to you out of the blue. When working as a designer in a role which often consists of incubating good ideas, however, idly waiting for the time-honoured lightbulb to appear above your head just isn’t good enough. We need to establish an environment where we tip the odds of getting good ideas in our favour. So, when faced with the blank canvas, what do we do to unlock the proverbial tidal wave of creativity? Fear not. We’re about to share with you a couple of stalwart techniques that will stand you in good stead when you need that good idea, in the face of the pressure of yet another looming deadline. Get the process right Where do ideas come from? In many cases they come from anywhere but the screen. Hence, our first commandment is to close the lid of your computer and, for a change, work on paper. It might seem strange, it might also seem like a distraction, but – trust us – the time invested here will more than pay off. Idea generation should be a process of rapid iteration, sketching and thinking aloud, all processes best undertaken in more fast paced, analogue media. Our tool of choice is the Sharpie and Flip Chart Combo©, intentionally low resolution to encourage lo-fi idea generation. In short, your tools should be designed not to be precious, but to quickly process your thoughts. Ideas can be expressed with a thick line marker or by drawing with a stick in the sand; it’s the ideas that matter, not the medium. Input > Synthesise > Output Ideas don’t materialise in a vacuum. Without constant input, the outputs will inevitably remain the same. As such, it’s essential to maintain an inquisitive mind, ensuring a steady flow of new triggers and stimuli that enable your thinking to evolve. What every designer brings to the table is their prior experience and unique knowledge. It should come as no surprise to discover that a tried and tested method of increasing that knowledge is, believe it or not, to read – often and widely. The best and most nuanced ideas come after many years of priming the brain with an array of diverse material, a point made recently in Jessica Hische’s aptly named Why You Should Know Your Shit. One of the best ways of synthesising the knowledge you accumulate is to write. The act of writing facilitates your thinking and stores the pieces of the jigsaw you’ll one day return to. You don’t have to write a book or a well-articulated article; a scribbled note in the margin will suffice in facilitating the process of digestion. As with writing, we implore you to make sketching an essential part of your digestion process. More immediate than writing, sketching has the power to put yet unformed ideas down on paper, giving you an insight into the fantastic conceptions you’re more often than not still incubating. Our second commandment is a practical one: always carry a sketchbook and a pen. Although it seems that the very best ideas are scribbled on the back of a beer mat or a wine-stained napkin, always carrying your ‘thinking utensils’ should be as natural as not leaving the house without your phone, wallet, keys or pants. Further, the more you use your sketchbook, the less precious you’ll find yourself becoming. Sketching isn’t about being an excellent draughtsman, it’s about synthesising and processing your thoughts and ideas, as Jason Santa Maria summarises nicely in his article Pretty Sketchy: Sketchbooks are not about being a good artist, they’re about being a good thinker. Jason Santa Maria The sketchbook and pen should become your trusted tools in your task to constantly survey the world around you. As Paul Smith says, You Can Find Inspiration in Anything; close the lid, look beyond the computer; there’s a whole world of inspiration out there. Learn to love old dusty buildings So, how do you learn? How do you push beyond the predictable world pre-filtered by Mr Google? The answer lies in establishing a habit of exploring the wonderful worlds of museums and libraries, dusty old buildings that repay repeated visits. Once the primary repositories of thought and endless sources of inspiration, these institutions are now often passed over for the quick fix of a Google search or Wikipedia by you, the designer, chained to a desk and manacled to a MacBook. Whilst others might frown, we urge you to get away from your desk and take an eye-opening stroll through the knowledge-filled corridors of yore (and don’t forget to bring your sketchbook). Here you’ll find ideas aplenty, ideas that will set you apart from your peers, who remain ever-reliant on the same old digital sources. The idea generation toolbox Now that we’ve established the importance of getting the process and the context right, it’s time to meet the idea generation toolbox: a series of tools and techniques that can be applied singularly or in combination to solve the perennial problem of the blank canvas. The clean sheet of paper, numbing in its emptiness, can prove an insurmountable barrier to many a project, but the route beyond it involves just a few, well-considered steps. The route to a good idea lies in widening your pool of inspiration at the project outset. Let go and generate ideas quickly; it’s critical to diverge before you converge – but how do we do this and what exactly do we mean by this? The temptation is to pull something out of your well-worn box of tricks, something that you know from experience will do the job. We urge you, however, not to fall prey to this desire. You can do better; better still, a few of you putting your minds together can do a lot better. By avoiding the path of least resistance, you can create something extraordinary. Culturally, we value logical, linear thinking. Since the days of Plato and Aristotle, critical thinking, deduction and the pursuit of truth have been rewarded. To generate creative ideas, however, we need to start thinking sideways, making connections that don’t necessarily follow logically. Lateral thinking, a phrase coined by Edward de Bono in 1967, aptly describes this very process: With logic you start out with certain ingredients, just as in playing chess you start out with given pieces – lateral thinking is concerned not with playing with the existing pieces but with seeking to change those very pieces. Edward de Bono One of the easiest ways to start thinking laterally is to start with a mind map, a perfect tool for widening the scope of a project beyond the predictable and an ideal one for getting the context right for discovery. Making connections Mind maps can be used to generate, visualise and structure ideas. Arranged intuitively and classified around groupings, mind maps allow chance connections to be drawn across related groups of information, and are perfect for exposing alogical associations and unexpected relationships. Get a number of people together in a room, equipped with the Sharpie and Flip Chart Combo©. Give yourself a limited amount of time – half an hour should prove more than enough – and you’ll be surprised at the results a few well-chosen people can generate in a very short space of time. The key is to work fast, diverge and not inhibit thinking. We’ve been embracing Tony Buzan’s methods in our teaching for over a decade. His ideas on the power of radiant thinking and how this can be applied to mind maps, uncover the real power which lies in the human brain’s ability to spot connections across a mapped out body of diverse knowledge. Frank Chimero wrote about this recently in How to Have an Idea, which beautifully illustrates Mr Buzan’s theories, articulating the importance of the brain’s ability to make abstract connections, finding unexpected pairings when a concept is mapped out on paper. Once a topic is surveyed and a rich set of stimuli articulated, the next stage is to draw connections, pulling from opposite sides of the mind map. It’s at this point, when defining alogical connections, that the truly interesting and unexpected ideas are often uncovered. The curve ball If you’ve followed our instructions so far, all being well, you should have a number of ideas. Good news: we have one last technique to throw into the mix. We like to call it ‘the curve ball’, that last minute ‘something’ that forces you to rethink and encourages you to address a problem from a different direction. There are a number of ways of throwing in a curve ball – a short, sharp, unexpected impetus – but we have a firm favourite we think you’ll appreciate. Brian Eno and Peter Schmidt’s Oblique Strategies – subtitled ‘Over One Hundred Worthwhile Dilemmas’ – are the perfect creative tool for throwing in a spot of unpredictability. As Eno and Schmidt put it: The Oblique Strategies can be used as a pack (a set of possibilities being continuously reviewed in the mind) or by drawing a single card from the shuffled pack when a dilemma occurs in a working situation. In this case the card is trusted even if its appropriateness is quite unclear. They are not final, as new ideas will present themselves, and others will become self-evident. Brian Eno and Peter Schmidt Simply pick a card and apply the strategy to the problem at hand. The key here, as with de Bono’s techniques, is to embrace randomness and provocation to inspire lateral creative approaches. To assist this process, you might wish to consult one of the many virtual decks of Oblique Strategies online. Wrapping up To summarise, it’s tempting to see the route to the fastest satisfactory conclusion in a computer when, in reality, that’s the last place you should start. The tools we’ve introduced, far from time-consuming, are hyper-efficient, always at hand and, if you factor them into your workflow, the key to unlocking the ideas that set the great designers apart. We wish you well on your quest in search of the perfect idea, now armed with the knowledge that the quest begins on paper. 2010 The Standardistas thestandardistas 2010-12-13T00:00:00+00:00 https://24ways.org/2010/good-ideas-grow-on-paper/ process
182 Breaking Out The Edges of The Browser HTML5 contains more than just the new entities for a more meaningful document, it also contains an arsenal of JavaScript APIs. So many in fact, that some APIs have outgrown the HTML5 spec’s backyard and have been sent away to grow up all on their own and been given the prestigious honour of being specs in their own right. So when I refer to (bendy finger quote) “HTML5”, I mean the HTML5 specification and a handful of other specifications that help us authors build web applications. Examples of those specs I would include in the umbrella term would be: geolocation, web storage, web databases, web sockets and web workers, to name a few. For all you guys and gals, on this special 2009 series of 24 ways, I’m just going to focus on data storage and offline applications: boldly taking your browser where no browser has gone before! Web Storage The Web Storage API is basically cookies on steroids, a unhealthy dosage of steroids. Cookies are always a pain to work with. First of all you have the problem of setting, changing and deleting them. Typically solved by Googling and blindly relying on PPK’s solution. If that wasn’t enough, there’s the 4Kb limit that some of you have hit when you really don’t want to. The Web Storage API gets around all of the hoops you have to jump through with cookies. Storage supports around 5Mb of data per domain (the spec’s recommendation, but it’s open to the browsers to implement anything they like) and splits in to two types of storage objects: sessionStorage – available to all pages on that domain while the window remains open localStorage – available on the domain until manually removed Support Ignoring beta browsers for our support list, below is a list of the major browsers and their support for the Web Storage API: Latest: Internet Explorer, Firefox, Safari (desktop & mobile/iPhone) Partial: Google Chrome (only supports localStorage) Not supported: Opera (as of 10.10) Usage Both sessionStorage and localStorage support the same interface for accessing their contents, so for these examples I’ll use localStorage. The storage interface includes the following methods: setItem(key, value) getItem(key) key(index) removeItem(key) clear() In the simple example below, we’ll use setItem and getItem to store and retrieve data: localStorage.setItem('name', 'Remy'); alert( localStorage.getItem('name') ); Using alert boxes can be a pretty lame way of debugging. Conveniently Safari (and Chrome) include database tab in their debugging tools (cmd+alt+i), so you can get a visual handle on the state of your data: Viewing localStorage As far as I know only Safari has this view on stored data natively in the browser. There may be a Firefox plugin (but I’ve not found it yet!) and IE… well that’s just IE. Even though we’ve used setItem and getItem, there’s also a few other ways you can set and access the data. In the example below, we’re accessing the stored value directly using an expando and equally, you can also set values this way: localStorage.name = "Remy"; alert( localStorage.name ); // shows "Remy" The Web Storage API also has a key method, which is zero based, and returns the key in which data has been stored. This should also be in the same order that you set the keys, for example: alert( localStorage.getItem(localStorage.key(0)) ); // shows "Remy" I mention the key() method because it’s not an unlikely name for a stored value. This can cause serious problems though. When selecting the names for your keys, you need to be sure you don’t take one of the method names that are already on the storage object, like key, clear, etc. As there are no warnings when you try to overwrite the methods, it means when you come to access the key() method, the call breaks as key is a string value and not a function. You can try this yourself by creating a new stored value using localStorage.key = "foo" and you’ll see that the Safari debugger breaks because it relies on the key() method to enumerate each of the stored values. Usage Notes Currently all browsers only support storing strings. This also means if you store a numeric, it will get converted to a string: localStorage.setItem('count', 31); alert(typeof localStorage.getItem('count')); // shows "string" This also means you can’t store more complicated objects natively with the storage objects. To get around this, you can use Douglas Crockford’s JSON parser (though Firefox 3.5 has JSON parsing support baked in to the browser – yay!) json2.js to convert the object to a stringified JSON object: var person = { name: 'Remy', height: 'short', location: 'Brighton, UK' }; localStorage.setItem('person', JSON.stringify(person)); alert( JSON.parse(localStorage.getItem('person')).name ); // shows "Remy" Alternatives There are a few solutions out there that provide storage solutions that detect the Web Storage API, and if it’s not available, fall back to different technologies (for instance, using a flash object to store data). One comprehensive version of this is Dojo’s storage library. I’m personally more of a fan of libraries that plug missing functionality under the same namespace, just as Crockford’s JSON parser does (above). For those interested it what that might look like, I’ve mocked together a simple implementation of sessionStorage. Note that it’s incomplete (because it’s missing the key method), and it could be refactored to not using the JSON stringify (but you would need to ensure that the values were properly and safely encoded): // requires json2.js for all browsers other than Firefox 3.5 if (!window.sessionStorage && JSON) { window.sessionStorage = (function () { // window.top.name ensures top level, and supports around 2Mb var data = window.top.name ? JSON.parse(window.top.name) : {}; return { setItem: function (key, value) { data[key] = value+""; // force to string window.top.name = JSON.stringify(data); }, removeItem: function (key) { delete data[key]; window.top.name = JSON.stringify(data); }, getItem: function (key) { return data[key] || null; }, clear: function () { data = {}; window.top.name = ''; } }; })(); } Now that we’ve cracked the cookie jar with our oversized Web Storage API, let’s have a look at how we take our applications offline entirely. Offline Applications Offline applications is (still) part of the HTML5 specification. It allows developers to build a web app and have it still function without an internet connection. The app is access via the same URL as it would be if the user were online, but the contents (or what the developer specifies) is served up to the browser from a local cache. From there it’s just an everyday stroll through open web technologies, i.e. you still have access to the Web Storage API and anything else you can do without a web connection. For this section, I’ll refer you to a prototype demo I wrote recently of a contrived Rubik’s cube (contrived because it doesn’t work and it only works in Safari because I’m using 3D transforms). Offline Rubik’s cube Support Support for offline applications is still fairly limited, but the possibilities of offline applications is pretty exciting, particularly as we’re seeing mobile support and support in applications such as Fluid (and I would expect other render engine wrapping apps). Support currently, is as follows: Latest: Safari (desktop & mobile/iPhone) Sort of: Firefox‡ Not supported: Internet Explorer, Opera, Google Chrome ‡ Firefox 3.5 was released to include offline support, but in fact has bugs where it doesn’t work properly (certainly on the Mac), Minefield (Firefox beta) has resolved the bug. Usage The status of the application’s cache can be tested from the window.applicationCache object. However, we’ll first look at how to enable your app for offline access. You need to create a manifest file, which will tell the browser what to cache, and then we point our web page to that cache: <!DOCTYPE html> <html manifest="remy.manifest"> <!-- continues ... --> For the manifest to be properly read by the browser, your server needs to serve the .manifest files as text/manifest by adding the following to your mime.types: text/cache-manifest manifest Next we need to populate our manifest file so the browser can read it: CACHE MANIFEST /demo/rubiks/index.html /demo/rubiks/style.css /demo/rubiks/jquery.min.js /demo/rubiks/rubiks.js # version 15 The first line of the manifest must read CACHE MANIFEST. Then subsequent lines tell the browser what to cache. The HTML5 spec recommends that you include the calling web page (in my case index.html), but it’s not required. If I didn’t include index.html, the browser would cache it as part of the offline resources. These resources are implicitly under the CACHE namespace (which you can specify any number of times if you want to). In addition, there are two further namespaces: NETWORK and FALLBACK. NETWORK is a whitelist namespace that tells the browser not to cache this resource and always try to request it through the network. FALLBACK tells the browser that whilst in offline mode, if the resource isn’t available, it should return the fallback resource. Finally, in my example I’ve included a comment with a version number. This is because once you include a manifest, the only way you can tell the browser to reload the resources is if the manifest contents changes. So I’ve included a version number in the manifest which I can change forcing the browser to reload all of the assets. How it works If you’re building an app that makes use of the offline cache, I would strongly recommend that you add the manifest last. The browser implementations are very new, so can sometimes get a bit tricky to debug since once the resources are cached, they really stick in the browser. These are the steps that happen during a request for an app with a manifest: Browser: sends request for your app.html Server: serves all associated resources with app.html – as normal Browser: notices that app.html has a manifest, it re-request the assets in the manifest Server: serves the requested manifest assets (again) Browser: window.applicationCache has a status of UPDATEREADY Browser: reloads Browser: only request manifest file (which doesn’t show on the net requests panel) Server: responds with 304 Not Modified on the manifest file Browser: serves all the cached resources locally What might also add confusion to this process, is that the way the browsers work (currently) is if there is a cache already in place, it will use this first over updated resources. So if your manifest has changed, the browser will have already loaded the offline cache, so the user will only see the updated on the next reload. This may seem a bit convoluted, but you can also trigger some of this manually through the applicationCache methods which can ease some of this pain. If you bind to the online event you can manually try to update the offline cache. If the cache has then updated, swap the updated resources in to the cache and the next time the app loads it will be up to date. You could also prompt your user to reload the app (which is just a refresh) if there’s an update available. For example (though this is just pseudo code): addEvent(applicationCache, 'updateready', function () { applicationCache.swapCache(); tellUserToRefresh(); }); addEvent(window, 'online', function () { applicationCache.update(); }); Breaking out of the Browser So that’s two different technologies that you can use to break out of the traditional browser/web page model and get your apps working in a more application-ny way. There’s loads more in the HTML5 and non-HTML5 APIs to play with, so take your Christmas break to check them out! 2009 Remy Sharp remysharp 2009-12-02T00:00:00+00:00 https://24ways.org/2009/breaking-out-the-edges-of-the-browser/ code
233 Wrapping Things Nicely with HTML5 Local Storage HTML5 is here to turn the web from a web of hacks into a web of applications – and we are well on the way to this goal. The coming year will be totally and utterly awesome if you are excited about web technologies. This year the HTML5 revolution started and there is no stopping it. For the first time all the browser vendors are rallying together to make a technology work. The new browser war is fought over implementation of the HTML5 standard and not over random additions. We live in exciting times. Starting with a bang As with every revolution there is a lot of noise with bangs and explosions, and that’s the stage we’re at right now. HTML5 showcases are often CSS3 showcases, web font playgrounds, or video and canvas examples. This is great, as it gets people excited and it gives the media something to show. There is much more to HTML5, though. Let’s take a look at one of the less sexy, but amazingly useful features of HTML5 (it was in the HTML5 specs, but grew at such an alarming rate that it warranted its own spec): storing information on the client-side. Why store data on the client-side? Storing information in people’s browsers affords us a few options that every application should have: You can retain the state of an application – when the user comes back after closing the browser, everything will be as she left it. That’s how ‘real’ applications work and this is how the web ones should, too. You can cache data – if something doesn’t change then there is no point in loading it over the Internet if local access is so much faster You can store user preferences – without needing to keep that data on your server at all. In the past, storing local data wasn’t much fun. The pain of hacky browser solutions In the past, all we had were cookies. I don’t mean the yummy things you get with your coffee, endorsed by the blue, furry junkie in Sesame Street, but the other, digital ones. Cookies suck – it isn’t fun to have an unencrypted HTTP overhead on every server request for storing four kilobytes of data in a cryptic format. It was OK for 1994, but really neither an easy nor a beautiful solution for the task of storing data on the client. Then came a plethora of solutions by different vendors – from Microsoft’s userdata to Flash’s LSO, and from Silverlight isolated storage to Google’s Gears. If you want to know just how many crazy and convoluted ways there are to store a bit of information, check out Samy’s evercookie. Clearly, we needed an easier and standardised way of storing local data. Keeping it simple – local storage And, lo and behold, we have one. The local storage API (or session storage, with the only difference being that session data is lost when the window is closed) is ridiculously easy to use. All you do is call a few methods on the window.localStorage object – or even just set the properties directly using the square bracket notation: if('localStorage' in window && window['localStorage'] !== null){ var store = window.localStorage; // valid, API way store.setItem(‘cow’,‘moo’); console.log( store.getItem(‘cow’) ); // => ‘moo’ // shorthand, breaks at keys with spaces store.sheep = ‘baa’ console.log( store.sheep ); // ‘baa’ // shorthand for all store[‘dog’] = ‘bark’ console.log( store[‘dog’] ); // => ‘bark’ } Browser support is actually pretty good: Chrome 4+; Firefox 3.5+; IE8+; Opera 10.5+; Safari 4+; plus iPhone 2.0+; and Android 2.0+. That should cover most of your needs. Of course, you should check for support first (or use a wrapper library like YUI Storage Utility or YUI Storage Lite). The data is stored on a per domain basis and you can store up to five megabytes of data in localStorage for each domain. Strings attached By default, localStorage only supports strings as storage formats. You can’t store results of JavaScript computations that are arrays or objects, and every number is stored as a string. This means that long, floating point numbers eat into the available memory much more quickly than if they were stored as numbers. var cowdesc = "the cow is of the bovine ilk, "+ "one end is for the moo, the "+ "other for the milk"; var cowdef = { ilk“bovine”, legs, udders, purposes front“moo”, end“milk” } }; window.localStorage.setItem(‘describecow’,cowdesc); console.log( window.localStorage.getItem(‘describecow’) ); // => the cow is of the bovine… window.localStorage.setItem(‘definecow’,cowdef); console.log( window.localStorage.getItem(‘definecow’) ); // => [object Object] = bad! This limits what you can store quite heavily, which is why it makes sense to use JSON to encode and decode the data you store: var cowdef = { "ilk":"bovine", "legs":4, "udders":4, "purposes":{ "front":"moo", "end":"milk" } }; window.localStorage.setItem(‘describecow’,JSON.stringify(cowdef)); console.log( JSON.parse( window.localStorage.getItem(‘describecow’) ) ); // => Object { ilk=“bovine”, more…} You can also come up with your own formatting solutions like CSV, or pipe | or tilde ~ separated formats, but JSON is very terse and has native browser support. Some use case examples The simplest use of localStorage is, of course, storing some data: the current state of a game; how far through a multi-form sign-up process a user is; and other things we traditionally stored in cookies. Using JSON, though, we can do cooler things. Speeding up web service use and avoiding exceeding the quota A lot of web services only allow you a certain amount of hits per hour or day, and can be very slow. By using localStorage with a time stamp, you can cache results of web services locally and only access them after a certain time to refresh the data. I used this technique in my An Event Apart 10K entry, World Info, to only load the massive dataset of all the world information once, and allow for much faster subsequent visits to the site. The following screencast shows the difference: For use with YQL (remember last year’s 24 ways entry?), I’ve built a small script called YQL localcache that wraps localStorage around the YQL data call. An example would be the following: yqlcache.get({ yql: 'select * from flickr.photos.search where text="santa"', id: 'myphotos', cacheage: ( 60*60*1000 ), callback: function(data) { console.log(data); } }); This loads photos of Santa from Flickr and stores them for an hour in the key myphotos of localStorage. If you call the function at various times, you receive an object back with the YQL results in a data property and a type property which defines where the data came from – live is live data, cached means it comes from cache, and freshcache indicates that it was called for the first time and a new cache was primed. The cache will work for an hour (60×60×1,000 milliseconds) and then be refreshed. So, instead of hitting the YQL endpoint over and over again, you hit it once per hour. Caching a full interface Another use case I found was to retain the state of a whole interface of an application by caching the innerHTML once it has been rendered. I use this in the Yahoo Firehose search interface, and you can get the full story about local storage and how it is used in this screencast: The stripped down code is incredibly simple (JavaScript with PHP embed): // test for localStorage support if(('localStorage' in window) && window['localStorage'] !== null){ var f = document.getElementById(‘mainform’); // test with PHP if the form was sent (the submit button has the name “sent”) // get the HTML of the form and cache it in the property “state” localStorage.setItem(‘state’,f.innerHTML); // if the form hasn’t been sent… // check if a state property exists and write back the HTML cache if(‘state’ in localStorage){ f.innerHTML = localStorage.getItem(‘state’); } } Other ideas In essence, you can use local storage every time you need to speed up access. For example, you could store image sprites in base-64 encoded datasets instead of loading them from a server. Or you could store CSS and JavaScript libraries on the client. Anything goes – have a play. Issues with local and session storage Of course, not all is rainbows and unicorns with the localStorage API. There are a few niggles that need ironing out. As with anything, this needs people to use the technology and raise issues. Here are some of the problems: Inadequate information about storage quota – if you try to add more content to an already full store, you get a QUOTA_EXCEEDED_ERR and that’s it. There’s a great explanation and test suite for localStorage quota available. Lack of automatically expiring storage – a feature that cookies came with. Pamela Fox has a solution (also available as a demo and source code) Lack of encrypted storage – right now, everything is stored in readable strings in the browser. Bigger, better, faster, more! As cool as the local and session storage APIs are, they are not quite ready for extensive adoption – the storage limits might get in your way, and if you really want to go to town with accessing, filtering and sorting data, real databases are what you’ll need. And, as we live in a world of client-side development, people are moving from heavy server-side databases like MySQL to NoSQL environments. On the web, there is also a lot of work going on, with Ian Hickson of Google proposing the Web SQL database, and Nikunj Mehta, Jonas Sicking (Mozilla), Eliot Graff (Microsoft) and Andrei Popescu (Google) taking the idea beyond simply replicating MySQL and instead offering Indexed DB as an even faster alternative. On the mobile front, a really important feature is to be able to store data to use when you are offline (mobile coverage and roaming data plans anybody?) and you can use the Offline Webapps API for that. As I mentioned at the beginning, we have a very exciting time ahead – let’s make this web work faster and more reliably by using what browsers offer us. For more on local storage, check out the chapter on Dive into HTML5. 2010 Christian Heilmann chrisheilmann 2010-12-06T00:00:00+00:00 https://24ways.org/2010/html5-local-storage/ code
302 Flexible Project Management in Inflexible Environments Handling unforeseen circumstances is an inevitable part of any project. It’s also often the most uncomfortable, and there is no amount of skill or planning that will fully eradicate the need to adapt to change. The ability to be flexible, responsive, and unafraid of facing not only problems, but also potentially positive scope changes and new ideas, isn’t an easy one to master. I am by no means saying that I have, but what I have learned is that there is often the temptation to shut out anything that might derail your plan, even sometimes at the cost of the quality you’re committed to. The reality is that as someone leading a project you know there will be challenges, but, in general, it’s a hassle to try keep the landscape open. Problems are bridges we should cross when we come to them, but intentional changes to the plan, and adapting for the sake of improving your first idea, is harder. There are tight schedules, resource is planned miles ahead, and you’re already juggling twenty other things. If you’re passionate about the quality of work you deliver and are working somewhere that considers itself expert within the field of digital, then having an attitude of flexibility is extremely important. It’s important when you’re overcoming a challenge or problem, but it’s also important for allowing ideas to evolve and be refined as much as they can be throughout the course of a project. Where theory falls short The premise of any Agile methodology, Scrum for example, is based around being able to work efficiently, react quickly and deliver relevant chunks of a product in manageable increments. It’s often hailed as king of flexible management and it can work really well, especially for in-house software products developed over a long or even an indefinite period of time. It holds off defining scope too far ahead and lets teams focus on smaller amounts of work, and allows them to regularly reprioritise. Unfortunately though, not all environments lend themselves as easily to a fully Agile setup. Even the ones that do may be restrained from putting it fully into practice for an array of other internal reasons. Delivering digital services to clients—within an agency setting or as a freelancer—often demands a more rigid structure. You need clear sign-off points, there’s a lot less flexibility in defining features, or working within budgets and timeframes. To start with, for a project to warrant a fully Agile team working on it, and especially for agencies, you need clients big enough and rich enough to justify the resource. You also need a lot of client trust to propose defining features and scope as you go. Although this is achievable—and there are agencies that operate an agile setup—it takes a long journey to reach that scale in the full sense of the word. Building a reputation that commands unconditional trust and reaching the point where your projects are consistently of a certain size often requires backing by long journey of success and excellence. So there is a lot of room left for understanding how we can best strive to still deliver excellent projects within more constrained structures. We know that rigid waterfall planning, more often than not, falls over as soon as a project gets anything past a basic brochure site. There are many critiques of the system, but one of the main ones tends to be that nobody considers each other’s work properly, which can result in very expensive and inefficient development. Equally, for reasons we’ve already touched upon, running fully agile teams often isn’t the right answer. So many companies, individuals, and organisations look for a middle-ground that balances being flexible and adaptive, but also provides enough upfront commitment to agree budgets, get client/stakeholder sign off, and effectively coordinate internal resource across multiple parallel projects. Although I don’t have a perfect formula—and can very much assert there is no one perfect way of managing a project because every project is different to the next—I’ve identified a few different ways you can approach flexibility that have really helped me in running projects more smoothly within more realistic constraints. Planned Flexibility Drawing on some of the traditional methodologies such as PRINCE2, a good starting point for aspiring to be flexible is by planning for it from the start. Planning flexibility comes in a few forms. For one, you can regularly identify and log potential risks as a generally good, on-going habit over the course of the project. This essentially just involves scanning the horizon for potential blips on a regular basis (for example weekly) by consulting with your team and documenting it somewhere. It means you have a checkpoint when you sit down and make sure you’re minimising what will or may catch you by surprise. A good time to do this is in a weekly catch up meeting. It’s not going to fix all your problems, but it will make sure you have a head start on the ones you can see coming. On the subject of team meetings, setting up recurring project events, including a weekly call, a weekly team meeting and (depending on the size of the project) I like to try also do a stand-up as often as possible. Keeping everyone involved and bought in to a project is going to help you infinitely when you need to spot a problem or manage changes to the plan. It will be the difference between your designer spotting an issue and making a mental note to ‘tell you later’, and them actually coming over to tell you directly and immediately. Despite the overhead of meetings, and looping people into stages that they aren’t directly responsible for, the business benefits are chances for success are drastically increased. Planning in, and being aware of how important your team is, will help you be flexible. Building contingency (formally know as slack) into your project plan from the word go is another well-known and essential way of planning to be flexible. Your project plan will change a lot over the course of a project, but there are still the days that you estimate a job will take, and the days you should actually plan in. Most sensible management teams understand that budgets need to be agreed with this slack in mind or you will not be able to deliver a quality service. I believe that commercial awareness is one of the most valuable skills a project manager can have, but penny pinching will ruin client and team relationships, destroy buy-in and creativity, and often end you up with a much more expensive, hacky, and resented product. It’s not a justification to let budgets spiral out of control, but a way of thinking about the bigger picture and wider plan of the company itself. It’s unlikely you want high staff turnover because everyone fell out while you were screaming money at them and they didn’t feel like they could do a good job. It’s also unlikely that you will be able to deliver quality products, which will win you a strong reputation and subsequently bigger and better projects. Evaluating risk factors and building in the right amount of slack from the start will give you more wriggle room when you need to adapt and react. On the flip side, also keeping an overview of the wider workload (that you’re not necessarily responsible for), and knowing who to talk if resource is becoming free or needs filling, is another handy way of being able to react quickly and ensuring your management system is respected. You want pockets of backup time planned in, but you also want everyone being as productive as they can most of the time. Never run at 100% capacity: as soon as something does need to change, you’re left with nowhere to move. Transparency Having a client or stakeholder that trusts you is a really powerful aid in any regard, but especially so when you need to communicate an issue or new suggestion. Positioning yourself and your team as experts and taking the time to delve into the wider picture—and the goals surrounding your client’s reasons to commission the project in the first place—will make you more valuable to them. Clients and stakeholders will always be different, and sometimes you will get people who are just plain difficult, but more often than not people will listen if you’re willing to talk and explain things. As I’m sure all of us have realised at one point or another, a lot of people think they know what they want, and it’s usually the wrong thing. Managing key stakeholders in your project is arguably your biggest challenge, if they are on the your side and feel like the team is genuinely working to give them something of quality and value, then they will make your job easier. It’s often down to you to educate them, and to help them recognise and understand the work involved and you and your team’s reasoning behind your decisions. Being overly submissive or overly secretive will foster a dynamic in which they feel expected to steer the project. In this situation they may not respect the team’s suggestions or may come up with some unreasonable and counterproductive ideas that are likely to hinder progress and lower morale. Getting the stakeholder on board and making them feel a part of the wider picture will make things easier. Pushing back and challenging ideas or working hard to justify something they don’t quite understand will often work in your favour and protects your team. On quite a basic level it also shows you care and are invested; on another, it shows you feel confident in your expertise within your field and that is ultimately the reason they hired you. Taking the time to think about and be aware of this relationship, will make it easier to be flexible and handle new ideas or suggestions that pop up as the project goes along. Change doesn’t need to be ‘scope creep’ if it’s raised in a practical, value-orientated, and level headed discussion. There is usually a way forward for new ideas, as long as they’re valuable and support the wider goals. Maybe the deadline gets pushed back, maybe you get more budget, maybe the client is happy to forgo something else. As long as there’s value and reason, it shows integrity to the project and respect for its success. You can’t expect for this to go smoothly without having invested in the client relationship, so it’s a large point in paving the way to handling change well. Reactive Flexibility Finally, if you’ve been doing this for a while, you’ll know by now that you can’t anticipate everything. Sometimes you will have to react and change the plan under circumstances that aren’t easy. When an unexpected problem first rears its head—a client’s casual afterthought that’s threatening the scope of the project, an internal resource conflict, a junior member of staff that’s not grasping the ropes quite as quickly as you’d hoped—you have to react quickly. In his book, ‘Pitch Anything’, Oren Klaff talks about people’s first reactions being processed by their ‘crocodile brain’ before they’ve had a chance to refine and digest the information more intelligibly. As project managers, product owners, or scrum masters, it’s natural for our immediate reactions to an unexpected problem to cause a pang of stress. But after that initial jolt you need to turn to practical solutions and start racking your brain for different ways forward. It’s here you need to remember to not let your imagination get the better of you, especially if you’ve been putting in the legwork with your team and your client. There is always a way forward and moments like this can be a good opportunity to develop your negotiation and diplomacy skills. Don’t let your immediate reaction be shutting the problem down; instead, take a second to think about it before you decide on the best direction. In a stressful situation, your first idea probably won’t be your best one. From an internal point of view, it’s very important that whatever went wrong doesn’t turn into a finger pointing exercise and you don’t lose your cool. Getting caught up in a blame game or a witch hunt is never productive. Relationship cultivating can sometimes be the pillar that gets you through a stressful blip. Biggest tip for staying flexible when you’re reacting to a problem—apart form obviously thinking of ways forward—is to communicate. Don’t go quiet until you feel like you have a plan, you’ll often need to put everyone else at ease before you can move things forward. Problem solving is part of the job and will need to happen in even the most flexible of product delivery systems. In conclusion, being flexible is never simple but there are things you can do to make your life easier. Owning a position of expertise, putting together a team that’s involved in each other’s work and cultivating a client/stakeholder relationship that’s as transparent and respectful as possible will get you a long way. In times of crisis, believe in your skills and be open to adapting over getting frustrated. 2016 Gillian Sibthorpe gilliansibthorpe 2016-12-04T00:00:00+00:00 https://24ways.org/2016/flexible-project-management/ process
245 Web Content Accessibility Guidelines 2.1—for People Who Haven’t Read the Update Happy United Nations International Day of Persons with Disabilities 2018! The United Nations chose “Empowering persons with disabilities and ensuring inclusiveness and equality” as this year’s theme. We’ve seen great examples of that in 2018; for example, Paul Robert Lloyd has detailed how he improved the accessibility of this very website. On social media, US Congressmember-Elect Alexandria Ocasio-Cortez started using the Clipomatic app to add live captions to her Instagram live stories, conforming to success criterion 1.2.4, “Captions (Live)” of the Web Content Accessibility Guidelines (figure 1) …and British Vogue Contributing Editor Sinéad Burke has used the split-screen feature of Instagram live stories to invite an interpreter to provide live Sign Language interpretation, going above and beyond success criterion 1.2.6, “Sign Language (Prerecorded)” of the Web Content Accessibility Guidelines (figure 2). Figure 1: Screenshot of Alexandria Ocasio-Cortez’s Instagram story with live captionsFigure 2: Screenshot of Sinéad Burke’s Instagram story with Sign Language Interpretation That theme chimes with this year’s publication of the World Wide Web Consortium (W3C)’s Web Content Accessibility Guidelines (WCAG) 2.1. In last year’s “Web Content Accessibility Guidelines—for People Who Haven’t Read Them”, I mentioned the scale of the project to produce this update during 2018: “the editors have to update the guidelines to cover all the new ways that people interact with new technologies, while keeping the guidelines backwards-compatible”. The WCAG working group have added 17 success criteria to the 61 that they released way back in 2008—for context, that was 1½ years before Apple released their first iPad! These new criteria make it easier than ever for us web geeks to produce work that is more accessible to people using mobile devices and touchscreens, people with low vision, and people with cognitive and learning disabilities. Once again, let’s rip off all the legalese and ambiguous terminology like wrapping paper, and get up to date. Can your users perceive the information on your website? The first guideline has criteria that help you prevent your users from asking, “What the **** is this thing here supposed to be?” We’ve seven new criteria for this guideline. 1.3.4 Some people can’t easily change the orientation of the device that they use to browse the web, and so you should make sure that your users can use your website in portrait orientation and in landscape orientation. Consider how people slowly twirl presents that they have plucked from under the Christmas tree, to find the appropriate orientation—and expect your users to do likewise with your websites and apps. We’ve had 18½ years since John Allsopp’s revelatory Dao of Web Design enlightened us to “embrace the fact that the web doesn’t have the same constraints” as printed pages, and to “design for this flexibility”. So, even though this guideline doesn’t apply to websites where “a specific display orientation is essential,” such as a piano tutorial, always ask yourself, “What would John Allsopp do?” 1.3.5 You should help the user’s browser to automatically complete–or not complete–form fields, to save the user some time and effort. The surprisingly powerful and flexible autocomplete attribute for input elements should prove most useful here. If you’ve used microformats or microdata to mark up information about a person, the autocomplete attribute’s range of values should seem familiar. I like how the W3’s “Using HTML 5.2 autocomplete attributes” says that autocompleted values in forms help “those with dexterity disabilities who have trouble typing, those who may need more time, and anyone who wishes to reduce effort to fill out a form” (emphasis mine). Um…🙋‍♂️ 1.3.6 I like this one a lot, because it can help a huge audience to overcome difficulties that might prevent them from ever using the web. Some people have cognitive difficulties that affect their memory, focus, attention, language processing, and/or decision-making. Those users often rely on assistive technologies that present information through proprietary symbols, summaries of content, and keyboard shortcuts. You could use ARIA landmarks to identify the regions of each webpage. You could also keep an eye on the W3C’s ongoing work on Personalisation Semantics. 1.4.10 If you were to find a Nintendo Switch and “Super Mario Odyssey” under your Christmas tree, you would have many hours of enjoyably scrolling horizontally and vertically to play the game. On the other hand, if you had to zoom a webpage to 400% so that you could read the content, you might have many hours of frustratedly scrolling horizontally and vertically to read the content. Learned reader, I assume you understand the purpose and the core techniques of Responsive Web Design. I also assume you’re getting up to speed with the new Grid, Flexbox, and Box Alignment techniques for layout, and overflow-wrap. Using those skills, you should make sure that all content and functionality remain available when the browser is 320px wide, without your user needing to scroll horizontally. (For vertical text, you should make sure that all content and functionality remain available when the browser is 256px high, without your user needing to scroll vertically.) You don’t have to do this for anything that would lose meaning if you restructured it into one narrow column. That includes some images, maps, diagrams, video, games, presentations, and data tables. Remember to check how your media queries affect font size: your user might find that text becomes smaller as they zoom into the webpage. So, test this one on real devices, or—better yet—test it with real users. 1.4.11 In “Web Content Accessibility Guidelines—for People Who Haven’t Read Them”, I recommended bookmarking Lea Verou’s Contrast Ratio calculator for checking that text contrasts enough with its background (for success criteria 1.4.3 and 1.4.6), so that more people can read it more easily. For this update, you should make sure that form elements and their focus states have a 3:1 contrast ratio with the colour around them. This doesn’t apply to controls that use the browser’s default styling. Also, you should make sure that graphics that convey information have a 3:1 contrast ratio with the colour around them. 1.4.12 Some people, due to low vision or dyslexia, might need to modify the typography that you agonised over. Research indicates that you should make sure that all content and functionality would remain available if a user were to set: line height to at least 1½ × the font size; space below paragraphs to at least 2 × the font size; letter spacing to at least 0.12 × the font size; word spacing to at least 0.16 × the font size. To test this, check for text overlapping, text hiding behind other elements, or text disappearing. 1.4.13 Sometimes when visiting a website, you hover over—or tab on to—something that unleashes a newsletter subscription pop-up, some suggested “related content”, and/or a GDPR-related pop-up. On a well-designed website, you can press the Esc key on your keyboard or click a prominent “Close” button or “X” button to vanquish such intrusions. If the Esc key fails you, or if you either can’t see or can’t click the “Close” button…well, you’ll probably just close that browser tab. This situation can prove even more infuriating for users with low vision or cognitive disabilities. So, if new content appears when your user hovers over or tabs on to some element, you should make sure that: your user can dismiss that content without needing to move their pointer or tab on to some other element (this doesn’t apply to error warnings, or well-behaved content that doesn’t obscure or replace other content); the new content remains visible while your user moves their cursor over it; the new content remains visible as long as the user hovers over that element or dismisses that content—or until the new content is no longer valid. This doesn’t apply to situations such as hovering over an element’s title attribute, where the user’s browser controls the display of the content that appears. Can users operate the controls and links on your website? The second guideline has criteria that help you prevent your users from asking, “How the **** does this thing work?” We’ve nine new criteria for this guideline. 2.1.4 Some websites offer keyboard shortcuts for users. For example, the keyboard shortcuts for Gmail allow the user to press the ⇧ key and u to mark a message as unread. Usually, shortcuts on websites include modifier keys, such as Ctrl, along with a letter, number, or punctuation symbol. Unfortunately, users who have dexterity challenges sometimes trigger those shortcuts by accident, and that can make a website impossible to use. Also, speech input technology can sometimes trigger those shortcuts. If your website offers single-character keyboard shortcuts, you must allow your user to turn off or remap those shortcuts. This doesn’t apply to single-character keyboard shortcuts that only work when a control, such as drop-down list, has focus. 2.2.6 If your website uses a timeout for some process, you could store the user’s data for at least 20 hours, so that users with cognitive disabilities can take a break or take longer than usual to complete the process without losing their place or losing their data. Alternatively, you could warn the user, at the start of the process, about that the website will timeout after whatever amount of time you have chosen. 2.3.3 If your website has some non-essential animation (such as parallax scrolling) that starts when the user does some particular action, you could allow the user to turn off that animation so that you avoid harming users with vestibular disorders. The prefers-reduced-motion media query currently has limited browser support, but you can start using it now to avoid showing animations to users who select the “Reduce Motion” setting (or equivalent) in their device’s operating system: @media (prefers-reduced-motion: reduce) { .MrFancyPants { animation: none; } } 2.5.1 Some websites let users use multi-touch gestures on touchscreen devices. For example, Google Maps allows users to pinch with two fingers to zoom out and “unpinch” with two fingers to zoom in. Also, some websites allow users to drag a finger to do some action, such as changing the value on an input element with type="range", or swiping sideways to the next photograph in a gallery. Some users with dexterity challenges, and some users who use a head pointer, an eye-gaze system, or speech-controlled mouse emulation, might find multi-touch gestures or dragging impossible. You must make sure that your website supports single-tap alternatives to any multi-touch gestures or dragging actions that it provides. For example, if your website lets someone pinch and unpinch a map to zoom in and out, you must also provide buttons that a user can tap to zoom in and out. 2.5.2 This might be my favourite accessibility criterion ever! Did you ever touch or press a “Send” button but then immediately realise that you really didn’t want to send the message, and so move your finger or cursor away from the “Send” button before lifting your finger?! Imagine how many arguments that functionality has prevented. 😌 You must make sure that touching or pressing does not cause anything to happen before the user raises their finger or cursor, or make sure that the user can move their finger or cursor away to prevent the action. In JavaScript, prefer onclick to onmousedown, unless your website has actions that need onmousedown. Also, this doesn’t apply to actions that need to happen as soon as the user clicks or touches. For example, a user playing a “Whac-A-Mole” game or a piano emulator needs the action to happen as soon as they click or touch the screen. 2.5.3 Recently, entrepreneur and social media guru Gary Vaynerchuk has emphasised the rise of audio and voice as output and input. He quotes a Google statistic that says one in five search queries use voice input. Once again, users with disabilities have been ahead of the curve here, having used screen readers and/or dictation software for many years. You must make sure that the text that appears on a form control or image matches how your HTML identifies that form control or image. Use proper semantic HTML to achieve this: use the label element to pair text with the corresponding input element; use an alt attribute value that exactly matches any text that appears in an image; use an aria-labelledby attribute value that exactly matches the text that appears in any complex component. 2.5.4 Modern Web APIs allow web developers to specify how their website will react to the user shaking, tilting, or gesturing towards their device. Some users might find those actions difficult, impossible, or embarrassing to perform. If you make any functionality available when the user shakes, tilts, or gestures towards their device, you must provide form controls that make that same functionality available. As usual, this doesn’t apply to websites that require shaking, tilting, or gesturing; this includes some games and music programmes. John Gruber describes the iPhone’s “Shake to Undo” gesture as “dreadful — impossible to discover through exploration of the on-screen [user interface], bad for accessibility, and risks your phone flying out of your hand”. This accessibility criterion seems to empathise with John: you must make sure that your user can prevent your website from responding to shaking, tilting and/or gesturing towards their device. 2.5.5 Homer Simpson’s telephone famously complained, “The fingers you have used to dial are too fat.” I think we’ve all felt like that when using phones and tablets, particularly when trying to dismiss pop-ups and ads. You could make interactive elements at least 44px wide × 44px high. Apple’s “Human Interface Guidelines” agree: “Provide ample touch targets for interactive elements. Try to maintain a minimum tappable area of 44pt x 44pt for all controls.” This doesn’t apply to links within inline text, or to unsoiled elements. 2.5.6 Expect your users to use a variety of input devices they want, and to change from one to another whenever they please. For example, a user with a tablet and keyboard might jab icons on the screen while typing on the keyboard, or a user might dictate text while alone and then type on a keyboard when a colleague arrives. You could make sure that your website allows your users to use whichever available input modality they choose. Once again, this doesn’t apply to websites that require a specific modality; this includes typing tutors and music programmes. Can users understand your content? The third guideline has criteria that help you prevent your users from asking, “What the **** does this mean?” We’ve no new criteria for this guideline. Have you made your website robust enough to work on your users’ browsers and assistive technologies? The fourth and final guideline has criteria that help you prevent your users from asking, “Why the **** doesn’t this work on my device?” We’ve one new criterion for this guideline. 4.1.3 Sometimes you need to let your user know the status of something: “Did it work OK? What was the error? How far through it are we?” However, you should avoid making your user lose their place on the webpage, and so you should let them know the status without opening a new window, focusing on another element, or submitting a form. To do this properly for assistive technology users, choose the appropriate ARIA role for the new content; for example: if your user needs to know, “Did it work OK?”, add role="status”; if your user needs to know, “What was the error?”, add role="alert”; if you user needs to know, “How far through it are we?”, add role="log" (for a chat window) or role="progressbar" (for, well, a progress bar). Better design for humans My favourite of Luke Wroblewski’s collection of Design Quotes is, “Design is the art of gradually applying constraints until only one solution remains,” from that most prolific author, “Unknown”. I’ve always viewed the Web Content Accessibility Guidelines as people-based constraints, and liked how they help the design process. With these 17 new web content accessibility criteria, go forth and create solutions that more people than ever before can use. Spending those book vouchers you got for Christmas What next? If you’re looking for something to do to keep you busy this Christmas, I thoroughly recommend these four books for increasing your accessibility expertise: “Pro HTML5 Accessibility” by Joshue O Connor (Head of Accessibility (Interim) at the UK Government Digital Service, Director of InterAccess, and one of the editors of the Web Content Accessibility Guidelines 2.1): Although this book is six years old—a long time in web design—I find it an excellent go-to resource. It begins by explaining how people with disabilities use the web, and then expertly explains modern HTML in that context. “A Web for Everyone—Designing Accessible User Experiences” by Sarah Horton (the Paciello Group’s UX Strategy Lead) and Whitney Quesenbery (the Center for Civic Design’s co-director): This book covers the Web Content Accessibility Guidelines 2.0, the principles of Universal Design, and design thinking. Its personas for Accessible UX and its profiles of well-known industry figures—including some 24ways authors—keep its content practical and relevant throughout. “Accessibility For Everyone” by Laura Kalbag (Ind.ie’s co-founder and designer, and 24ways author): This book is just over a year old, and so serves as a great resource for up-to-date coverage of guidelines, laws, and accessibility features of operating systems—as well as content, design, coding, and testing. The audiobook, which Laura narrates, can help you and your colleagues go from having little or no understanding of web accessibility, to becoming familiar with all aspects of web accessibility—in less than four hours. “Just Ask: Integrating Accessibility Throughout Design” by Shawn Lawton Henry (the World Wide Web Consortium (W3C)’s Web Accessibility Initiative (WAI)’s Outreach Coordinator): Although this book is 11½ years old, the way it presents accessibility as part of the User-Centered Design process is timeless. I found its section on Usability Testing with people with disabilities particularly useful. 2018 Alan Dalton alandalton 2018-12-03T00:00:00+00:00 https://24ways.org/2018/wcag-for-people-who-havent-read-the-update/ ux
137 Cheating Color Have you ever been strapped to use specific colors outlined in a branding guide? Felt restricted because those colors ended up being too light or dark for the way you want to use them? Here’s the solution: throw out your brand guide. gasp! OK, don’t throw it out. Just put it in a drawer for a few minutes. Branding Guides be Damned When dealing with color on screen, it’s easy to get caught up in literal values from hex colors, you can cheat colors ever so slightly to achieve the right optical value. This is especially prevalent when trying to bring a company’s identity colors to a screen design. Because the most important idea behind a brand guide is to help a company maintain the visual integrity of their business, consider hex numbers to be guidelines rather than law. Once you are familiar enough with the colors your company uses, you can start to flex them a bit, and take a few liberties. This is a quick method for cheating to get the color you really want. With a little sleight of design, we can swap a color that might be part of your identity guidelines, with one that works better optically, and no one will be the wiser! Color is a Wily Beast This might be hard: You might have to break out of the idea that a color can only be made using one method. Color is fluid. It interacts and changes based on its surroundings. Some colors can appear lighter or darker based on what color they appear on or next to. The RGB gamut is additive color, and as such, has a tendency to push contrast in the direction that objects may already be leaning—increasing the contrast of light colors on dark colors and decreasing the contrast of light on light. Obviously, because we are talking about monitors here, these aren’t hard and fast rules. Cheat and Feel Good About It On a light background, when you have a large element of a light color, a small element of the same color will appear lighter. Enter our fake company: Double Dagger. They manufacture footnotes. Take a look at Fig. 1 below. The logo (Double Dagger), rule, and small text are all #6699CC. Because the logo so large, we get a good sense of the light blue color. Unfortunately, the rule and small text beneath it feel much lighter because we can’t create enough contrast with such small shapes in that color. Now take a look at Fig. 2. Our logo is still #6699CC, but now the rule and smaller text have been cheated to #4477BB, effectively giving us the same optical color that we used in the logo. You will find that we get a better sense of the light blue, and the added benefit of more contrast for our text. Doesn’t that feel good? Conversely, when you have a large element of a dark color, a small element of the same color will appear darker. Let’s look at Fig. 3 below. Double Dagger has decided to change its identity colors from blue to red. In Fig. 3, our logo, rule, and small text are all #330000, a very dark red. If you look at the rule and small text below the logo, you will notice that they seem dark enough to be confused with black. The dark red can’t be sustained by the smaller shapes. Now let’s look at Fig. 4. The logo is still #33000, but we’ve now cheated the rule and smaller text to #550000. This gives us a better sense of a red, but preserves the dark and moody direction the company has taken. But we’ve only touched on color against a white background. For colors against a darker background, you may find lighter colors work fine, but darker colors need to be cheated a bit to the lighter side in order to reach a good optical equivalent. Take a look below at Fig. 5 and Fig. 6. Both use the same exact corresponding colors as Fig. 1 and Fig. 2 above, but now they are set against a dark background. Where the blue used in Fig. 1 above was too light for the smaller elements, we find it is just right for them in Fig. 5, and the darker blue we used in Fig. 2 has now proven too dark for a dark background, as evidenced in Fig. 6. Your mileage may vary, and this may not be applicable in all situations, but consider it to be just another tool on your utility belt for dealing with color problems. 2006 Jason Santa Maria jasonsantamaria 2006-12-23T00:00:00+00:00 https://24ways.org/2006/cheating-color/ design
265 Designing for Perfection Hello, 24 ways readers. I hope you’re having a nice run up to Christmas. This holiday season I thought I’d share a few things with you that have been particularly meaningful in my work over the last year or so. They may not make you wet your santa pants with new-idea-excitement, but in the context of 24 ways I think they may serve as a nice lesson and a useful seasonal reminder going into the New Year. Enjoy! Story Despite being a largely scruffy individual for most of my life, I had some interesting experiences regarding kitchen tidiness during my third year at university. As a kid, my room had always been pretty tidy, and as a teenager I used to enjoy reordering my CDs regularly (by artist, label, colour of spine – you get the picture); but by the time I was twenty I’d left most of these traits behind me, mainly due to a fear that I was turning into my mother. The one remaining anally retentive part of me that remained however, lived in the kitchen. For some reason, I couldn’t let all the pots and crockery be strewn across the surfaces after cooking. I didn’t care if they were washed up or not, I just needed them tidied. The surfaces needed to be continually free of grated cheese, breadcrumbs and ketchup spills. Also, the sink always needed to be clear. Always. Even a lone teabag, discarded casually into the sink hours previously, would give me what I used to refer to as “kitchen rage”. Whilst this behaviour didn’t cause any direct conflicts, it did often create weirdness. We would be happily enjoying a few pre-night out beverages (Jack Daniels and Red Bull – nice) when I’d notice the state of the kitchen following our round of customized 49p Tesco pizzas. Kitchen rage would ensue, and I’d have to blitz the kitchen, which usually resulted in me having to catch everyone up at the bar afterwards. One evening as we were just about to go out, I was stood there, in front of the shithole that was our kitchen with the intention of cleaning it all up, when a realization popped into my head. In hindsight, it was a pretty obvious one, but it went along the lines of “What the fuck are you doing? Sort your life out”. I sodded the washing up, rolled out with my friends, and had a badass evening of partying. After this point, whenever I got the urge to clean the kitchen, I repeated that same realization in my head. My tidy kitchen obsession strived for a level of perfection that my housemates just didn’t share, so it was ultimately pointless. It didn’t make me feel that good, either; it was like having a cigarette after months of restraint – initially joyous but soon slightly shameful. Lesson Now, around seven years later, I’m a designer on the web and my life is chaotic. It features no planning for significant events, no day-to-day routine or structure, no thought about anything remotely long-term, and I like to think I do precisely what I want. It seems my days at striving for something ordered and tidy, in most parts of my life, are long gone. For much of my time as a designer, though, it’s been a different story. I relished industry-standard terms such as ‘pixel perfection’ and ‘polished PSDs’, taking them into my stride as I strove to design everything that was put on my plate perfectly. Even down to grids and guidelines, all design elements would be painstakingly aligned to a five-pixel grid. There were no seven-pixel margins or gutters to be found in my design work, that’s for sure. I put too much pride and, inadvertently, too much ego into my work. Things took too long to create, and because of the amount of effort put into the work, significant changes, based on client feedback for example, were more difficult to stomach. Over the last eighteen months I’ve made a conscious effort to change the way I approach designing for the web. Working on applications has probably helped with this; they seem to have a more organic development than rigid content-based websites. Mostly though, a realization similar to my kitchen rage one came about when I had to make significant changes to a painstakingly crafted Photoshop document I had created. The changes shouldn’t have been difficult or time-consuming to implement, but they were turning out to be. One day, frustrated with how long it was taking, the refrain “What the fuck are you doing? Sort your life out” again entered my head. I blazed the rest of the work, not rushing or doing scruffy work, but just not adhering to the insane levels of perfection I had previously set for myself. When the changes were presented, everything went down swimmingly. The client in this case (and I’d argue most cases) cared more about the ideas than the perfect way in which they had been implemented. I had taken myself and my ego out of the creative side of the work, and it had been easier to succeed. Argument I know many other designers who work on the web share such aspirations to perfection. I think it’s a common part of the designer DNA, but I’m not sure it really has a place when designing for the web. First, there’s the environment. The landscape in which we work is continually shifting and evolving. The inherent imperfection of the medium itself makes attempts to create perfect work for it redundant. Whether you consider it a positive or negative point, the products we make are never complete. They’re always scaling and changing. Like many aspects of web design, this striving for perfection in our design work is a way of thinking borrowed from other design industries where it’s more suited. A physical product cannot be as easily altered or developed after it has been manufactured, so the need to achieve perfection when designing is more apt. Designers who can relate to anything I’ve talked about can easily let go of that anal retentiveness if given the right reasons to do so. Striving for perfection isn’t a bad thing, but I simply don’t think it can be achieved in such a fast-moving, unique industry. I think design for the web works better when it begins with quick and simple, followed by iteration and polish over time. To let go of ego and to publish something that you’re not completely happy with is perhaps the most difficult part of the job for designers like us, but it’s followed by a satisfaction of knowing your product is alive and breathing, whereas others (possibly even competitors) may still be sitting in Photoshop, agonizing over whether a margin should be twenty or forty pixels. I keep telling myself to stop sitting on those two hundred ideas that are all half-finished. Publish them, clean them up and iterate over time. I’ve been telling myself this for months and, hopefully, writing this article will give me the kick in the arse I need. Hopefully, it will also give someone else the same kick. 2011 Greg Wood gregwood 2011-12-17T00:00:00+00:00 https://24ways.org/2011/designing-for-perfection/ process
2 Levelling Up Hello, 24 ways. I’m Ashley and I sell property insurance. I’m interrupting your Christmas countdown with an article about rental property software and a guy, Pete, who selflessly encouraged me to build my first web app. It doesn’t sound at all festive, or — considering I’ve used both “insurance” and “rental property” — interesting, but do stick with me. There’s eggnog at the end. I run a property insurance business, Brokers Direct. It’s a small operation, but well established. We’ve been selling landlord insurance on the web for over thirteen years, for twelve of which we have provided our clients with third-party software for managing their rental property portfolios. Free. Of. Charge. It sounds like a sweet deal for our customers, but it isn’t. At least, not any more. The third-party software is victim to years of neglect by its vendor. Its questionable interface, garish visuals and, ahem, clip art icons have suffered from a lack of updates. While it was never a contender for software of the year, I’ve steadily grown too embarrassed to associate my business with it. The third-party rental property software we distributed I wanted to offer my customers a simple, clean and lightweight alternative. In an industry that’s dominated by dated and bloated software, it seemed only logical that I should build my own rental property tool. The long learning-to-code slog Learning a programming language is daunting, the source of my frustration stemming from a non-programming background. Generally, tutorials assume a degree of familiarity with programming, whether it be tools, conventions or basic skills. I had none and, at the time, there was nothing on the web really geared towards a novice. I reached the point where I genuinely thought I was just not cut out for coding. Surrendering to my feelings of self-doubt and frustration, I sourced a local Rails developer, Pete, to build it for me. Pete brought a pack of index cards to our meeting. Index cards that would represent each feature the rental property software would launch with. “OK,” he began. “We’ll need a user model, tenant model, authentication, tenant and property relationships…” A dozen index cards with a dozen features lined the coffee table in a grid-like format. Logical, comprehensible, achievable. Seeing the app laid out in a digestible manner made it seem surmountable. Maybe I could do this. “I’ve been trying to learn Rails…”, I piped up. I don’t know why I said it. I was fully prepared to hire Pete to do the hard work for me. But Pete, unprompted, gathered the index cards and neatly stacked them together, coasting them across the table towards me. “You should build this”. Pete, a full-time freelance developer at the time, was turning down a paying job in favour of encouraging me to learn to code. Looking back, I didn’t realise how significant this moment was. That evening, I took Pete’s index cards home to make a start on my app, slowly evolving each of the cards into a working feature. Building the app solo, I turned to Stack Overflow to solve the inevitable coding hurdles I encountered, as well as calling on a supportive Rails community. Whether they provided direct solutions to my programming woes, or simply planted a seed on how to solve a problem, I kept coding. Many months later, and after several more doubtful moments, Lodger was born. Property overview of my app, Lodger. If I can do it, so can you I misspent a lot of time building Twitter and blogging applications (apparently, all Rails tutorials centre around Twitter and blogging). If I could rewind and impart some advice to myself, this is what I’d say. There’s no magic formula “I haven’t quite grasped Rails routing. I should tackle another tutorial.” Making excuses — or procrastination — is something we are all guilty of. I was waiting for a programming book that would magically deposit a grasp of the entire Ruby syntax in my head. I kept buying books thinking each one would be the one where it all clicked. I now have a bookshelf full of Ruby material, all of which I’ve barely read, and none of which got me any closer to launching my web app. Put simply, there’s no magic formula. Break it down Whatever it is you want to build, break it down into digestible chunks. Taking Pete’s method as an example, having an index card represent an individual feature helped me tremendously. Tackle one at a time. Even if each feature takes you a month to build, and you have eight features to launch with, after eight months you’ll have your MVP. Remember, if you do nothing each day, it adds up to nothing. Have a tangible product to build I have a wonderful habit of writing down personal notes, usually to express my feelings at the time or to log an idea, only to uncover them months or years down the line, long after I forgot I had written them. I made a timely discovery while writing this article, discovering this gem while flicking through a battered Moleskine: “I don’t seem to be making good progress with learning Rails, but development still excites me. I should maybe stop doing tutorials and work towards building a specific app.” Having a real product to work on, like I did with Lodger, means you have something tangible to apply the techniques you are learning. I found this prevented me from flitting aimlessly between tutorials and books, which is an easy area to accidentally remain in. Team up If possible, team up with a designer and create something together. Designers are great at presenting features in a way you’d never have considered. You will learn a lot from making their designs come to life. Your homework for the holiday Despite having a web app under my belt, I am not a programmer. I tinker with code, piecing enough bits of it together to make something functional. And that’s OK! I’m not excusing sloppiness, but if we aimed for perfection every time, we’d never execute any of our ideas. As the holidays approach and you’ve exhausted yet another viewing of The Muppet Christmas Carol (or is that just my guilty pleasure at Christmas?), you may have time on your hands. Time to explore an idea you’ve been sitting on, but — plagued with procrastination and doubt — have yet to bring to life. This holiday, I am here to say to you what Pete said to me. You should build this. You don’t need to be the next Mark Zuckerberg or Larry Page. You just have to learn enough to get it done. PS: I lied about the eggnogg, but try capturing somebody’s attention when you tell them you sell property insurance! 2013 Ashley Baxter ashleybaxter 2013-12-06T00:00:00+00:00 https://24ways.org/2013/levelling-up/ business
238 Everything You Wanted To Know About Gradients (And a Few Things You Didn’t) Hello. I am here to discuss CSS3 gradients. Because, let’s face it, what the web really needed was more gradients. Still, despite their widespread use (or is it overuse?), the smartly applied gradient can be a valuable contributor to a designer’s vocabulary. There’s always been a tension between the inherently two-dimensional nature of our medium, and our desire for more intensity, more depth in our designs. And a gradient can evoke so much: the splay of light across your desk, the slow decrease in volume toward the end of your favorite song, the sunset after a long day. When properly applied, graded colors bring a much needed softness to our work. Of course, that whole ‘proper application’ thing is the tricky bit. But given their place in our toolkit and their prominence online, it really is heartening to see we can create gradients directly with CSS. They’re part of the draft images module, and implemented in two of the major rendering engines. Still, I’ve always found CSS gradients to be one of the more confusing aspects of CSS3. So if you’ll indulge me, let’s take a quick look at how to create CSS gradients—hopefully we can make them seem a bit more accessible, and bring a bit more art into the browser. Gradient theory 101 (I hope that’s not really a thing) Right. So before we dive into the code, let’s cover a few basics. Every gradient, no matter how complex, shares a few common characteristics. Here’s a straightforward one: I spent seconds hours designing this gradient. I hope you like it. At either end of our image, we have a final color value, or color stop: on the left, our stop is white; on the right, black. And more color-rich gradients are no different: (Don’t ever really do this. Please. I beg you.) It’s visually more intricate, sure. But at the heart of it, we have just seven color stops (red, orange, yellow, and so on), making for a fantastic gradient all the way. Now, color stops alone do not a gradient make. Between each is a transition point, the fail-over point between the two stops. Now, the transition point doesn’t need to fall exactly between stops: it can be brought closer to one stop or the other, influencing the overall shape of the gradient. A tale of two syntaxes Armed with our new vocabulary, let’s look at a CSS gradient in the wild. Behold, the simple input button: There’s a simple linear gradient applied vertically across the button, moving from a bright sunflowerish hue (#FAA51A, for you hex nuts in the audience) to a much richer orange (#F47A20). And here’s the CSS that makes it happen: input[type=submit] { background-color: #F47A20; background-image: -moz-linear-gradient( #FAA51A, #F47A20 ); background-image: -webkit-gradient(linear, 0 0, 0 100%, color-stop(0, #FAA51A), color-stop(1, #F47A20) ); } I’ve borrowed David DeSandro’s most excellent formatting suggestions for gradients to make this snippet a bit more legible but, still, the code above might have turned your stomach a bit. And that’s perfectly understandable—heck, it sort of turned mine. But let’s step through the CSS slowly, and see if we can’t make it a little less terrifying. Verbose WebKit is verbose Here’s the syntax for our little gradient on WebKit: background-image: -webkit-gradient(linear, 0 0, 0 100%, color-stop(0, #FAA51A), color-stop(1, #F47A20) ); Woof. Quite a mouthful, no? Well, here’s what we’re looking at: WebKit has a single -webkit-gradient property, which can be used to create either linear or radial gradients. The next two values are the starting and ending positions for our gradient (0 0 and 0 100%, respectively). Linear gradients are simply drawn along the path between those two points, which allows us to change the direction of our gradient simply by altering its start and end points. Afterward, we specify our color stops with the oh-so-aptly named color-stop parameter, which takes the stop’s position on the gradient (0 being the beginning, and 100% or 1 being the end) and the color itself. For a simple two-color gradient like this, -webkit-gradient has a bit of shorthand notation to offer us: background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#FAA51A), to(#FAA51A) ); from(#FAA51A) is equivalent to writing color-stop(0, #FAA51A), and to(#FAA51A) is the same as color-stop(1, #FAA51A) or color-stop(100%, #FAA51A)—in both cases, we’re simply declaring the first and last color stops in our gradient. Terse Gecko is terse WebKit proposed its syntax back in 2008, heavily inspired by the way gradients are drawn in the canvas specification. However, a different, leaner syntax came to the fore, eventually appearing in a draft module specification in CSS3. Naturally, because nothing on the web was meant to be easy, this is the one that Mozilla has implemented. Here’s how we get gradient-y in Gecko: background-image: -moz-linear-gradient( #FAA51A, #F47A20 ); Wait, what? Done already? That’s right. By default, -moz-linear-gradient assumes you’re trying to create a vertical gradient, starting from the top of your element and moving to the bottom. And, if that’s the case, then you simply need to specify your color stops, delimited with a few commas. I know: that was almost… painless. But the W3C/Mozilla syntax also affords us a fair amount of flexibility and control, by introducing features as we need them. We can specify an origin point for our gradient: background-image: -moz-linear-gradient(50% 100%, #FAA51A, #F47A20 ); As well as an angle, to give it a direction: background-image: -moz-linear-gradient(50% 100%, 45deg, #FAA51A, #F47A20 ); And we can specify multiple stops, simply by adding to our comma-delimited list: background-image: -moz-linear-gradient(50% 100%, 45deg, #FAA51A, #FCC, #F47A20 ); By adding a percentage after a given color value, we can determine its position along the gradient path: background-image: -moz-linear-gradient(50% 100%, 45deg, #FAA51A, #FCC 20%, #F47A20 ); So that’s some of the flexibility implicit in the W3C/Mozilla-style syntax. Now, I should note that both syntaxes have their respective fans. I will say that the W3C/Mozilla-style syntax makes much more sense to me, and lines up with how I think about creating gradients. But I can totally understand why some might prefer WebKit’s more verbose approach to the, well, looseness behind the -moz syntax. À chacun son gradient syntax. Still, as the language gets refined by the W3C, I really hope some consensus is reached by the browser vendors. And with Opera signaling that it will support the W3C syntax, I suppose it falls on WebKit to do the same. Reusing color stops for fun and profit But CSS gradients aren’t all simple colors and shapes and whatnot: by getting inventive with individual color stops, you can create some really complex, compelling effects. Tim Van Damme, whose brain, I believe, should be posthumously donated to science, has a particularly clever application of gradients on The Box, a site dedicated to his occasional podcast series. Now, there are a fair number of gradients applied throughout the UI, but it’s the feature image that really catches the eye. You see, there’s nothing that says you can’t reuse color stops. And Tim’s exploited that perfectly. He’s created a linear gradient, angled at forty-five degrees from the top left corner of the photo, starting with a fully transparent white (rgba(255, 255, 255, 0)). At the halfway mark, he’s established another color stop at an only slightly more opaque white (rgba(255, 255, 255, 0.1)), making for that incredibly gradual brightening toward the middle of the photo. But then he has set another color stop immediately on top of it, bringing it back down to rgba(255, 255, 255, 0) again. This creates that fantastically hard edge that diagonally bisects the photo, giving the image that subtle gloss. And his final color stop ends at the same fully transparent white, completing the effect. Hot? I do believe so. Rocking the radials We’ve been looking at linear gradients pretty exclusively. But I’d be remiss if I didn’t at least mention radial gradients as a viable option, including a modest one as a link accent on a navigation bar: And here’s the relevant CSS: background: -moz-radial-gradient(50% 100%, farthest-side, rgb(204, 255, 255) 1%, rgb(85, 85, 85) 15%, rgba(85, 85, 85, 0) ); background: -webkit-gradient(radial, 50% 100%, 0, 50% 100%, 15, from(rgb(204, 255, 255)), to(rgba(85, 85, 85, 0)) ); Now, the syntax builds on what we’ve already learned about linear gradients, so much of it might be familiar to you, picking out color stops and transition points, as well as the two syntaxes’ reliance on either a separate property (-moz-radial-gradient) or parameter (-webkit-gradient(radial, …)) to shift into circular mode. Mozilla introduces another stand-alone property (-moz-radial-gradient), and accepts a starting point (50% 100%) from which the circle radiates. There’s also a size constant defined (farthest-side), which determines the reach and shape of our gradient. WebKit is again the more verbose of the two syntaxes, requiring both starting and ending points (50% 100% in both cases). Each also accepts a radius in pixels, allowing you to control the skew and breadth of the circle. Again, this is a fairly modest little radial gradient. Time and article length (and, let’s be honest, your author’s completely inadequate grasp of geometry) prevent me from covering radial gradients in much more detail, because they are incredibly powerful. For those interested in learning more, I can’t recommend the references at Mozilla and Apple strongly enough. Leave no browser behind But no matter the kind of gradients you’re working with, there is a large swathe of browsers that simply don’t support gradients. Thankfully, it’s fairly easy to declare a sensible fallback—it just depends on the kind of fallback you’d like. Essentially, gradient-blind browsers will disregard any properties containing references to either -moz-linear-gradient, -moz-radial-gradient, or -webkit-gradient, so you simply need to keep your fallback isolated from those properties. For example: if you’d like to fall back to a flat color, simply declare a separate background-color: .nav { background-color: #000; background-image: -moz-linear-gradient(rgba(0, 0, 0, 0), rgba(255, 255, 255, 0.45)); background-image: -webkit-gradient(linear, 0 0, 0 100%, from(rgba(0, 0, 0, 0)), to(rgba(255, 255, 255, 0.45))); } Or perhaps just create three separate background properties. .nav { background: #000; background: #000 -moz-linear-gradient(rgba(0, 0, 0, 0), rgba(255, 255, 255, 0.45)); background: #000 -webkit-gradient(linear, 0 0, 0 100%, from(rgba(0, 0, 0, 0)), to(rgba(255, 255, 255, 0.45))); } We can even build on this to fall back to a non-gradient image: .nav { background: #000 <strong>url("faux-gradient-lol.png") repeat-x</strong>; background: #000 -moz-linear-gradient(rgba(0, 0, 0, 0), rgba(255, 255, 255, 0.45)); background: #000 -webkit-gradient(linear, 0 0, 0 100%, from(rgba(0, 0, 0, 0)), to(rgba(255, 255, 255, 0.45))); } No matter the approach you feel most appropriate to your design, it’s really just a matter of keeping your fallback design quarantined from its CSS3-ified siblings. (If you’re feeling especially masochistic, there’s even a way to get simple linear gradients working in IE via Microsoft’s proprietary filters. Of course, those come with considerable performance penalties that even Microsoft is quick to point out, so I’d recommend avoiding those. And don’t tell Andy Clarke I told you, or he’ll probably unload his Derringer at me. Or something.) Go forth and, um, gradientify! It’s entirely possible your head’s spinning. Heck, mine is, but that might be the effects of the ’nog. But maybe you’re wondering why you should care about CSS gradients. After all, images are here right now, and work just fine. Well, there are some quick benefits that spring to mind: fewer HTTP requests are needed; CSS3 gradients are easily made scalable, making them ideal for variable widths and heights; and finally, they’re easily modifiable by tweaking a few CSS properties. Because, let’s face it, less time spent yelling at Photoshop is a very, very good thing. Of course, CSS-generated gradients are not without their drawbacks. The syntax can be confusing, and it’s still under development at the W3C. As we’ve seen, browser support is still very much in flux. And it’s possible that gradients themselves have some real performance drawbacks—so test thoroughly, and gradient carefully. But still, as syntaxes converge, and support improves, I think generated gradients can make a compelling tool in our collective belts. The tasteful design is, of course, entirely up to you. So have fun, and get gradientin’. 2010 Ethan Marcotte ethanmarcotte 2010-12-22T00:00:00+00:00 https://24ways.org/2010/everything-you-wanted-to-know-about-gradients/ code
77 Colour Accessibility Here’s a quote from Josef Albers: In visual perception a colour is almost never seen as it really is[…] This fact makes colour the most relative medium in art.Josef Albers, Interaction of Color, 1963 Albers was a German abstract painter and teacher, and published a very famous course on colour theory in 1963. Colour is very relative — not just in the way that it appears differently across different devices due to screen quality and colour management, but it can also be seen differently by different people — something we really need to be more mindful of when designing. What is colour blindness? Colour blindness very rarely means that you can’t see any colour at all, or that people see things in greyscale. It’s actually a decreased ability to see colour, or a decreased ability to tell colours apart from one another. How does it happen? Inside the typical human retina, there are two types of receptor cells — rods and cones. Rods are the cells that allow us to see dark and light, and shape and movement. Cones are the cells that allow us to perceive colour. There are three types of cones, each responsible for absorbing blue, red, and green wavelengths in the spectrum. Problems with colour vision occur when one or more of these types of cones are defective or absent entirely, and these problems can either be inherited through genetics, or acquired through trauma, exposure to ultraviolet light, degeneration with age, an effect of diabetes, or other factors. Colour blindness is a sex-linked trait and it’s much more common in men than in women. The most common type of colour blindness is called deuteranomaly which occurs in 7% of males, but only 0.5% of females. That’s a pretty significant portion of the population if you really stop and think about it — we can’t ignore this demographic. What does it look like? People with the most common types of colour blindness, like protanopia and deuteranopia, have difficulty discriminating between red and green hues. There are also forms of colour blindness like tritanopia, which affects perception of blue and yellow hues. Below, you can see what a colour wheel might look like to these different people. What can we do? Here are some things you can do to make your websites and apps more accessible to people with all types of colour blindness. Include colour names and show examples One of the most common annoyances I’ve heard from people who are colour-blind is that they often have difficulty purchasing clothing and they will sometimes need to ask another person for a second opinion on what the colour of the clothing might actually be. While it’s easier to shop online than in a physical store, there are still accessibility issues to consider on shopping websites. Let’s say you’ve got a website that sells T-shirts. If you only show a photo of the shirt, it may be impossible for a person to tell what colour the shirt really is. For clarification, be sure to reference the name of the colour in the description of the product. United Pixelworkers does a great job of following this rule. The St. John’s T-shirt has a quirky palette inspired by the unofficial pink, white and green Newfoundland flag, and I can imagine many people not liking it. Another common problem occurs when a colour filter has been added to a product search. Here’s an example from a clothing website with unlabelled colour swatches, and how that might look to someone with deuteranopia-type colour blindness. The colour search filter below, from the H&M website, is much better since it uses names instead. At first glance, Urban Outfitters also uses unlabelled colour swatches on product pages (below), but on closer inspection, the colour name is displayed on hover. This isn’t an ideal solution, because although it’ll work on a desktop browser, it won’t work on a touchscreen device where hovering isn’t an option. Using overly fancy colour names, like the ones you might find labelling high-end interior paint can be just as confusing as not using a colour name at all. Names like grape instead of purple don’t really give the viewer any useful information about what the colour actually is on a colour wheel. Is grape supposed to be purple, or could it refer to red grapes or even green? Stick with hue names as much as possible. Avoid colour-specific instructions When designing forms, avoid labelling required fields only with coloured text. It’s safer to use a symbol cue like the asterisk which is colour-independent. A similar example would be directing a user to click a green button to purchase a product. Label your buttons clearly and reference them in the site copy by function, not colour, to avoid confusion. Don’t rely on colour coding Designing accessible maps and infographics can be much more challenging. Don’t rely on colour coding alone — try to use a combination of colour and texture or pattern, along with precise labels, and reflect this in the key or legend. Combine a blue background with a crosshatched pattern, or a pink background with a stippled dot — your users will always have two pieces of information to work with. The map of the London subway system is an iconic image not just in London, but around the world. Unfortunately, it contains some colours that are indistinguishable from each other to a person with a vision problem. This is true not only for the London underground, but also for any other wayfinding system that relies on colour coding as the only key in a legend. There are printable versions of the map available online in black and white, using patterns and shades of black and grey that are distinguishable, but the point is that there would be no need for such a map if it were designed with accessibility in mind from the beginning. And, if you’re a person who has a physical disability as well as a vision problem, the “Step-Free” guide map which shows stations is based on the original coloured map. Provide alternatives and customization While it’s best to consider these issues and design your app to be accessible by default, sometimes this might not be possible. Providing alternative styles or allowing users to edit their own colours is a feature to keep in mind. The developers of the game Faster Than Light created an alternate colour-blind mode and asked for public feedback to make sure that it passed the test. Not much needed to be done, but you can see they added stripes to the red zones and changed some outlines to blue. iChat is also a good example. Although by default it uses coloured bubbles to indicate a user’s status (available for chat, away or idle, or busy), included in the preferences is a “User Shapes to Indicate Status” option, which changes the shape of the standard circles to green circles, yellow triangles and red squares. Pay attention to contrast Colours that are similar in value but different in hue may be easy to distinguish between for a user with good vision, but a person who suffers from colour blindness may not be able to tell them apart at all. Proofing your work in greyscale is a quick way to tell if there’s enough contrast between the most important information in your design. Check with a simulator There are many tools out there for simulating different types of colour blindness, and it’s worth checking your design to catch any potential problems up front. One is called Sim Daltonism and it’s available for Mac OS X. It’ll show a pop-up preview next to your cursor and you can choose which type of colour blindness you want to test from a drop-down menu. You can also proof for the two most common types of colour blindness right in Photoshop or Illustrator (CS4 and later) while you’re designing. The colour contrast check tool from designer and developer Jonathan Snook gives you the option to enter a colour code for a background, and a colour code for text, and it’ll tell you if the colour contrast ratio meets the Web Content Accessibility Guidelines 2.0. You can use the built-in sliders to adjust your colours until they meet the compliant contrast ratios. This is a great tool to test your palette before going live. For live websites, you can use the accessibility tool called WAVE, which also has a contrast checker. It’s important to keep in mind, though, that while WAVE can identify contrast errors in text, other things can slip through, so a site that passes the test does not automatically mean it’s accessible in reality. For example, the contrast checker here doesn’t notice that our red link in the introduction isn’t underlined, and therefore could blend into the surrounding paragraph text. I know that once I started getting into the habit of checking my work in a simulator, I became more mindful of any potential problem areas and it was easier to avoid them up front. It’s also made me question everything I see around me and it sends red flags off in my head if I think it’s a serious colour blindness fail. Understanding that colour is relative in the planning stages and following these tips will help us make more accessible design for all. 2012 Geri Coady gericoady 2012-12-04T00:00:00+00:00 https://24ways.org/2012/colour-accessibility/ design
94 Using Questionnaires for Design Research How do you ask the right questions? In this article, I share a bunch of tips and practical advice on how to write and use your own surveys for design research. I’m an audience researcher – I’m not a designer or developer. I’ve spent much of the last thirteen years working with audience data both in creative agencies and on the client-side. I’m also a member of the Market Research Society. I run user surveys and undertake user research for our clients at the design studio I run with my husband – Mark Boulton Design. So let’s get started! Who are you designing for? Good web designers and developers appreciate the importance of understanding the audience they are designing or building a website or app for. I’m assuming that because you are reading a quality publication like 24 ways that you fall into this category, and so I won’t begin this article with a lecture. Suffice it to say, it’s a good idea to involve research of some sort during the life cycle of every project you undertake. I don’t just mean visual or competitor research, which of course is also very important. I mean looking at or finding your own audience or user data. Whether that be auditing existing data or research available from the client, carrying out user interviews, A/B testing, or conducting a simple questionnaire with users, any research is better than none. If you create personas as a design tool, they should always be based on research, so you will need to have plenty of data to hand for that. Where do I start? In the initial kick-off stages of a project, it’s a good idea to start by asking your client (when working in-house you still have a client – you might even be the client) what research or audience data they have available. Some will have loads – analytics, surveys, focus groups and insights – from talking to customers. Some won’t have much at all and you’ll be hard pressed to find out much about the audience. It’s best to review existing research first without rushing headlong into doing new research. Get a picture of what the data tells you and perhaps get this into a document – who, what, why and how are they using this website or app? What gaps are there in existing research? What else do you need to know? Then you can decide what else you need to do to plug these gaps. Think about the information first before deciding on the methodology. The rest of my article talks mostly about running self-completion online surveys. You can of course do face-to-face surveys, self-completion written questionnaires or phone polls, but I won’t cover those here. That’s for another article. Why run a survey? Surveys are great for getting a broad picture of your audience. As long as they are designed carefully, you can create an overview of them, how they use the site and their opinions of it, with an idea of which parts of this picture are more important than others. By using a limited amount of open-ended questions, you can also get some more qualitative feedback or insights on your website or app. The clients we work with surprisingly often don’t have much in the way of audience research available, even basic analytics, so I will often suggest running a short survey, just to create a picture of who is out there. OK, what should I do first? Before you rush into writing questions, stop and think about what you’re trying to find out. Remember being in school when you studied science and you had to propose a hypothesis? This could be a starting point – something to prove or disprove. Or, even better, write a research brief. It doesn’t have to be long; it can be just a sentence that encapsulates what you’re trying to do, like a good creative brief. For the purposes of this article, I created a short, slightly silly survey on Christmas and beliefs in Father Christmas. My research brief was: To find out more about people’s beliefs about Father Christmas and their experiences of Christmas. Inevitably, as you start thinking of what questions to ask, you will find that you go off at tangents or your client will want you to add in everything but the kitchen sink. In order for your questionnaire not to get too long and lose focus, you could write lists of what it is and what it’s not. This is how I’d apply it to my Christmas questionnaire example: What it is about How people communicate with Father Christmas If someone’s background has affected their likelihood of believing in Father Christmas What it is not about What colour to change Father Christmas’s coat to Father Christmas’s elves Let’s get down to business: the questions. Kinds of questions There are two basic kinds of questions: open-ended and closed. Closed questions limit answers by giving the respondent a number of predefined lists of options to choose from. Typically, these are multiple-choice questions with a list of responses. You can either select one or tick all that apply. Another useful type of closed question I often use is a rating scale, where a respondent can assess a situation along a continuum of values. These can also be useful as a measure of advocacy or strength of feeling about something. There is a standard measure called the Net Promoter score, which measures how likely someone is to recommend your product or service to a friend or acquaintance. It’s a useful benchmark as you can compare your scores to others in a similar sector. Open-ended questions often take the form of a statement which requires a response. Generally, respondents are given a text box to fill in. It’s useful to limit this in some way so that people have an idea of how long the expected response should be; for example, a single line for an email address (Q18), or a larger text area for a longer response (Q6). If you plan to send your survey out to a large number of people, I would suggest using mostly closed questions, unless you want to spend a long time wading through comments and hand-coded responses. I’d always advise adding a general request at the end of a survey (‘Is there anything else you’d like to tell us?’). You’d be surprised how many interesting and insightful comments people will add. There are times when it’s better to provide an open-ended text box rather than a predefined list makes assumptions about your audience’s groupings. For example, we ran a short survey for our Gridset beta testers and rather than assume we knew who they were, we decided to ask an open-ended question: “What is your current job title?” The analysis took quite a bit longer than responses using a predefined list, but it meant that we were able to make sure we didn’t miss anyone. And next time we run a survey for Gridset, I can use the responses gathered from this survey to help create a predefined list to make analysis easier. What to ask The questions to ask depend on what you want to know, but your brief and lists of what the survey is and isn’t should help here. I always ask the design team and client to give me ideas of what they are interested in finding out, and combine this with a mix of new and standard questions I have used in other surveys. I find Survey Monkey’s question bank a very useful source of example questions and help with tricky wording. I always include simple demographics so I can compare my results to the population at large or internet users as a whole – just going on age, gender and location can be quite illuminating. For example, with the Christmas survey, I can see that the respondents were typical of the online design and dev community, mainly young and male. If appropriate, I add questions on disability, ethnic background, religion and community of interest. Questions about ethnicity, religion, sexual preference, disability and other sensitive subjects can feel awkward and difficult to ask. This is not a good reason to not ask them. Perhaps you’re working for a public sector client, like a local council, so it’s likely you will need to consider groups of people who maybe under-represented, who may have differing views to others, or who you need to look at specifically as a subset. How to ask Although they may seem clunky and wordy, it’s often best to use the census wording or professional body wording for such demographic questions. For example, I used the UK census 2011 wording for Wales on my Christmas questionnaire in my questions on religion [PDF] (Q16) and ethnicity [PDF] (Q17). I had to adapt them slightly for the Survey Monkey format – self-completion online, rather than pen and paper – which is why “White Welsh” came up as the first option for the ethnicity question. For similar questions for US audiences, try the Census Bureau website. When conducting a survey for a project that has a global audience, you need to consider who your primary audience is. For example, I recently created a questionnaire for a global news website. A large proportion of its audience is based in the USA, so I was careful to word things in a way Americans would find familiar. I used the US ethnic background census question wording and options, and looked at data for US competitor news websites to decide which to include. You should also consider people whose first language isn’t English. Working as an audience researcher at BBC Wales, every survey we did was bilingual. I’ve also recently run a user survey in Arabic using Google Forms. During this project, we found that while Survey Monkey supports different languages, including Arabic, the text ran left to right with no option to change it to right to left – an essential when it comes to reading Arabic! If research is a deliverable in a client project, and you know you’ll need to conduct it in a foreign language, always build in extra time for translation at both the questionnaire design and analysis stages. Make sure you also allow for plenty of checks. In this case we had to change to Google Forms after initially creating our survey with Survey Monkey to get the functionality we needed. Look and feel Think about the survey as another way your audience will experience your brand. Take care getting the tone of voice right. There are plenty of great articles and books out there about tone of voice – try Letting Go of the Words by Ginny Redish for starters, or Brand Language by Liz Doig. The basic rule of thumb is to sound like a human, and use clear and friendly language. If, like me, you are lucky enough to work with journalists or copy editors, you should ask for their help, particularly in the preamble, linking text and closing statements. I find it helpful to break my questions down into sections and to have a page for each. I then have an introductory piece of text for each section to guide the respondent through the survey. You should also make sure you check with your designers how your survey looks – use a company logo and branding, and make the typography legible. Many survey apps like Survey Monkey and Google Forms have a progress bar. This is helpful for users to see how far through your survey they are. I generally time the survey and give an indication in the preamble: “This survey will only take five minutes of your time.” You also need to think about how you will technically serve the questionnaire. For example, will it be via email, social media, a pop-up or lightbox on your website, or (not recommended but possible) in an ad space? Ethical considerations Something else to think about are any local laws that govern how you collect and store data, such as the Data Protection Act in the UK. As a member of the Market Research Society, I am also obliged to consider its guidelines, but even if you’re not, it’s always a good idea to deal with personal data ethically. If you collect personal data that can identify individuals, you must ask their permission to share it with others, and store it securely for no longer than two years. If you want to contact people afterwards, you must ask for their permission. If you ask for email addresses, as I did in question 18, you have a ready-made sample for a further survey, interviews or focus groups. Remember, you shouldn’t survey people under sixteen years old without the permission of their parents or legal guardians, so if you know your website is likely to be used by children, you must ask for verification of age early on, and your survey should close someone answers that they are under sixteen. The ESOMAR guidelines for online research [PDF] are well worth reading, as they go into detail about such issues, as well as privacy guidelines – using cookies, storing IP addresses, and so on. Tools Unless you work in-house and have proprietary software, or at a market research agency and you’re using specialist software such as Snap or IBM SPSS Statistics (previously just SPSS), you will need to use a good tool to run your survey, collect your responses and, ideally, help with the analysis. I like Survey Monkey because of the question bank and analysis tools. The software graphs your results and does simple cross-tabbing and filtering. What this means is you can slice the data in more interesting ways and delve a bit deeper. For example, in the Gridset questionnaire I mentioned earlier, I cross-tabbed responses to questions against whether a person worked in-house, for an agency or as a freelancer. Other well known online tools that I also use from time to time are Wufoo and Google Forms. Smart Surveys is a similar service to Survey Monkey and it’s used by many leading brands in the UK. Snap Surveys mentioned above is a well-established player in the market research scene, used a lot for face-to-face surveys and also on tablets and smartphones. Analysis Analysis is often overlooked but is as important as the design of the questionnaire. Don’t just rely on looking at the summary report and charts generated as standard by your form or survey software. Spend time with your data. Spend at least a week now and then if you can, looking at the data. Keep coming back to it and tweaking or cutting it a different way to see if there are any different pictures. Slice it up in different ways to reveal new insights. Here is the data from my dummy survey (apart from the open-ended responses). For open-ended questions, you can analyse collaboratively. Print and cut out the open-ended responses and do a cluster analysis or affinity sort with a colleague. Discussing the comments helps you to understand them. You will also find the design team are more likely to buy into the research as they have uncovered the insights for themselves. Always make sure to treat open-ended responses sensitively and don’t share anything publicly in a way that identifies the respondent. Write a report Never hand over a dataset to your client without a summary of the findings. Data on its own can be skewed to suit the reader’s needs, and not everyone is able to find the story in a dataset. Even if it’s not a deliverable, it’s always a good idea to capture your findings in a report of some sort. Use graphs sparingly to show really interesting things or to aid the reader’s understanding. I have written a quick dummy report using the data from the Christmas questionnaire so you can see how it’s done. I highly recommend Brian Suda’s book A Practical Guide to Designing with Data for tips on how to present data effectively, but that’s a subject that benefits a whole article (indeed book) in itself. I am not a designer. I am a researcher, so I never write design recommendations in a report unless they have been talked about or suggested by the designers I work with. More often, I write up the results and we talk about them and what impact they have on the project or design. Often they lead to more questions or further research. So that’s it: a brief introduction to using questionnaires for design research. Here’s a quick summary to remind you what I have talked about, and a list of resources if you’re interested in reading further. Top 10 things to remember when using questionnaires for design research: Start by auditing existing research to identify gaps in data. Write a research brief. Work out exactly what you’re trying to find out – what is the survey about, and what is it not about? The two basic kinds of questions are open-ended and closed. Closed questions limit responses by giving the respondent a number of predefined lists of options to choose from (multiple choice, rating scales, and so on). Open-ended questions are often in the form of a statement which requires a response. Always ask one at the end of a questionnaire. Always include simple demographics to enable you to compare your sample against the population in general. It’s best to use official census or professional body wording for questions on ethnicity, disability and religion. Be sure to think carefully about your tone of voice and the look of your questionnaire. Pay attention to guidelines and laws on storing personal data, cookies and privacy. Invest plenty of time in analysis and report writing. Don’t just look at the obvious – dig deep for more interesting insights. Some useful resources for further study Online research Design Research: Methods and Perspectives edited by Brenda Laurel Online Research Essentials by Brenda Russell and John Purcell Handbook of Online and Social Media Research by Ray Poynter ESOMAR guidelines for online research [PDF] Online questionnaires Market research books on questionnaire design Using Questionnaires in Small-Scale Research: A Beginner’s Guide by Pamela Munn Questionnaire Design by A N Oppenheim Developing a Questionnaire by Bill Gillham 2012 Emma Boulton emmaboulton 2012-12-14T00:00:00+00:00 https://24ways.org/2012/using-questionnaires-for-design-research/ business
134 Photographic Palettes How many times have you seen a colour combination that just worked, a match so perfect that it just seems obvious? Now, how many times do you come up with those in your own work? A perfect palette looks easy when it’s done right, but it’s often maddeningly difficult and time-consuming to accomplish. Choosing effective colour schemes will always be more art than science, but there are things you can do that will make coming up with that oh-so-smooth palette just a little a bit easier. A simple trick that can lead to incredibly gratifying results lies in finding a strong photograph and sampling out particularly harmonious colours. Photo Selection Not all photos are created equal. You certainly want to start with imagery that fits the eventual tone you’re attempting to create. A well-lit photo of flowers might lead to a poor colour scheme for a funeral parlour’s web site, for example. It’s worth thinking about what you’re trying to say in advance, and finding a photo that lends itself to your message. As a general rule of thumb, photos that have a lot of neutral or de-saturated tones with one or two strong colours make for the best palette; bright and multi-coloured photos are harder to derive pleasing results from. Let’s start with a relatively neutral image. Sampling In the above example, I’ve surrounded the photo with three different background colours directly sampled from the photo itself. Moving from left to right, you can see how each of the sampled colours is from an area of increasingly smaller coverage within the photo, and yet there’s still a strong harmony between the photo and the background image. I don’t really need to pick the big obvious colours from the photo to create that match, I can easily concentrate on more interesting colours that might work better for what I intend. Using a similar palette, let’s apply those colour choices to a more interesting layout: In this mini-layout, I’ve re-used the same tan colour from the previous middle image as a background, and sampled out a nicely matching colour for the top and bottom overlays, as well as the two different text colours. Because these colours all fall within a narrow range, the overall balance is harmonious. What if I want to try something a little more daring? I have a photo of stacked chairs of all different colours, and I’d like to use a few more of those. No problem, provided I watch my colour contrast: Though it uses varying shades of red, green, and yellow, this palette actually works because the values are even, and the colours muted. Placing red on top of green is usually a hideous combination of death, but if the green is drab enough and the red contrasts well enough, the result can actually be quite pleasing. I’ve chosen red as my loudest colour in this palette, and left green and yellow to play the quiet supporting roles. Obviously, there are no hard and fast rules here. You might not want to sample absolutely every colour in your scheme from a photo. There are times where you’ll need a variation that’s just a little bit lighter, or a blue that’s not in the photo. You might decide to start from a photo base and tweak, or add in colours of your own. That’s okay too. Tonal Variations I’ll leave you with a final trick I’ve been using lately, a way to bring a bit more of a formula into the equation and save some steps. Starting with the same base palette I sampled from the chairs, in the above image I’ve added a pair of overlaying squares that produce tonal variations of each primary. The lighter variation is simply a solid white square set to 40% opacity, the darker one is a black square at 20%. That gives me a highlight and shadow for each colour, which would prove handy if I had to adapt this colour scheme to a larger layout. I could add a few more squares of varying opacities, or adjust the layer blending modes for different effects, but as this looks like a great place to end, I’ll leave that up to your experimental whims. Happy colouring! 2006 Dave Shea daveshea 2006-12-22T00:00:00+00:00 https://24ways.org/2006/photographic-palettes/ design
332 CSS Layout Starting Points I build a lot of CSS layouts, some incredibly simple, others that cause sleepless nights and remind me of the torturous puzzle books that were given to me at Christmas by aunties concerned for my education. However, most of the time these layouts fit quite comfortably into one of a very few standard formats. For example: Liquid, multiple column with no footer Liquid, multiple column with footer Fixed width, centred Rather than starting out with blank CSS and (X)HTML documents every time you need to build a layout, you can fairly quickly create a bunch of layout starting points, that will give you a solid basis for creating the rest of the design and mean that you don’t have to remember how a three column layout with a footer is best achieved every time you come across one! These starting points can be really basic, in fact that’s exactly what you want as the final design, the fonts, the colours and so on will be different every time. It’s just the main sections we want to be able to quickly get into place. For example, here is a basic starting point CSS and XHTML document for a fixed width, centred layout with a footer. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>Fixed Width and Centred starting point document</title> <link rel="stylesheet" type="text/css" href="fixed-width-centred.css" /> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> </head> <body> <div id="wrapper"> <div id="side"> <div class="inner"> <p>Sidebar content here</p> </div> </div> <div id="content"> <div class="inner"> <p>Your main content goes here.</p> </div> </div> <div id="footer"> <div class="inner"> <p>Ho Ho Ho!</p> </div> </div> </div> </body> </html> body { text-align: center; min-width: 740px; padding: 0; margin: 0; } #wrapper { text-align: left; width: 740px; margin-left: auto; margin-right: auto; padding: 0; } #content { margin: 0 200px 0 0; } #content .inner { padding-top: 1px; margin: 0 10px 10px 10px; } #side { float: right; width: 180px; margin: 0; } #side .inner { padding-top: 1px; margin: 0 10px 10px 10px; } #footer { margin-top: 10px; clear: both; } #footer .inner { margin: 10px; } 9 times out of 10, after figuring out exactly what main elements I have in a layout, I can quickly grab the ‘one I prepared earlier’, mark-up the relevant sections within the ready-made divs, and from that point on, I only need to worry about the contents of those different areas. The actual layout is tried and tested, one that I know works well in different browsers and that is unlikely to throw me any nasty surprises later on. In addition, considering how the layout is going to work first prevents the problem of developing a layout, then realising you need to put a footer on it, and needing to redevelop the layout as the method you have chosen won’t work well with a footer. While enjoying your mince pies and mulled wine during the ‘quiet time’ between Christmas and New Year, why not create some starting point layouts of your own? The css-discuss Wiki, CSS layouts section is a great place to find examples that you can try out and find your favourite method of creating the various layout types. 2005 Rachel Andrew rachelandrew 2005-12-04T00:00:00+00:00 https://24ways.org/2005/css-layout-starting-points/ code
196 Designing a Remote Project I came across an article recently, which I have to admit made my blood boil a little. Yes, I know it’s the season of goodwill and all that, and I’m going to risk sounding a little Scrooge-like, but I couldn’t help it. It was written by someone who’d tried out ‘telecommuting’ (big sigh) a.k.a. remote or distributed working. They’d tested it in their company and decided it didn’t work. Why did it enrage me so much? Well, this person sounded like they’d almost set it up to fail. To them, it was the latest buzzword, and they wanted to offer their employees a ‘perk’. But it was going to be risky, because, well, they just couldn’t trust their employees not to be lazy and sit around in their pyjamas at home, watching TV, occasionally flicking their mousepad to ‘appear online’. Sounds about right, doesn’t it? Well, no. This attitude towards remote working is baked in the past, where working from one office and people all sitting around together in a cosy circle singing kum-by-yah* was a necessity not an option. We all know the reasons remote working and flexibility can happen more easily now: fast internet, numerous communication channels, and so on. But why are companies like Yahoo! and IBM backtracking on this? Why is there still such a negative perception of this way of working when it has so much real potential for the future? *this might not have ever really happened in an office. So what is remote working? It can come in various formats. It’s actually not just the typical office worker, working from home on a specific day. The nature of digital projects has been changing over a number of years. In this era where organisations are squeezing budgets and trying to find the best value wherever they can, it seems that the days of whole projects being tackled by one team, in the same place, is fast becoming the past. What I’ve noticed more recently is a much more fragmented way of putting together a project – a mixture of in-house and agency, or multiple agencies or organisations, or working with an offshore team. In the past we might have done the full integrated project from beginning to end, now, it’s a piece of the pie. Which means that everyone is having to work with people who aren’t sat next to them even more than before. Whether that’s a freelancer you’re working with who’s not in the office, an offshore agency doing development or a partner company in another city tackling UX… the future is looking more and more like a distributed workplace. So why the negativity, man? As I’ve seen from this article, and from examples of large corporations changing their entire philosophy away from remote working, there’s a lot of negativity towards this way of working. Of course if you decide to let everyone work from home when they want, set them off and then expect them all to check in at the right time or be available 24/7 it’s going to be a bit of a mess. Equally if you just jump into work with a team on the other side of the world without any setup, should you expect anything less than a problematic project? Okay, okay so what about these people who are going to sit on Facebook all day if we let them work from home? It’s the age old response to the idea of working from home. I can’t see the person, so how do I know what they are doing? This comes up regularly as one of the biggest fears of letting people work remotely. There’s also the perceived lack of productivity and distractions at home. The limited collaboration and communication with distributed workers. The lack of availability. The lower response times. Hang on a second, can’t these all still be problems even if you’ve got your whole team sat in the same place? “They won’t focus on work.” How many people will go on Facebook or Twitter whilst sat in an office? “They won’t collaborate as much.” How many people sit in the office with headphones on to block out distractions? I think we have to move away from the idea that being sat next to people automatically makes them work harder. If the work is satisfying, challenging, and relevant to a person – surely we should trust them to do it, wherever they are sat? There’s actually a lot of benefits to remote working, and having distributed teams. Offering this as a way of working can attract and retain employees, due to the improved flexibility. There can actually be fewer distractions and disruptions at home, which leads to increased productivity. To paraphrase Jason Fried in his talk ‘Why work doesn’t happen at work’, at home there are voluntary distractions where you have to choose to distract yourself with something. At the office these distractions become involuntary. Impromptu meetings and people coming to talk to you all the time are actually a lot more disruptive. Often, people find it easier to focus away from the office environment. There’s also the big benefit for a lot of people of the time saved commuting. The employee can actually do a lot that’s beneficial to them in this time, rather than standing squeezed into people’s armpits on public transport. Hence increased job satisfaction. With a distributed team, say if you’re working with an off-shore team, there could be a wider range of talent to pick from and it also encourages diversity. There can be a wider range of cultural differences and opinions brought to a project, which encourages more diverse ways of thinking. Tackling the issues - or, how to set up a project with a remote team But that isn’t to say running projects with a distributed team or being a remote worker is easy, and can just happen, like that. It needs work – and good groundwork – to ensure you don’t set it up to fail. So how do you help create a smoother remote project? Start with trust First of all, the basis of the team needs to be trust. Yes I’m going to sound a little like a cheesy, self-help guru here (perhaps in an attempt to seem less Scrooge-like and inject some Christmas cheer) but you do need to trust the people working remotely as well as them trusting you. This extends to a distributed team. You can’t just tell the offshore team what to do, and micromanage them, scared they won’t do what you want, how you want it because you can’t see them. You need to give them ownership and let them manage the tasks. Remember, people are less likely to criticise their own work. Make them own the work and they are more likely to be engaged and productive. Set a structure Distributed teams and remote workers can fail when there is no structure – just as much as teams sitting together fail without it too. It’s not so much setting rules, as having a framework to work within. Eliminate blockers before they happen. Think about what could cause issues for the team, and think of ways to solve this. For example, what do you do if you won’t be able to get hold of someone for a few hours because of a time difference? Put together a contingency, e.g. is there someone else on your time zone you could go to with queries after assessing the priority? Would it be put aside until that person is back in? Define team roles and responsibilities clearly. Sit down at the beginning of the project and clearly set out expectations. Also ask the team, what are their expectations of you? There won’t be a one size fits all framework either. Think about your team, the people in it, the type of project you’re working with, the type of client and stakeholder. This should give you an idea of what sort of communications you’ll need on the project. Daily calls, video calls, Slack channels, the choice is yours. Decide on the tools To be honest, I could spend hours talking about the different tools you can use for communication. But you know them, right? And in the end it’s not the tool that’s important here - it’s the communication that’s being done on the tool. Tools need to match the type of communications needed for your team. One caveat here though, never rely solely on email! Emails are silos, and can become beasts to manage communications on. Transparency in communication Good communication is key. Make sure there are clear objectives for communication. Set up one time during the week where those people meet together, discuss all the work during that week that they’ve done. If decisions are made between team members who are together, make sure everyone knows what these are. But try to make collective decisions where you can, when it doesn’t impact on people’s time. Have a face-to-face kick off Yes, I know this might seem to counter my argument, but face-to-face comms are still really important. If it’s feasible, have an in-person meeting to kick off your project, and to kick off your team working together. An initial meeting, to break the ice, discuss ways of working, set the goals, can go a long way to making working with distributed teams successful. If this is really not viable, then hold a video call with the team. Try to make this a little more informal. I know, I know, not the dreaded cringey icebreakers… but something to make everyone relax and get to know each other is really important. Bring everybody together physically on a regular basis if you can, for example with quarterly meetings. You’ve got to really make sure people still feel part of a team, and it often takes a little more work with a remote team. Connect with new team members, one-on-one first, then you can have more of a ‘remote’ relationship. Get visual Visual communication is often a lot better tool to use than just a written sentence, and can help bring ideas to life. Encourage people to sketch things, take a photo and add this to your written communications. Or use a mockup tool to sketch ideas. But what about Agile projects? The whole premise of Agile projects is to have face-to-face contact I hear you cry. The Agile Manifesto itself states “The most efficient and effective method of conveying information to and within a development team is face-to-face conversation”. However, this doesn’t mean the death of remote working. In fact loads of successful companies still run Agile projects, whilst having a distributed team. With all the collaborative tools you can use for centralising code, tracking tasks, visualising products, it’s not difficult to still communicate in a way that works. Just think about how to replicate the principles of Agile remotely - working together daily, a supportive environment, trust, and simplicity. How can you translate these to your remote or distributed team? One last thought to leave you with before you run off to eat your mince pies (in your pyjamas, whilst working). A common mistake in working with a remote project team or working remotely yourself, is replacing distance with time. If you’re away from the office you think you need to always be ‘on’ – messaging, being online, replying to requests. If you have a distributed team, you might think a lot of meetings, calls, and messages will be good to foster communication. But don’t overload these meetings, calls, and communication. This can be disruptive in itself. Give people the gift of some uninterrupted time to actually do some work, and not feel like they have to check in every second. 2017 Suzanna Haworth suzannahaworth 2017-12-06T00:00:00+00:00 https://24ways.org/2017/designing-a-remote-project/ business
244 It’s Beginning to Look a Lot Like XSSmas I dread the office Secret Santa. I have a knack for choosing well-meaning but inappropriate presents, like a bottle of port for a teetotaller, a cheese-tasting experience for a vegan, or heaven forbid, Spurs socks for an Arsenal supporter. Ok, the last one was intentional. It’s the same with gifting code. Once, I made a pattern library for A List Apart which I open sourced, and a few weeks later, a glaring security vulnerability was found in it. My gift was so generous that it enabled unrestricted access to any file on any public-facing server that hosted it. With platforms like GitHub and npm, giving the gift of code is so easy it’s practically a no-brainer. This giant, open source yankee swap helps us do our jobs without starting from scratch with every project. But like any gift-giving, it’s also risky. Vulnerabilities and Open Source Open source code is not inherently more or less vulnerable than closed-source code. What makes it higher risk is that the same piece of code gets reused in lots of places, meaning a hacker can use the same exploit mechanism on the same vulnerable code in different apps. Graph showing the number of open source vulnerabilities published per year, from the State of Open Source Security 2017 In the first 24 ways article this year, Katie referenced a few different types of vulnerability: Cross-site Request Forgery (also known as CSRF) SQL Injection Cross-site Scripting (also known as XSS) There are many more types of vulnerability, and those that live under the same category share similarities. For example, my favourite – is it weird to have a favourite vulnerability? – is Cross Site Scripting (XSS), which allows for the injection of scripts into web pages. This is a really common vulnerability often unwittingly added by developers. OWASP (the Open Web Application Security Project) wrote a great article about how to prevent opening the door to XSS attacks – share it generously with your colleagues. Most vulnerabilities like this are not added intentionally – they’re doors left ajar due to the way something has been scripted, like the over-generous code in my pattern library. Others, though, are added intentionally. A few months ago, a hacker, disguised as a helpful elf, offered to take over the maintenance of a popular npm package that had been unmaintained for a couple of years. The owner had moved onto other projects, and was keen to see it continue to be maintained by someone else, so transferred ownership. Fast-forward 3 months, it was discovered that the individual had quietly added a malicious package to the codebase, and the obfuscated code in it had been unwittingly installed onto thousands of apps. The code added was designed to harvest Bitcoin if it was run alongside another application. It was only spotted due to a developer’s curiosity. Another tactic to get developers to unwittingly install malicious packages into their codebase is “typosquatting” – back in August last year, npm reported that a user had been publishing packages with very similar names to popular packages (for example, crossenv instead of cross-env). This is a big wakeup call for open source maintainers. Techniques like this are likely to be used more as the maintenance of open source libraries becomes an increasing burden to their owners. After all, starting a new project often has a greater reward than maintaining an existing one, but remember, an open source library is for life, not just for Christmas. Santa’s on his sleigh If you use open source libraries, chances are that these libraries also use open source libraries. Your app may only have a handful of dependencies, but tucked in the back of that sleigh may be a whole extra sack of dependencies known as deep dependencies (ones that you didn’t directly install, but are dependencies of that dependency), and these can contain vulnerabilities too. Let’s look at the npm package santa as an example. santa has 8 direct dependencies listed on npm. That seems pretty manageable. But that’s just the tip of the iceberg – have a look at the full dependency tree which contains 109 dependencies – more dependencies than there are Christmas puns in this article. Only one of these direct dependencies has a vulnerability (at the time of writing), but there are actually 13 other known vulnerabilities in santa, which have been introduced through its deeper dependencies. Fixing vulnerabilities – the ultimate christmas gift If you’re a maintainer of open source libraries, taking good care of them is the ultimate gift you can give. Keep your dependencies up to date, use a security tool to monitor and alert you when new vulnerabilities are found in your code, and fix or patch them promptly. This will help keep the whole open source ecosystem healthy. When you find out about a new vulnerability, you have some options: Fix the vulnerability via an upgrade You can often fix a vulnerability by upgrading the library to the latest version. Make sure you’re using software that monitors your dependencies for new security issues and lets you know when a fix is ready, otherwise you may be unwittingly using a vulnerable version. Patch the vulnerable code Sometimes, a fix for a vulnerable library isn’t possible. This is often the case when a library is no longer being maintained, or the version of the library being used might be so out of date that upgrading it would cause a breaking change. Patches are bits of code that will fix that particular issue, but won’t change anything else. Switch to a different library If the library you’re using has no fix or patch, you may be better of switching it out for another one, particularly if it looks like it’s being unmaintained. Responsibly disclosing vulnerabilities Knowing how to responsibly disclose vulnerabilities is something I’m ashamed to admit that I didn’t know about before I joined a security company. But it’s so important! On discovering a new vulnerability, a developer has a few options: A malicious developer will exploit that vulnerability for their own gain. A reckless (or inexperienced) developer will disclose that vulnerability to the world without following a responsible disclosure process. This opens the door to an unethical developer exploiting the vulnerability. At Snyk, we monitor social media for mentions of newly found vulnerabilities so we can add them to our database and share fixes before they get exploited. An ethical and aware developer will follow what’s known as a “responsible disclosure process”. They will contact the maintainer of the code privately, allowing reasonable time for them to release a fix for the issue and to give others who use that vulnerable code a chance to fix it too. It’s important to understand this process if you’re a maintainer or contributor of code. It can be daunting when a report comes in, but understanding and following the right steps will help reduce the risk to the people who use that code. So what does responsible disclosure look like? I’ll take Node.js’s security disclosure policy as an example. They ask that all security issues that are found in Node.js are reported there. (There’s a separate process for bug found in third-party npm packages). Once you’ve reported a vulnerability, they promise to acknowledge it within 24 hours, and to give a more detailed response within 48 hours. If they find that the issue is indeed a security bug, they’ll give you regular updates about the progress they’re making towards fixing it. As part of this, they’ll figure out which versions are affected, and prepare fixes for them. They’ll assign the vulnerability a CVE (Common Vulnerabilities and Exposures) ID and decide on an embargo date for public disclosure. On the date of the embargo, they announce the vulnerability in their Node.js security mailing list and deploy fixes to nodejs.org. Tim Kadlec published an in-depth article about responsible disclosures if you’re interested in knowing more. It has some interesting horror stories of what happened when the disclosure process was not followed. Encourage responsible disclosure Add a SECURITY.md file to your project so someone who wants to message you about a vulnerability can do so without having to hunt around for contact details. Last year, Snyk published a State of Open Source Security report that found 79.5% of maintainers do not have a public disclosure policy. Those that did were considerably more likely to get notified privately about a vulnerability – 73% of maintainers who had one had been notified, vs 21% of maintainers who hadn’t published one one. Stats from the State of Open Source Security 2017 Bug bounties Some companies run bug bounties to encourage the responsible disclosure of vulnerabilities. By offering a reward for finding and safely disclosing a vulnerability, it also reduces the enticement of exploiting a vulnerability over reporting it and getting a quick cash reward. Hackerone is a community of ethical hackers who pentest apps that have signed up for the scheme and get paid when they find a new vulnerability. Wordpress is one such participant, and you can see the long list of vulnerabilities that have been disclosed as part of that program. If you don’t have such a bounty, be prepared to get the odd vulnerability extortion email. Scott Helme, who founded securityheaders.com and report-uri.com, wrote a post about some of the requests he gets for a report about a critical vulnerability in exchange for money. On one hand, I want to be as responsible as possible and if my users are at risk then I need to know and patch this issue to protect them. On the other hand this is such irresponsible and unethical behaviour that interacting with this person seems out of the question. A gift worth giving It’s time to brush the dust off those old gifts that we shared and forgot about. Practice good hygiene and run them through your favourite security tool – I’m just a little biased towards Snyk, but as Katie mentioned, there’s also npm audit if you use Node.js, and most source code managers like GitHub and GitLab have basic vulnerability alert capabilities. Stats from the State of Open Source Security 2017 Most importantly, patch or upgrade away those vulnerabilities away, and if you want to share that Christmas spirit, open fixes for your favourite open source projects, too. 2018 Anna Debenham annadebenham 2018-12-17T00:00:00+00:00 https://24ways.org/2018/its-beginning-to-look-a-lot-like-xssmas/ code
243 Researching a Property in the CSS Specifications I frequently joke that I’m “reading the specs so you don’t have to”, as I unpack some detail of a CSS spec in a post on my blog, some documentation for MDN, or an article on Smashing Magazine. However waiting for someone like me to write an article about something is a pretty slow way to get the information you need. Sometimes people like me get things wrong, or specifications change after we write a tutorial. What if you could just look it up yourself? That’s what you get when you learn to read the CSS specifications, and in this article my aim is to give you the basic details you need to grab quick information about any CSS property detailed in the CSS specs. Where are the CSS Specifications? The easiest way to see all of the CSS specs is to take a look at the Current Work page in the CSS section of the W3C Website. Here you can see all of the specifications listed, the level they are at and their status. There is also a link to the specification from this page. I explained CSS Levels in my article Why there is no CSS 4. Who are the specifications for? CSS specifications are for everyone who uses CSS. You might be a browser engineer - referred to as an implementor - needing to know how to implement a feature, or a web developer - referred to as an author - wanting to know how to use the feature. The fact that both parties are looking at the same document hopefully means that what the browser displays is what the web developer expected. Which version of a spec should I look at? There are a couple of places you might want to look. Each published spec will have the latest published version, which will have TR in the URL and can be accessed without a date (which is always the newest version) or at a date, which will be the date of that publication. If I’m referring to a particular Working Draft in an article I’ll typically link to the dated version. That way if the information changes it is possible for someone to see where I got the information from at the time of writing. If you want the very latest additions and changes to the spec, then the Editor’s Draft is the place to look. This is the version of the spec that the editors are committing changes to. If I make a change to the Multicol spec and push it to GitHub, within a few minutes that will be live in the Editor’s Draft. So it is possible there are errors, bits of text that we are still working out and so on. The Editor’s Draft however is definitely the place to look if you are wanting to raise an issue on a spec, as it may be that the issue you are about to raise is already fixed. If you are especially keen on seeing updates to specifications keep an eye on https://drafts.csswg.org/ as this is a list of drafts, along with the date they were last updated. How to approach a spec The first thing to understand is that most CSS Specifications start with the most straightforward information, and get progressively further into the weeds. For an author the initial examples and explanations are likely to be of interest, and then the property definitions and examples. Therefore, if you are looking at a vast spec, know that you probably won’t need to read all the way to the bottom, or read every section in detail. The second thing that is useful to know about modern CSS specifications is how modularized they are. It really never is a case of finding everything you need in a single document. If we tried to do that, there would be a lot of repetition and likely inconsistency between specs. There are some key specifications that many other specifications draw on, such as: Values and Units Intrinsic and Extrinsic Sizing Box Alignment When something is defined in another specification the spec you are reading will link to it, so it is worth opening that other spec in a new tab in order that you can refer back to it as you explore. Researching your property As an example we will take a look at the property grid-auto-rows, this property defines row tracks in the implicit grid when using CSS Grid Layout. The first thing you will need to do is find out which specification defines this property. You might already know which spec the property is part of, and therefore you could go directly to the spec and search using your browser or look in the navigation for the spec to find it. Alternatively, you could take a look at the CSS Property Index, which is an automatically generated list of CSS Properties. Clicking on a property will take you to the TR version of the spec, the latest published draft, and the definition of that property in it. This definition begins with a panel detailing the syntax of this property. For grid-auto-rows, you can see that it is listed along with grid-auto-columns as these two properties are essentially identical. They take the same values and work in the same way, one for rows and the other for columns. Value For value we can see that the property accepts a value <track-size>. The next thing to do is to find out what that actually means, clicking will take you to where it is defined in the Grid spec. The <track-size> value is defined as accepting various values: <track-breadth> minmax( <inflexible-breadth> , <track-breadth> ) fit-content( <length-percentage> We need to head down the rabbit hole to find out what each of these mean. From here we essentially go down line by line until we have unpacked the value of track-size. <track-breadth> is defined just below <track-size> as: <length-percentage> <flex> min-content max-content auto So these are all things that would be valid to use as a value for grid-auto-rows. The first value of <length-percentage> is something you will see in many specifications as a value. It means that you can use a length unit - for example px or em - or a percentage. Some properties only accept a <length> in which case you know that you cannot use a percentage as the value. This means that you could have grid-auto-rows with any of the following values. grid-auto-rows: 100px; grid-auto-rows: 1em; grid-auto-rows: 30%; When using percentages, it is important to know what it is a percentage of. As a percentage has to resolve from something. There is text in the spec which explains how column and row percentages work. “<percentage> values are relative to the inline size of the grid container in column grid tracks, and the block size of the grid container in row grid tracks.” This means that in a horizontal writing mode such as when using English, a percentage when used as a track-size in grid-auto-columns would be a percentage of the width of the grid, and a percentage in grid-auto-rows a percentage of the height of the grid. The second value of <flex> is also defined here, as “A non-negative dimension with the unit fr specifying the track’s flex factor.” This is the fr unit, and the spec links to a fuller definition of fr as this unit is only used in Grid Layout so it is therefore defined in the grid spec. We now know that a valid value would be: grid-auto-rows: 1fr; There is some useful information about the fr unit in this part of the spec. It is noted that the fr unit has an automatic minimum. This means that 1fr is really minmax(auto, 1fr). This is why having a number of tracks all at 1fr does not mean that all are equal sized, as a larger item in any of the tracks would have a large auto size and therefore would be larger after spare space had been distributed. We then have min-content and max-content. These keywords can be used for track sizing and the specification defines what they mean in the context of sizing a track, representing the min and max-sizing contributions of the grid tracks. You will see that there are various terms linked in the definition, so if you do not know what these mean you can follow them to find out. For example the spec links max-content contribution to the CSS Intrinsic and Extrinsic Sizing specification. This is one of those specs which is drawn on by many other specifications. If we follow that link we can read the definition there and follow further links to understand what each term means. The more that you read specifications the more these terms will become familiar to you. Just like learning a foreign language, at first you feel like you have to look up every little thing. After a while you remember the vocabulary. We can now add min-content and max-content to our available values. grid-auto-rows: min-content; grid-auto-rows: max-content; The final item in our list is auto. If you are familiar with using Grid Layout, then you are probably aware that an auto sized track for will grow to fit the content used. There is an interesting note here in the spec detailing that auto sized rows will stretch to fill the grid container if there is extra space and align-content or justify-content have a value of stretch. As stretch is the default value, that means these tracks stretch by default. Tracks using other types of length will not behave like this. grid-auto-rows: auto; So, this was the list for <track-breadth>, the next possible value is minmax( <inflexible-breadth> , <track-breadth> ). So this is telling us that we can use minmax() as a value, the final (max) value will be <track-breadth> and we have already unpacked all of the allowable values there. The first value (min) is detailed as an <inflexible-breadth>. If we look at the values for this, we discover that they are the same as <track-breadth>, minus the <flex> value: <length-percentage> min-content max-content auto We already know what all of these do, so we can add possible minmax() values to our list of values for <track-size>. grid-auto-rows: minmax(100px, 200px); grid-auto-rows: minmax(20%, 1fr); grid-auto-rows: minmax(1em, auto); grid-auto-rows: minmax(min-content, max-content); Finally we can use fit-content( <length-percentage>. We can see that fit-content takes a value of <length-percentage> which we already know to be either a length unit, or a percentage. The spec details how fit-content is worked out, and it essentially allows a track which acts as if you had used the max-content keyword, however the track stops growing when it hits the length passed to it. grid-auto-rows: fit-content(200px); grid-auto-rows: fit-content(20%); Those are all of our possible values, and to round things off, check again at the initial <track-size> value, you can see it has a little + sign next to it, click that and you will be taken to the CSS Values and Units module to find that, “A plus (+) indicates that the preceding type, word, or group occurs one or more times.” This means that we can pass a single track size to grid-auto-rows or multiple track sizes as a space separated list. Below the box is an explanation of what happens if you pass in more than one track size: “If multiple track sizes are given, the pattern is repeated as necessary to find the size of the implicit tracks. The first implicit grid track after the explicit grid receives the first specified size, and so on forwards; and the last implicit grid track before the explicit grid receives the last specified size, and so on backwards.” Therefore with the following CSS, if five implicit rows were needed they would be as follows: 100px 1fr auto 100px 1fr .grid { display: grid; grid-auto-rows: 100px 1fr auto; } Initial We can now move to the next line in the box, and you’ll be glad to know that it isn’t going to require as much unpacking! This simply defines the initial value for grid-auto-rows. If you do not specify anything, created rows will be auto sized. All CSS properties have an initial value that they will use if they are invoked as part of the usage of the specification they are in, but you do not set a value for them. In the case of grid-auto-rows it is used whenever rows are created in the implicit grid, so it needs to have a value to be used even if you do not set one. Applies to This line tells us what this property is used for. Some properties are used in multiple places. For example if you look at the definition for justify-content in the Box Alignment specification you can see it is used in multicol containers, flex containers, and grid containers. In our case the property only applies for grid containers. Inherited This tells us if the property can be inherited from a parent element if it is not set. In the case of grid-auto-rows it is not inherited. A property such as color is inherited, so you do not need to set it on each element. Percentages Are percentages allowed for this property, and if so how are they calculated. In this case we are referred to the definition for grid-template-columns and grid-template-rows where we discover that the percentage is from the corresponding dimension of the content area. Media This defines the media group that the property belongs to. In this case visual. Computed Value This details how the value is resolved. The grid-auto-rows property again refers to track sizing as defined for grid-template-columns and grid-template-rows, which tells us the computed value is as specified with lengths made absolute. Canonical Order If you have a property–generally a shorthand property–which takes multiple values in a set order, then those values need to be serialized in the order detailed in the grammar for that property. In general you don’t need to worry about this value in the table. Animation Type This details whether the property can be animated, and if so what type of animation. This is useful if you are trying to animate something and not getting the result that you expect. Note that just because something is listed in the spec as animatable does not mean that browsers will have implemented animation for that property yet! That’s (mostly) it! Sometimes the property will have additional examples - there is one underneath the table for grid-auto-rows. These are worth looking at as they will highlight usage of the property that the spec editor has felt could use an example. There may also be some additional text explaining anythign specific to this property. In selecting grid-auto-rows I chose a fairly complex property in terms of the work we needed to do to unpack the value. Many properties are far simpler than this. However ultimately, even when you come across a complex value, it really is just a case of stepping through the definitions until you come to the bottom of the rabbit hole. Being able to work out what is valid for each property is incredibly useful. It means you don’t waste time trying to use a value that doesn’t work for that property. You also may find that there are values you weren’t aware of, that solve problems for you. Further reading Specifications are not designed to be user manuals, and while they often contain examples, these are pretty terse as they need to be clear to demonstrate their particular point. The manual for the Web Platform is MDN Web Docs. Pairing reading a specification with the examples and information on an MDN property page such as the one for grid-auto-rows is a really great way to ensure that you have all the information and practical usage examples you might need. You may also find useful: Value Definition Syntax on MDN. The MDN Glossary defines many common terms. Understanding the CSS Property Value Syntax goes into more detail in terms of reading the syntax. How to read W3C Specs - from 2001 but still relevant. I hope this article has gone some way to demystify CSS specifications for you. Even if the specifications are not your preferred first stop to learn about new CSS, being able to go directly to the source and avoid having your understanding filtered by someone else, can be very useful indeed. 2018 Rachel Andrew rachelandrew 2018-12-14T00:00:00+00:00 https://24ways.org/2018/researching-a-property-in-the-css-specifications/ code
131 Random Lines Made With Mesh I know that Adobe Illustrator can be a bit daunting for people who aren’t really advanced users of the program, but you would be amazed by how easy you can create cool effects or backgrounds. In this short tutorial I show you how to create a cool looking background only in 5 steps. Step 1 – Create Lines Create lines using random widths and harmonious suitable colors. If you get stuck on finding the right colors, check out Adobe’s Kuler and start experimenting. Step 2 – Convert Strokes to Fills Select all lines and convert them to fills. Go to the Object menu, select Path > Outline Stroke. Select the Rectangle tool and draw 1 big rectangle on top the lines. Give the rectangle a suitable color. With the rectangle still selected, go to the Object menu, select Arrange > Send to Back. Step 3 – Convert to Mesh Select all objects by pressing the command key (for Mac users), control key (for Windows users) + the “a” key. Go to the Object menu and select the Envelope Distort > Make with Mesh option. Enter 2 rows and 2 columns. Check the preview box to see what happens and click the OK button. Step 4 – Play Around with The Mesh Points Play around with the points of the mesh using the Direct Selection tool (the white arrow in the Toolbox). Click on the top right point of the mesh. Once you’re starting to drag hold down the shift key and move the point upwards. Now start dragging the bezier handles on the mesh to achieve the effect as shown in the above picture. Of course you can try out all kind of different effects here. The Final Result This is an example of how the final result can look. You can try out all kinds of different shapes dragging the handles of the mesh points. This is just one of the many results you can get. So next time you haven’t got inspiration for a background of a header, a banner or whatever, just experiment with a few basic shapes such as lines and try out the ‘Envelope Distort’ options in Illustrator or the ‘Make with Mesh’ option and experiment, you’ll be amazed by the unexpected creative results. 2006 Veerle Pieters veerlepieters 2006-12-08T00:00:00+00:00 https://24ways.org/2006/random-lines-made-with-mesh/ design
248 How to Use Audio on the Web I know what you’re thinking. I never never want to hear sound anywhere near a browser, ever ever, wow! 🙉 You’re having flashbacks, flashbacks to the days of yore, when we had a <bgsound> element and yup did everyone think that was the most rad thing since <blink>. I mean put those two together with a <marquee>, only use CSS colour names, make sure your borders were all set to ridge and you’ve got yourself the neatest website since 1998. The sound played when the website loaded and you could play a MIDI file as well! Everyone could hear that wicked digital track you chose. Oh, surfing was gnarly back then. Yes it is 2018, the end of in fact, soon to be 2019. We are certainly living in the future. Hoverboards self driving cars, holodecks VR headsets, rocket boots drone racing, sound on websites get real, Ruth. We can’t help but be jaded, even though the <bgsound> element is depreciated, and the autoplay policy appeared this year. Although still in it’s infancy, the policy “controls when video and audio is allowed to autoplay”, which should reduce the somewhat obtrusive playing of sound when a website or app loads in the future. But then of course comes the question, having lived in a muted present for so long, where and why would you use audio? ✨ Showcase Time ✨ There are some incredible uses of audio on websites today. This is my personal favourite futurelibrary.no, a site from Norway chronicling books that have been published from a forest of trees planted precisely for the books themselves. The sound effects are lovely, adding to the overall experience. futurelibrary.no Another site that executes this well is pottermore.com. The Hogwarts WebGL simulation uses both sound effects and ambient background music and gives a great experience. The button hovers are particularly good. pottermore.com Eighty-six and a half years is a beautiful narrative site, documenting the musings of an eighty-six and a half year old man. The background music playing on this site is not offensive, it adds to the experience. Eighty-six and a half years Sound can be powerful and in some cases useful. Last year I wrote about using them to help validate forms. Audiochart is a library which “allows the user to explore charts on web pages using sound and the keyboard”. Ben Byford recorded voice descriptions of the pages on his website for playback should you need or want it. There is a whole area of accessibility to be explored here. Then there’s education. Fancy beginning with some piano in the new year? flowkey.com is a website which allows you to play along and learn at the same time. Need to brush up on your music theory? lightnote.co takes you through lessons to do just that, all audio enhanced. Electronic music more your thing? Ableton has your back with learningmusic.ableton.com, a site which takes you through the process of composing electronic music. A website, all made possible through the powers with have with the Web Audio API today. lightnote.co learningmusic.ableton.com Considerations Yes, tis the season, let’s be more thoughtful about our audios. There are some user experience patterns to begin with. 86andahalfyears.com tells the user they are about to ‘enter’ the site and headphones are recommended. This is a good approach because it a) deals with the autoplay policy (audio needs to be instigated by a user gesture) and b) by stating headphones are recommended you are setting the users expectations, they will expect sound, and if in a public setting can enlist the use of a common electronic device to cause less embarrassment. Eighty-six and a half years Allowing mute and/or volume control clearly within the user interface is a good idea. It won’t draw the user out of the experience, it’ll give more control to the user about what audio they want to hear (they may not want to turn down the volume of their entire device), and it’s less thought to reach for a very visible volume than to fumble with device settings. Indicating that sound is playing is also something to consider. Browsers do this by adding icons to tabs, but this isn’t always the first place to look for everyone. To The Future So let’s go! We see amazing demos built with Web Audio, and I’m sure, like me, they make you think, oh wow I wish I could do that / had thought of that / knew the first thing about audio to begin to even conceive that. But audio doesn’t actually need to be all bells and whistles (hey, it’s Christmas). Starting, stopping and adjusting simple panning and volume might be all you need to get started to introduce some good sound design in your web design. Isn’t it great then that there’s a tutorial just for that! Head on over to the MDN Web Audio API docs where the Using the Web Audio API article takes you through playing and pausing sounds, volume control and simple panning (moving the sound from left to right on stereo speakers). This year I believe we have all experienced the web as a shopping mall more than ever. It’s shining store fronts, flashing adverts, fast food, loud noises. Let’s use 2019 to create more forests to explore, oceans to dive and mountains to climb. 2018 Ruth John ruthjohn 2018-12-22T00:00:00+00:00 https://24ways.org/2018/how-to-use-audio-on-the-web/ design
240 My CSS Wish List I love Christmas. I love walking around the streets of London, looking at the beautifully decorated windows, seeing the shiny lights that hang above Oxford Street and listening to Christmas songs. I’m not going to lie though. Not only do I like buying presents, I love receiving them too. I remember making long lists that I would send to Father Christmas with all of the Lego sets I wanted to get. I knew I could only get one a year, but I would spend days writing the perfect list. The years have gone by, but I still enjoy making wish lists. And I’ll tell you a little secret: my mum still asks me to send her my Christmas list every year. This time I’ve made my CSS wish list. As before, I’d be happy with just one present. Before I begin… … this list includes: things that don’t exist in the CSS specification (if they do, please let me know in the comments – I may have missed them); others that are in the spec, but it’s incomplete or lacks use cases and examples (which usually means that properties haven’t been implemented by even the most recent browsers). Like with any other wish list, the further down I go, the more unrealistic my expectations – but that doesn’t mean I can’t wish. Some of the things we wouldn’t have thought possible a few years ago have been implemented and our wishes fulfilled (think multiple backgrounds, gradients and transformations, for example). The list Cross-browser implementation of font-size-adjust When one of the fall-back fonts from your font stack is used, rather than the preferred (first) one, you can retain the aspect ratio by using this very useful property. It is incredibly helpful when the fall-back fonts are smaller or larger than the initial one, which can make layouts look less polished. What font-size-adjust does is divide the original font-size of the fall-back fonts by the font-size-adjust value. This preserves the x-height of the preferred font in the fall-back fonts. Here’s a simple example: p { font-family: Calibri, "Lucida Sans", Verdana, sans-serif; font-size-adjust: 0.47; } In this case, if the user doesn’t have Calibri installed, both Lucida Sans and Verdana will keep Calibri’s aspect ratio, based on the font’s x-height. This property is a personal favourite and one I keep pointing to. Firefox supported this property from version three. So far, it’s the only browser that does. Fontdeck provides the font-size-adjust value along with its fonts, and has a handy tool for calculating it. More control over overflowing text The text-overflow property lets you control text that overflows its container. The most common use for it is to show an ellipsis to indicate that there is more text than what is shown. To be able to use it, the container should have overflow set to something other than visible, and white-space: nowrap: div { white-space: nowrap; width: 100%; overflow: hidden; text-overflow: ellipsis; } This, however, only works for blocks of text on a single line. In the wish list of many CSS authors (and in mine) is a way of defining text-overflow: ellipsis on a block of multiple text lines. Opera has taken the first step and added support for the -o-ellipsis-lastline property, which can be used instead of ellipsis. This property is not part of the CSS3 spec, but we could certainly make good use of it if it were… WebKit has -webkit-line-clamp to specify how many lines to show before cutting with an ellipsis, but support is patchy at best and there is no control over where the ellipsis shows in the text. Many people have spent time wrangling JavaScript to do this for us, but the methods used are very processor intensive, and introduce a JavaScript dependency. Indentation and hanging punctuation properties You might notice a trend here: almost half of the items in this list relate to typography. The lack of fine-grained control over typographical detail is a general concern among designers and CSS authors. Indentation and hanging punctuation fall into this category. The CSS3 specification introduces two new possible values for the text-indent property: each-line; and hanging. each-line would indent the first line of the block container and each line after a forced line break; hanging would invert which lines are affected by the indentation. The proposed hanging-punctuation property would allow us to specify whether opening and closing brackets and quotes should hang outside the edge of the first and last lines. The specification is still incomplete, though, and asks for more examples and use cases. Text alignment and hyphenation properties Following the typographic trend of this list, I’d like to add better control over text alignment and hyphenation properties. The CSS3 module on Generated Content for Paged Media already specifies five new hyphenation-related properties (namely: hyphenate-dictionary; hyphenate-before and hyphenate-after; hyphenate-lines; and hyphenate-character), but it is still being developed and lacks examples. In the text alignment realm, the new text-align-last property allows you to define how the last line of a block (or a line just before a forced break) is aligned, if your text is set to justify. Its value can be: start; end; left; right; center; and justify. The text-justify property should also allow you to have more control over text set to text-align: justify but, for now, only Internet Explorer supports this. calc() This is probably my favourite item in the list: the calc() function. This function is part of the CSS3 Values and Units module, but it has only been implemented by Firefox (4.0). To take advantage of it now you need to use the Mozilla vendor code, -moz-calc(). Imagine you have a fluid two-column layout where the sidebar column has a fixed width of 240 pixels, and the main content area fills the rest of the width available. This is how you could create that using -moz-calc(): #main { width: -moz-calc(100% - 240px); } Can you imagine how many hacks and headaches we could avoid were this function available in more browsers? Transitions and animations are really nice and lovely but, for me, it’s the ability to do the things that calc() allows you to that deserves the spotlight and to be pushed for implementation. Selector grouping with -moz-any() The -moz-any() selector grouping has been introduced by Mozilla but it’s not part of any CSS specification (yet?); it’s currently only available on Firefox 4. This would be especially useful with the way HTML5 outlines documents, where we can have any number of variations of several levels of headings within numerous types of containers (think sections within articles within sections…). Here is a quick example (copied from the Mozilla blog post about the article) of how -moz-any() works. Instead of writing: section section h1, section article h1, section aside h1, section nav h1, article section h1, article article h1, article aside h1, article nav h1, aside section h1, aside article h1, aside aside h1, aside nav h1, nav section h1, nav article h1, nav aside h1, nav nav h1, { font-size: 24px; } You could simply write: -moz-any(section, article, aside, nav) -moz-any(section, article, aside, nav) h1 { font-size: 24px; } Nice, huh? More control over styling form elements Some are of the opinion that form elements shouldn’t be styled at all, since a user might not recognise them as such if they don’t match the operating system’s controls. I partially agree: I’d rather put the choice in the hands of designers and expect them to be capable of deciding whether their particular design hampers or improves usability. I would say the same idea applies to font-face: while some fear designers might go crazy and litter their web pages with dozens of different fonts, most welcome the freedom to use something other than Arial or Verdana. There will always be someone who will take this freedom too far, but it would be useful if we could, for example, style the default Opera date picker: <input type="date" /> or Safari’s slider control (think star movie ratings, for example): <input type="range" min="0" max="5" step="1" value="3" /> Parent selector I don’t think there is one CSS author out there who has never come across a case where he or she wished there was a parent selector. There have been many suggestions as to how this could work, but a variation of the child selector is usually the most popular: article < h1 { … } One can dream… Flexible box layout The Flexible Box Layout Module sounds a bit like magic: it introduces a new box model to CSS, allowing you to distribute and order boxes inside other boxes, and determine how the available space is shared. Two of my favourite features of this new box model are: the ability to redistribute boxes in a different order from the markup the ability to create flexible layouts, where boxes shrink (or expand) to fill the available space Let’s take a quick look at the second case. Imagine you have a three-column layout, where the first column takes up twice as much horizontal space as the other two: <body> <section id="main"> </section> <section id="links"> </section> <aside> </aside> </body> With the flexible box model, you could specify it like this: body { display: box; box-orient: horizontal; } #main { box-flex: 2; } #links { box-flex: 1; } aside { box-flex: 1; } If you decide to add a fourth column to this layout, there is no need to recalculate units or percentages, it’s as easy as that. Browser support for this property is still in its early stages (Firefox and WebKit need their vendor prefixes), but we should start to see it being gradually introduced as more attention is drawn to it (I’m looking at you…). You can read a more comprehensive write-up about this property on the Mozilla developer blog. It’s easy to understand why it’s harder to start playing with this module than with things like animations or other more decorative properties, which don’t really break your layouts when users don’t see them. But it’s important that we do, even if only in very experimental projects. Nested selectors Anyone who has never wished they could do something like the following in CSS, cast the first stone: article { h1 { font-size: 1.2em; } ul { margin-bottom: 1.2em; } } Even though it can easily turn into a specificity nightmare and promote redundancy in your style sheets (if you abuse it), it’s easy to see how nested selectors could be useful. CSS compilers such as Less or Sass let you do this already, but not everyone wants or can use these compilers in their projects. Every wish list has an item that could easily be dropped. In my case, I would say this is one that I would ditch first – it’s the least useful, and also the one that could cause more maintenance problems. But it could be nice. Implementation of the ::marker pseudo-element The CSS Lists module introduces the ::marker pseudo-element, that allows you to create custom list item markers. When an element’s display property is set to list-item, this pseudo-element is created. Using the ::marker pseudo-element you could create something like the following: Footnote 1: Both John Locke and his father, Anthony Cooper, are named after 17th- and 18th-century English philosophers; the real Anthony Cooper was educated as a boy by the real John Locke. Footnote 2: Parts of the plane were used as percussion instruments and can be heard in the soundtrack. where the footnote marker is generated by the following CSS: li::marker { content: "Footnote " counter(notes) ":"; text-align: left; width: 12em; } li { counter-increment: notes; } You can read more about how to use counters in CSS in my article from last year. Bear in mind that the CSS Lists module is still a Working Draft and is listed as “Low priority”. I did say this wish list would start to grow more unrealistic closer to the end… Variables The sight of the word ‘variables’ may make some web designers shy away, but when you think of them applied to things such as repeated colours in your stylesheets, it’s easy to see how having variables available in CSS could be useful. Think of a website where the main brand colour is applied to elements like the main text, headings, section backgrounds, borders, and so on. In a particularly large website, where the colour is repeated countless times in the CSS and where it’s important to keep the colour consistent, using variables would be ideal (some big websites are already doing this by using server-side technology). Again, Less and Sass allow you to use variables in your CSS but, again, not everyone can (or wants to) use these. If you are using Less, you could, for instance, set the font-family value in one variable, and simply call that variable later in the code, instead of repeating the complete font stack, like so: @fontFamily: Calibri, "Lucida Grande", "Lucida Sans Unicode", Helvetica, Arial, sans-serif; body { font-family: @fontFamily; } Other features of these CSS compilers might also be useful, like the ability to ‘call’ a property value from another selector (accessors): header { background: #000000; } footer { background: header['background']; } or the ability to define functions (with arguments), saving you from writing large blocks of code when you need to write something like, for example, a CSS gradient: .gradient (@start:"", @end:"") { background: -webkit-gradient(linear, left top, left bottom, from(@start), to(@end)); background: -moz-linear-gradient(-90deg,@start,@end); } button { .gradient(#D0D0D0,#9F9F9F); } Standardised comments Each CSS author has his or her own style for commenting their style sheets. While this isn’t a massive problem on smaller projects, where maybe only one person will edit the CSS, in larger scale projects, where dozens of hands touch the code, it would be nice to start seeing a more standardised way of commenting. One attempt at creating a standard for CSS comments is CSSDOC, an adaptation of Javadoc (a documentation generator that extracts comments from Java source code into HTML). CSSDOC uses ‘DocBlocks’, a term borrowed from the phpDocumentor Project. A DocBlock is a human- and machine-readable block of data which has the following structure: /** * Short description * * Long description (this can have multiple lines and contain <p> tags * * @tags (optional) */ CSSDOC includes a standard for documenting bug fixes and hacks, colours, versioning and copyright information, amongst other important bits of data. I know this isn’t a CSS feature request per se; rather, it’s just me pointing you at something that is usually overlooked but that could contribute towards keeping style sheets easier to maintain and to hand over to new developers. Final notes I understand that if even some of these were implemented in browsers now, it would be a long time until all vendors were up to speed. But if we don’t talk about them and experiment with what’s available, then it will definitely never happen. Why haven’t I mentioned better browser support for existing CSS3 properties? Because that would be the same as adding chocolate to your Christmas wish list – you don’t need to ask, everyone knows you want it. The list could go on. There are dozens of other things I would love to see integrated in CSS or further developed. These are my personal favourites: some might be less useful than others, but I’ve wished for all of them at some point. Part of the research I did while writing this article was asking some friends what they would add to their lists; other than a couple of items I already had in mine, everything else was different. I’m sure your list would be different too. So tell me, what’s on your CSS wish list? 2010 Inayaili de León Persson inayailideleon 2010-12-03T00:00:00+00:00 https://24ways.org/2010/my-css-wish-list/ code
119 Rocking Restrictions I love my job. I live my job. For every project I do, I try to make it look special. I’ll be honest: I have a fetish for comments like “I never saw anything like that!” or, “I wish I thought of that!”. I know, I have an ego-problem. (Eleven I’s already) But sometimes, you run out of inspiration. Happens to everybody, and everybody hates it. “I’m the worst designer in the world.” “Everything I designed before this was just pure luck!” No it wasn’t. Countless articles about finding inspiration have already been written. Great, but they’re not the magic potion you’d expect them to be when you need it. Here’s a list of small tips that can have immediate effect when applying them/using them. Main theme: Liberate yourself from the designers’ block by restricting yourself. Do’s Grids If you aren’t already using grids, you’re doing something wrong. Not only are they a great help for aligning your design, they also restrict you to certain widths and heights. (For more information about grids, I suggest you read Mark Boulton’s series on designing grid systems. Oh, he’s also publishing a book I think.) So what’s the link between grids and restrictions? Instead of having the option to style a piece of layout with a width of 1 to 960 pixels, you have to choose from values like 60 pixels, 140, 220, 300, … Start small Having a hard time finding a style for the layout, why don’t you start with one small object? No, not that small object, I meant a piece of a form, or a link, or try styling your headers (h1 – h6). Let’s take a submit button of a form: it’s small, but needs much attention. People will click it. People will hover it. Maybe sometimes it’s disabled? Also: a button needs to look like a button, so typically it requires more styling then a regular link. Once you’ve got the button, move on, following the button’s style. Color palettes There are lots of resources on the web for finding inspiration for color palettes. Some of the most famous are COLOURlovers, wear palettes and Adobe’s Kuler. Browse through them (or create your own from a picture), pick a color palette you like and which works with the subject you’re handling, and stick with it. 4-5 colors, maybe with some tonal variations, but that’s it. Fonts There aren’t many fonts available for the web (Richard Rutter has a great article on this subject), but you’d be surprised how long they go. A simple text-transform: uppercase; or font-style: italic; can change a dull looking font into something entirely fresh. Play around with the fonts you want to use and the variations you’ll be using, and make a list. Pick five combinations of fonts and their variations, and stick with them throughout the layout. Single-task Most of us use multiple monitors. They’re great to increase productivity, but make it harder to focus on a single task. Here’s what you do: try using only your smallest monitor. Maybe it’s the one from your laptop, maybe it’s an old 1024×768 you found in the attic. Having Photoshop (or Fireworks or…) taking over your entire workspace blocks out all the other distractions on your screen, and works quite liberating. Mute everything… …but not entirely. I noticed I was way more focused when I set NetNewsWire to refresh it’s feeds only once every two hours. After two hours, I need a break anyway. Turning off Twitterrific was a mistake, as it’s my window to the world, and it’s the place where the people I like to call colleagues live. You can’t exactly ask them to bring you a cup of coffee when they go to the vending machine, but they do keep you fresh, and it stops you from going human-shy. Instead I changed the settings to not play a notification sound when new Tweets arrive so it doesn’t disturb me when I’m zoning. Don’ts CSS galleries Don’t start browsing all kinds of CSS galleries. Either you’ll feel bad, or you just start using elements in a way you can’t call “inspired” anymore. Instead gather your own collection of inspiration. Example: I use LittleSnapper in which I dump everything I find inspiring. This goes from a smart layout idea, to a failed picture someone posted on Flickr. Everything is inspiring. Panicking Don’t panic. It’s the worst thing you could do. Instead, get away from the computer, and go to bed early. A good night of sleep combined with a hot/cold shower can give you a totally new perspective on a design. Got a deadline by tomorrow? Well, you should’ve started earlier. Got a good excuse to start on this design this late? Tell your client it was either that or a bad design. 120-hour work-week Don’t work all day long, including evenings and early mornings. Write off that first hour, you don’t really think you’ll get anything productive done before 9AM?! I don’t even think you should work on one and the same design all day long. If you’re stuck, try working in blocks of 1 or 2 hours on a certain design. Mixing projects isn’t for everyone, but it might just do the trick for you. Summary Use grids, not only for layout purposes. Pick a specific element to start with. Use a colour palette. Limit the amount of fonts and variations you’ll use. Search for the smallest monitor around, and restrict yourself to that one. Reduce the amount of noise. Don’t start looking on the internet for inspiration. Build your own little inspirarchive. Work in blocks. 2008 Tim Van Damme timvandamme 2008-12-14T00:00:00+00:00 https://24ways.org/2008/rocking-restrictions/ process
212 Refactoring Your Way to a Design System I love refactoring code. Absolutely love it. There’s something about taking a piece of UI or a bit of code and reworking it in a way that is simpler, modular, and reusable that makes me incredibly happy. I also love design systems work. It gives hybrids like me a home. It seems like everyone is talking about design systems right now. Design systems teams are perfect for those who enjoy doing architectural work and who straddle the line between designer and developer. Una Kravets recently identified some of the reasons that design systems fail, and chief among them are lack of buy-in, underlying architecture, and communication. While it’s definitely easier to establish these before project work begins, that doesn’t mean it is the only path to success. It’s a privilege to work on a greenfield project, and one that is not afforded to many. Companies with complex and/or legacy codebases may not be able to support a full rewrite of their product. In addition, many people feel overwhelmed at the thought of creating a complete system and are at a loss of how or where to even begin the process. This is where refactoring comes into play. According to Martin Fowler, “refactoring is the process of changing a software system in such a way that it does not alter the external behavior of the code yet improves its internal structure.” It’s largely invisible work, and if you do it right, the end user will never know the difference. What it will do is provide a decent foundation to begin more systematic work. Build a solid foundation When I was first asked to create Pantsuit, the design system for Hillary for America, I was tasked with changing our codebase to be more modular and scalable, without changing the behavior or visual design of the UI. We needed a system in place that would allow for the rapid creation of new projects while maintaining a consistent visual language. In essence, I was asked to refactor our code into a design system. During that refactor, I focused the majority of my efforts on creating a scalable architecture based on the UI components in a single workflow. Since I needed to maintain a 1:1 parity with production, the only changes I could create were under-the-hood. I started with writing coding standards and deciding on a CSS architecture that I would then use as I rewrote sections of the codebase. If you already have these in place, great! If not, then this is an excellent place to start. Even if your dream of a design system is never fully realized, having a coding philosophy and architecture in place will still have far-reaching benefits and implications. I want to note that if your refactor includes creating new coding standards or a CSS architecture, don’t try to switch everything over right away. Instead, focus on a single new feature and isolate/encapsulate your work from the rest of the codebase. Focus on the features The key principle to cleaning up a complex codebase is to always refactor in the service of a feature. — Max Kanat-Alexander Refactoring for the sake of refactoring can easily lead to accusations of misused time and lack of results. Another danger of refactoring is that it can turn into yak-shaving if you aren’t disciplined in your approach. To that end, tying your refactored components to feature work is a great way to limit scope and reduce the rest of unintended changes. For example, the initial work on Pantsuit focused only on components related to the donations flow. Every line of code I wrote was in service to improving the maintainability and modularity of that UI. Because we didn’t have any standards in place, I started with those. From there, I identified all the components present in every step of the donations flow, which included some type styles, buttons, form inputs and error states. Then came the refactor of each individual component. Finally, I reintegrated the newly refactored components into the existing donations flow and tested it against production, checking for visual and behavioral diffs. At the end of this process, I had the beginning of a design system that would grow to serve over 50 applications, and a case study to demonstrate its effectiveness. Ideally, you’ll want to get buy-in from your stakeholders and product owners before you begin any design systems work. However, in the absence of buy-in, linking your work to new feature development is a good way to both limit the scope of your refactor and jump start component creation. In addition, if you’re still trying to convince your team of the benefits of a design system, starting small and using the newly refactored, feature-driven work as a case study is one way showcase a design systems’ value. By providing a concrete example of how working towards a design system contributed to the project’s success, you’re gathering the data necessary to secure buy-in for a larger-scale effort. It’s a great way to show value, rather than just talking about it. Show, don’t tell Perhaps the most important thing you can do for any design system is to document it. The key is to create a frictionless way to keep the documentation up-to-date, otherwise no one will contribute to it, and in turn, it will become obsolete and useless. There are lots of tools out there to help you get started documenting your new system. One of my favorites is KSS, which parses comments in the code and uses them to generate a style guide. For Pantsuit, I used the node version of KSS, along with a template to quickly spin up a documentation site. I’ve listed just a few tools below; for even more, check out the tools sections of styleguides.io. Fractal Pattern Lab Drizzle Fabricator Astrum Catalog Regardless of what tool you settle on, it needs to integrate well with your current workflow. Conclusion: always be refactoring If you’re not lucky enough to be able to start a new design system from scratch, you can start small and work on a single feature or component. With each new project comes a new opportunity to flesh out a new part of the system, and another potential case study to secure buy-in and showcase its value. Make sure to carefully and thoroughly document each new portion of the system as it’s built. After a few projects, you’ll find yourself with a decent start to a design system. Good luck, and happy holidays! Further reading: Why Design Systems Fail CSS Architecture for Design Systems Refactoring: Improving the Design of Existing Code Refactoring CSS: The Three I’s Refactoring is About Features 2017 Mina Markham minamarkham 2017-12-23T00:00:00+00:00 https://24ways.org/2017/refactoring-your-way-to-a-design-system/ code
45 Is Agile Harder for Agencies? I once sat in a pitch meeting and watched a new business exec tell a potential client that his agency followed an agile workflow process at all times. The potential client nodded wisely, and they both agreed that agile was indeed the way to go. The meeting progressed and they signed off on a contract for a massive project, to be delivered in a standard waterfall fashion, with all manner of phases and key deliverables. Of course both of them left the meeting perfectly happy, because neither of them knew nor cared what an agile workflow process might be. That was about five years ago. As 2015 heaves into view I think it’s fair to say that attitudes have changed. Perhaps the same number of people claim to do Agile™ now as in 2010, but I think more of them are telling the truth. As a developer in an agency that works primarily with larger organisations, this year I have started to see a shift from agencies pushing agile methodologies with their clients, to clients requesting and even demanding agile practices from their agencies. Only a couple of years ago this would have been unusual behaviour. So what’s the problem? We should be happy then, no? Those of us in agencies will get to spend more time delivering great products, and less time arguing over out-of-date functional specs or battling through an adversarial change management procedure because somebody had a good idea during development rather than planning. We get to be a little bit more like our brothers and sisters in vaunted teams like the Government Digital Service, which is using agile approaches to great effect on projects that have a real benefit to their users. Almost. Unfortunately, it seems to be the case that adhering to an agile framework such as scrum is more difficult within an agency/client structure than it is for an in-house development team. This is no surprise. The Agile Manifesto was written in 2001 by a group of software developers for their own use. Many of the underlying principles of a framework like Scrum assume the existence of an in-house team, working on a highly technical project, and working for the business that employs them. The agency/client model must to some extent be retrofitted into agile frameworks. It can be done though, and there are plenty of agencies out there doing it well. This article isn’t meant to be another introduction to agile techniques – there are too many of those online already. This article is for people just dipping their toes into this way of working. I’ve laid out a few of the key reasons why adopting a more fully agile approach seems difficult, at least initially, for those of us working in agencies. 1. Agile asks more of your clients When a team adopts Scrum everyone has to get used to a number of unfamiliar roles and rituals. Few team members have a steeper learning curve than the person designated as the product owner. The product owner carries a lot of weight on their shoulders. They have to uphold the overall vision for the project. They are also meant to be the primary author of the project’s user stories (short atomic descriptions of project features which are testable and relate to a real business need). They should own this list of stories (called a backlog) and should be able to prioritise the order in which the stories are developed, to ensure that the project is delivering real value to the business early and often. When a burst of work is completed (bursts of work in Scrum are called sprints), the product owner leads a review or show-and-tell session with the wider project stakeholders. The product owner needs to understand the work that has been completed, and must champion it to the business. Finally, and most importantly, the product owner is responsible for managing the feedback and requests from stakeholders in such a way that they don’t derail the project team’s agreed workload for any given sprint, without upsetting or offending any of the stakeholders – some of whom may outrank the product owner. If you follow that spec, this is a job for a superhuman in any organisational context. And within the agency/client structure this superhuman needs to be client-side for the process to be at its most effective. So your client, who in the past might have briefed a project to an agency team and then had the work presented back to them every few weeks, is now asked to be involved with the team on a daily basis; to fight on behalf of the team when new or difficult requests come in from senior figures within their organisation; and to present the agency’s work to their own colleagues after each sprint. It’s a big change if all that gets dropped into someone’s lap without warning. There are several ways agencies can mitigate this issue. The ScrumAlliance suggests some alternative ways to structure the product owner role. The approach I have taken in the past is simply to start slow, and gradually move more of the product owner role over to the client side as and when they feel comfortable with it. If you’re working together long-term on a project, and you both see tangible improvements in the quality of the work after adopting an agile process, then your client is more likely to be open to further changes as the partnership progresses. 2. My client wants fixed costs, fixed deadlines and a fixed scope I know. Mine too. Of course they do – it is the way that agencies and clients have agreed to work in digital and other creative service industries for a very long time. On both sides of the fence we’re used to thinking about projects in this way. Of the three, fixing scope is the one that agile purists would rail hardest against. The more time we spend working on digital projects, the less sense it makes. James Archer, CEO of UI/UX design agency Forty puts it like this: For me, the Agile approach is really about acknowledging that disturbing truth that every project manager knows, but has trouble admitting. The truth that the project plan is wrong. Scope creep. Change orders. Shifting priorities. New directions. We act shocked and appalled when those things happen during our carefully planned project, even though they happen on every project ever. Successful relationships require trust and honesty, and we shouldn’t be afraid of discussing this aspect of project management. If you do move away from a fixed scope of work, then the other two items (costs and timings) can be fixed – more or less. If you can get your clients to buy into this from a standing start then you are doing well. In fact you probably deserve a promotion. For most of us this is a continual discussion. Anyway, as soon as you’ve made headway on the argument that it makes little or no sense to try and fix the scope of a digital project, you usually run into a related concern, which we’ll look at next. 3. Fear of uncontrolled costs We all know that a dog is for life, not just for Christmas. At this time of year perhaps we should reiterate to everyone that digital products and services also need support and love once we have taken the decision to bring them into the world. More organisations are realising that their investment in digital platforms should be viewed as an operational expenditure rather than a capital expenditure. But from time to time we will find ourselves working on projects for people who have a finite amount of money to invest in a product at a given point in time. When agencies start talking about these projects as rolling investments those responsible can understandably worry about their costs running out of control. There’s another factor at play here. Agile, on the whole, prefers to derive a cost for services from the hours a team spends working on a project. In other industries this is referred to as charging for time and materials, and there seems to be an ingrained distrust in this approach among people in general. See, for example, the Citizens Advice Bureau’s “Top tips for employing a builder”: “Bear in mind that if you pay a daily rate, this makes it easier for a builder to string the work out and get more money so agree what you will do if the job takes longer than expected.” It’s hard not to feel stung if you are in the builder’s shoes here, as we are when we’re talking about our role as an agency. But if you’ve ever haggled with a builder over time and materials, and also moaned about your clients misunderstanding agile methods, take a moment to reflect on the similarities from your client’s point of view. Again, there are some things we can do to mitigate this issue. Some agencies put in place a service level agreement around their team’s velocity (an agile-related term related to how much work a team delivers in any given sprint) and this can help. As the industry moves further towards a long-term approach to investment in digital I hope this fear will subside. But that shift in approach leads to the final concern I want to address. 4. Agency structures need shaking up If you work for a company that has spent many years developing a business model around the waterfall process, you may have to break through many layers of entrenched thinking in order to establish new practices and effect organisational change. There are consultancies that exist specifically to help agencies through their own agile transformation. One of these companies, AgencyAgile, provides a helpful list of common pitfalls. They emphasise the need to look at your whole agency’s structure, rather than simply encouraging project teams to adopt new workflows. Even awesomely run Agile projects can have a limited impact on the overall organization. If you’re serious about changing the way your company approaches projects then try talking to people who sit outside the usual project delivery team. Speak to the finance department if you have one, and try to convince your senior management team if they’re not already on board. And definitely speak to your new business people, who go out there and win the projects you get to work on. It’s these people who need to understand the potential business benefits of working in a new way, and also which of their existing habits and behaviours they might need to change to accommodate a new approach. Otherwise you’ll find yourself with a team of designers, developers and project managers who are ready and waiting to deliver work in an iterative and collaborative way, but by the time they get hold of the project a cost has already been agreed, a deadline has been imposed, and a functional requirements document has been painstakingly put together. Nobody wins in this situation. Conclusion So where should we go from here? I certainly don’t have hard and fast answers – I’m not sure that they exist in a one-size-fits-all approach for agencies. There are plenty of smart people thinking about this problem. It’s a hot topic right now. Earlier in the year a London-based meetup was established called Agile for Agencies. If you’re in the capital and want to discuss these issues with your peers it’s a great opportunity to do so. I’ve mentioned James Archer and Forty already. Both James and Paul Boag have written in the last twelve months on this subject. They both come out on the side of the argument that suggests you adopt agile principles, but don’t have to worry about the rituals if they don’t fit in with your practices. Personally, I think the rituals and the discipline mandated by an agile framework like Scrum can provide a great deal of value to your team, even it if is hard to implement within an agency culture that has traditionally structured its work and its services in another way. In whatever way you figure out the details, when your teams collaborate with your clients rather than work for them at arm’s length, and when everyone prioritises frequent delivery, reflection and iteration over exhaustive scoping and planning, I believe you’ll see a tangible difference in the quality of the work that you create. 2014 Charlie Perrins charlieperrins 2014-12-12T00:00:00+00:00 https://24ways.org/2014/is-agile-harder-for-agencies/ process
304 Five Lessons From My First 18 Months as a Dev I recently moved from Sydney to London to start a dream job with Twitter as a software engineer. A software engineer! Who would have thought. Having started my career as a journalist, the title ‘engineer’ is very strange to me. The notion of writing in first person is also very strange. Journalists are taught to be objective, invisible, to keep yourself out of the story. And here I am writing about myself on a public platform. Cringe. Since I started learning to code I’ve often felt compelled to write about my experience. I want to share my excitement and struggles with the world! But as a junior I’ve been held back by thoughts like ‘whatever you have to say won’t be technical enough’, ‘any time spent writing a blog would be better spent writing code’, ‘blogging is narcissistic’, etc.  Well, I’ve been told that your thirties are the years where you stop caring so much about what other people think. And I’m almost 30. So here goes! These are five key lessons from my first year and a half in tech: Deployments should delight, not dread Lesson #1: Making your deployment process as simple as possible is worth the investment. In my first dev job, I dreaded deployments. We would deploy every Sunday night at 8pm. Preparation would begin the Friday before. A nominated deployment manager would spend half a day tagging master, generating scripts, writing documentation and raising JIRAs. The only fun part was choosing a train gif to post in HipChat: ‘All aboard! The deployment train leaves in 3, 2, 1…” When Sunday night came around, at least one person from every squad would need to be online to conduct smoke tests. Most times, the deployments would succeed. Other times they would fail. Regardless, deployments ate into people’s weekend time — and they were intense. Devs would rush to have their code approved before the Friday cutoff. Deployment managers who were new to the process would fear making a mistake.  The team knew deployments were a problem. They were constantly striving to improve them. And what I’ve learnt from Twitter is that when they do, their lives will be bliss. TweetDeck’s deployment process fills me with joy and delight. It’s quick, easy and stress free. In fact, it’s so easy I deployed code on my first day in the job! Anyone can deploy, at any time of day, with a single command. Rollbacks are just as simple. There’s no rush to make the deployment train. No manual preparation. No fuss. Value — whether in the form of big new features, simple UI improvements or even production bug fixes — can be shipped in an instant. The team assures me the process wasn’t always like this. They invested lots of time in making their deployments better. And it’s clearly paid off. Code reviews need love, time and acceptance Lesson #2: Code reviews are a three-way gift. Every time I review someone else’s code, I help them, the team and myself. Code reviews were another pain point in my previous job. And to be honest, I was part of the problem. I would raise code reviews that were far too big. They would take days, sometimes weeks, to get merged. One of my reviews had 96 comments! I would rarely review other people’s code because I felt too junior, like my review didn’t carry any weight.  The review process itself was also tiring, and was often raised in retrospectives as being slow. In order for code to be merged it needed to have ticks of approval from two developers and a third tick from a peer tester. It was the responsibility of the author to assign the reviewers and tester. It was felt that if it was left to team members to assign themselves to reviews, the “someone else will do it” mentality would kick in, and nothing would get done. At TweetDeck, no-one is specifically assigned to reviews. Instead, when a review is raised, the entire team is notified. Without fail, someone will jump on it. Reviews are seen as blocking. They’re seen to be equally, if not more important, than your own work. I haven’t seen a review sit for longer than a few hours without comments.  We also don’t work on branches. We push single commits for review, which are then merged to master. This forces the team to work in small, incremental changes. If a review is too big, or if it’s going to take up more than an hour of someone’s time, it will be sent back. What I’ve learnt so far at Twitter is that code reviews must be small. They must take priority. And they must be a team effort. Being a new starter is no “get out of jail free card”. In fact, it’s even more of a reason to be reviewing code. Reviews are a great way to learn, get across the product and see different programming styles. If you’re like me, and find code reviews daunting, ask to pair with a senior until you feel more confident. I recently paired with my mentor at Twitter and found it really helpful. Get friendly with feature flagging Lesson #3: Feature flagging gives you complete control over how you build and release a project. Say you’re implementing a new feature. It’s going to take a few weeks to complete. You’ll complete the feature in small, incremental changes. At what point do these changes get merged to master? At what point do they get deployed? Do you start at the back end and finish with the UI, so the user won’t see the changes until they’re ready? With feature flagging — it doesn’t matter. In fact, with feature flagging, by the time you are ready to release your feature, it’s already deployed, sitting happily in master with the rest of your codebase.  A feature flag is a boolean value that gets wrapped around the code relating to the thing you’re working on. The code will only be executed if the value is true. if (TD.decider.get(‘new_feature’)) { //code for new feature goes here } In my first dev job, I deployed a navigation link to the feature I’d been working on, making it visible in the product, even though the feature wasn’t ready. “Why didn’t you use a feature flag?” a senior dev asked me. An honest response would have been: “Because they’re confusing to implement and I don’t understand the benefits of using them.” The fix had to wait until the next deployment. The best thing about feature flagging at TweetDeck is that there is no need to deploy to turn on or off a feature. We set the status of the feature via an interface called Deckcider, and the code makes regular API requests to get the status.  At TweetDeck we are also able to roll our features out progressively. The first rollout might be to a staging environment. Then to employees only. Then to 10 per cent of users, 20 per cent, 30 per cent, and so on. A gradual rollout allows you to monitor for bugs and unexpected behaviour, before releasing the feature to the entire user base. Sometimes a piece of work requires changes to existing business logic. So the code might look more like this: if (TD.decider.get(‘change_to_existing_feature’)) { //new logic goes here } else { //old logic goes here } This seems messy, right? Riddling your code with if else statements to determine which path of logic should be executed, or which version of the UI should be displayed. But at Twitter, this is embraced. You can always clean up the code once a feature is turned on. This isn’t essential, though. At least not in the early days. When a cheeky bug is discovered, having the flag in place allows the feature to be very quickly turned off again. Let data and experimentation drive development Lesson #4: Use data to determine the direction of your product and measure its success. The first company I worked for placed a huge amount of emphasis on data-driven decision making. If we had an idea, or if we wanted to make a change, we were encouraged to “bring data” to show why it was necessary. “Without data, you’re just another person with an opinion,” the chief data scientist would say. This attitude helped to ensure we were building the right things for our customers. Instead of just plucking a new feature out of thin air, it was chosen based on data that reflected its need. But how do you design that feature? How do you know that the design you choose will have the desired impact? That’s where experiments come into play.  At TweetDeck we make UI changes that we hope will delight our users. But the assumptions we make about our users are often wrong. Our front-end team recently sat in a room and tried to guess which UIs from A/B tests had produced better results. Half the room guessed incorrectly every time. We can’t assume a change we want to make will have the impact we expect. So we run an experiment. Here’s how it works. Users are placed into buckets. One bucket of users will have access to the new feature, the other won’t. We hypothesise that the bucket exposed to the new feature will have better results. The beauty of running an experiment is that we’ll know for sure. Instead of blindly releasing the feature to all users without knowing its impact, once the experiment has run its course, we’ll have the data to make decisions accordingly. Hire the developer, not the degree Lesson #5: Testing candidates on real world problems will allow applicants from all backgrounds to shine. Surely, a company like Twitter would give their applicants insanely difficult code tests, and the toughest technical questions, that only the cleverest CS graduates could pass, I told myself when applying for the job. Lucky for me, this wasn’t the case. The process was insanely difficult—don’t get me wrong—but the team at TweetDeck gave me real world problems to solve. The first code test involved bug fixes, performance and testing. The second involved DOM traversal and manipulation. Instead of being put on the spot in a room with a whiteboard and pen I was given a task, access to the internet, and time to work on it. Similarly, in my technical interviews, I was asked to pair program on real world problems that I was likely to face on the job. In one of my phone screenings I was told Twitter wanted to increase diversity in its teams. Not just gender diversity, but also diversity of experience and background. Six months later, with a bunch of new hires, team lead Tom Ashworth says TweetDeck has the most diverse team it’s ever had. “We designed an interview process that gave us a way to simulate the actual job,” he said. “It’s not about testing whether you learnt an algorithm in school.” Is this lowering the bar? No. The bar is whether a candidate has the ability to solve problems they are likely to face on the job. I recently spoke to a longstanding Atlassian engineer who said they hadn’t seen an algorithm in their seven years at the company. These days, only about 50 per cent of developers have computer science degrees. The majority of developers are self taught, learn on the job or via online courses. If you want to increase diversity in your engineering team, ensure your interview process isn’t excluding these people. 2016 Amy Simmons amysimmons 2016-12-20T00:00:00+00:00 https://24ways.org/2016/my-first-18-months-as-a-dev/ process
16 URL Rewriting for the Fearful I think it was Marilyn Monroe who said, “If you can’t handle me at my worst, please just fix these rewrite rules, I’m getting an internal server error.” Even the blonde bombshell hated configuring URL rewrites on her website, and I think most of us know where she was coming from. The majority of website projects I work on require some amount of URL rewriting, and I find it mildly enjoyable — I quite like a good rewrite rule. I suspect you may not share my glee, so in this article we’re going to go back to basics to try to make the whole rigmarole more understandable. When we think about URL rewriting, usually that means adding some rules to an .htaccess file for an Apache web server. As that’s the most common case, that’s what I’ll be sticking to here. If you work with a different server, there’s often documentation specifically for translating from Apache’s mod_rewrite rules. I even found an automatic converter for nginx. This isn’t going to be a comprehensive guide to every URL rewriting problem you might ever have. That would take us until Christmas. If you consider yourself a trial-and-error dabbler in the HTTP 500-infested waters of URL rewriting, then hopefully this will provide a little bit more of a basis to help you figure out what you’re doing. If you’ve ever found yourself staring at the white screen of death after screwing up your .htaccess file, don’t worry. As Michael Jackson once insipidly whined, you are not alone. The basics Rewrite rules form part of the Apache web server’s configuration for a website, and can be placed in a number of different locations as part of your virtual host configuration. By far the simplest and most portable option is to use an .htaccess file in your website root. Provided your server has mod_rewrite available, all you need to do to kick things off in your .htaccess file is: RewriteEngine on The general formula for a rewrite rule is: RewriteRule URL/to/match URL/to/use/if/it/matches [options] When we talk about URL rewriting, we’re normally talking about one of two things: redirecting the browser to a different URL; or rewriting the URL internally to use a particular file. We’ll look at those in turn. Redirects Redirects match an incoming URL, and then redirect the user’s browser to a different address. These can be useful for maintaining legacy URLs if content changes location as part of a site redesign. Redirecting the old URL to the new location makes sure that any incoming links, such as those from search engines, continue to work. In 1998, Sir Tim Berners-Lee wrote that Cool URIs don’t change, encouraging us all to go the extra mile to make sure links keep working forever. I think that sometimes it’s fine to move things around — especially to correct bad URL design choices of the past — provided that you can do so while keeping those old URLs working. That’s where redirects can help. A redirect might look like this RewriteRule ^article/used/to/be/here.php$ /article/now/lives/here/ [R=301,L] Rewriting By default, web servers closely map page URLs to the files in your site. On receiving a request for http://example.com/about/history.html the server goes to the configured folder for the example.com website, and then goes into the about folder and returns the history.html file. A rewrite rule changes that process by breaking the direct relationship between the URL and the file system. “When there’s a request for /about/history.html” a rewrite rule might say, “use the file /about_section.php instead.” This opens up lots of possibilities for creative ways to map URLs to the files that know how to serve up the page. Most MVC frameworks will have a single rule to rewrite all page URLs to one single file. That file will be a script which kicks off the framework to figure out what to do to serve the page. RewriteRule ^for/this/url/$ /use/this/file.php [L] Matching patterns By now you’ll have noted the weird ^ and $ characters wrapped around the URL we’re trying to match. That’s because what we’re actually using here is a pattern. Technically, it is what’s called a Perl Compatible Regular Expression (PCRE) or simply a regex or regexp. We’ll call it a pattern because we’re not animals. What are these patterns? If I asked you to enter your credit card expiry date as MM/YY then chances are you’d wonder what I wanted your credit card details for, but you’d know that I wanted a two-digit month, a slash, and a two-digit year. That’s not a regular expression, but it’s the same idea: using some placeholder characters to define the pattern of the input you’re trying to match. We’ve already met two regexp characters. ^ Matches the beginning of a string $ Matches the end of a string When a pattern starts with ^ and ends with $ it’s to make sure we match the complete URL start to finish, not just part of it. There are lots of other ways to match, too: [0-9] Matches a number, 0–9. [2-4] would match numbers 2 to 4 inclusive. [a-z] Matches lowercase letters a–z [A-Z] Matches uppercase letters A–Z [a-z0-9] Combining some of these, this matches letters a–z and numbers 0–9 These are what we call character groups. The square brackets basically tell the server to match from the selection of characters within them. You can put any specific characters you’re looking for within the brackets, as well as the ranges shown above. However, all these just match one single character. [0-9] would match 8 but not 84 — to match 84 we’d need to use [0-9] twice. [0-9][0-9] So, if we wanted to match 1984 we could to do this: [0-9][0-9][0-9][0-9] …but that’s getting silly. Instead, we can do this: [0-9]{4} That means any character between 0 and 9, four times. If we wanted to match a number, but didn’t know how long it might be (for example, a database ID in the URL) we could use the + symbol, which means one or more. [0-9]+ This now matches 1, 123 and 1234567. Putting it into practice Let’s say we need to write a rule to match article URLs for this website, and to rewrite them to use /article.php under the hood. The articles all have URLs like this: 2013/article-title/ They start with a year (from 2005 up to 2013, currently), a slash, and then have a URL-safe version of the article title (a slug), ending in a slash. We’d match it like this: ^[0-9]{4}/[a-z0-9-]+/$ If that looks frightening, don’t worry. Breaking it down, from the start of the URL (^) we’re looking for four numbers ([0-9]{4}). Then a slash — that’s just literal — and then anything lowercase a–z or 0–9 or a dash ([a-z0-9-]) one or more times (+), ending in a slash (/$). Putting that into a rewrite rule, we end up with this: RewriteRule ^[0-9]{4}/[a-z0-9-]+/$ /article.php We’re getting close now. We can match the article URLs and rewrite them to use article.php. Now we just need to make sure that article.php knows which article it’s supposed to display. Capturing groups, and replacements When rewriting URLs you’ll often want to take important parts of the URL you’re matching and pass them along to the script that handles the request. That’s usually done by adding those parts of the URL on as query string arguments. For our example, we want to make sure that article.php knows the year and the article title we’re looking for. That means we need to call it like this: /article.php?year=2013&slug=article-title To do this, we need to mark which parts of the pattern we want to reuse in the destination. We do this with round brackets or parentheses. By placing parentheses around parts of the pattern we want to reuse, we create what’s called a capturing group. To capture an important part of the source URL to use in the destination, surround it in parentheses. Our pattern now looks like this, with parentheses around the parts that match the year and slug, but ignoring the slashes: ^([0-9]{4})/([a-z0-9-]+)/$ To use the capturing groups in the destination URL, we use the dollar sign and the number of the group we want to use. So, the first capturing group is $1, the second is $2 and so on. (The $ is unrelated to the end-of-pattern $ we used before.) RewriteRule ^([0-9]{4})/([a-z0-9-]+)/$ /article.php?year=$1&slug=$2 The value of the year capturing group gets used as $1 and the article title slug is $2. Had there been a third group, that would be $3 and so on. In regexp parlance, these are called back-references as they refer back to the pattern. Options Several brain-taxing minutes ago, I mentioned some options as the final part of a rewrite rule. There are lots of options (or flags) you can set to change how the rule is processed. The most useful (to my mind) are: R=301 Perform an HTTP 301 redirect to send the user’s browser to the new URL. A status of 301 means a resource has moved permanently and so it’s a good way of both redirecting the user to the new URL, and letting search engines know to update their indexes. L Last. If this rule matches, don’t bother processing the following rules. Options are set in square brackets at the end of the rule. You can set multiple options by separating them with commas: RewriteRule ^([0-9]{4})/([a-z0-9-]+)/$ /article.php?year=$1&slug=$2 [L] or RewriteRule ^about/([a-z0-9-]+).jsp/$ /about/$1/ [R=301,L] Common pitfalls Once you’ve built up a few rewrite rules, things can start to go wrong. You may have been there: a rule which looks perfectly good is somehow not matching. One common reason for this is hidden behind that [L] flag. L for Last is a useful option to tell the rewrite engine to stop once the rule has been matched. This is what it does — the remaining rules in the .htaccess file are then ignored. However, once a URL has been rewritten, the entire set of rules are then run again on the new URL. If the new URL matches any of the rules, that too will be rewritten and on it goes. One way to avoid this problem is to keep your ‘real’ pages under a folder path that will never match one of your rules, or that you can exclude from the rewrite rules. Useful snippets I find myself reusing the same few rules over and over again, just with minor changes. Here are some useful examples to refer back to. Excluding a directory As mentioned above, if you’re rewriting lots of fancy URLs to a collection of real files it can be helpful to put those files in a folder and exclude it from rewrite rules. This helps solve the issue of rewrite rules reapplying to your newly rewritten URL. To exclude a directory, put a rule like this at the top of your file, before your other rules. Our files are in a folder called _source, the dash in the rule means do nothing, and the L flag means the following rules won’t be applied. RewriteRule ^_source - [L] This is also useful for excluding things like CMS folders from your website’s rewrite rules RewriteRule ^perch - [L] Adding or removing www from the domain Some folk like to use a www and others don’t. Usually, it’s best to pick one and go with it, and redirect the one you don’t want. On this site, we don’t use www.24ways.org so we redirect those requests to 24ways.org. This uses a RewriteCond which is like an if for a rewrite rule: “If this condition matches, then apply the following rule.” In this case, it’s if the HTTP HOST (or domain name, basically) matches this pattern, then redirect everything: RewriteCond %{HTTP_HOST} ^www.24ways.org$ [NC] RewriteRule ^(.*)$ http://24ways.org/$1 [R=301,L] The [NC] flag means ‘no case’ — the match is case-insensitive. The dots in the domain are escaped with a backslash, as a dot is a regular expression character which means match anything, so we escape it because we literally mean a dot in this instance. Removing file extensions Sometimes all you need to do to tidy up a URL is strip off the technology-specific file extension, so that /about/history.php becomes /about/history. This is easily achieved with the help of some more rewrite conditions. RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteCond %{REQUEST_FILENAME}.php -f RewriteRule ^(.+)$ $1.php [L,QSA] This says if the file being asked for isn’t a file (!-f) and if it isn’t a directory (!-d) and if the file name plus .php is an actual file (-f) then rewrite by adding .php on the end. The QSA flag means ‘query string append’: append the existing query string onto the rewritten URL. It’s these sorts of more generic catch-all rules that you need to watch out for when your .htaccess gets rerun after a successful match. Without care they can easily rematch the newly rewritten URL. Logging for when it all goes wrong Although not possible within your .htaccess file, if you have access to your Apache configuration files you can enable rewrite logging. This can be useful to track down where a rule is going wrong, if it’s matching incorrectly or failing to match. It also gives you an overview of the amount of work being done by the rewrite engine, enabling you to rearrange your rules and maximise performance. RewriteEngine On RewriteLog "/full/system/path/to/rewrite.log" RewriteLogLevel 5 To be doubly clear: this will not work from an .htaccess file — it needs to be added to the main Apache configuration files. (I sometimes work using MAMP PRO locally on my Mac, and this can be pasted into the snappily named Customized virtual host general settings box in the Advanced tab for your site.) The white screen of death One of the most frustrating things when working with rewrite rules is that when you make a mistake it can result in the server returning an HTTP 500 Internal Server Error. This in itself isn’t an error message, of course. It’s more of a notification that an error has occurred. The real error message can usually be found in your Apache error log. If you have access to your server logs, check the Apache error log and you’ll usually find a much more descriptive error message, pointing you towards your mistake. (Again, if using MAMP PRO, go to Server, Apache and the View Log button.) In conclusion Rewriting URLs can be a bear, but the advantages are clear. Keeping a tidy URL structure, disconnected from the technology or file structure of your site can result in URLs that are easier to use and easier to maintain into the future. If you’re redesigning a site, remember that cool URIs don’t change, so budget some time to make sure that any content you move has a rewrite rule associated with it to keep any links working. Further reading To find out more about URL rewriting and perhaps even learn more about regular expressions, I can recommend the following resources. From the horse’s mouth, the Apache mod_rewrite documentation Particularly useful with that documentation is the RewriteRule Flags listing You may wish to don sunglasses to follow the otherwise comprehensive Regular-Expressions.info tutorial Friend of 24 ways, Neil Crosby has a mod_rewrite Beginner’s Guide which I’ve found handy over the years. As noted at the start, this isn’t a fully comprehensive guide, but I hope it’s useful in finding your feet with a powerful but sometimes annoying technology. Do you have useful snippets you often use on projects? Feel free to share them in the comments. 2013 Drew McLellan drewmclellan 2013-12-01T00:00:00+00:00 https://24ways.org/2013/url-rewriting-for-the-fearful/ code
255 Inclusive Considerations When Restyling Form Controls I would like to begin by saying 2018 was the year that we, as developers, visual designers, browser implementers, and inclusive design and experience specialists rallied together and achieved a long-sought goal: We now have the ability to fully style form controls, across all modern browsers, while retaining their ease of declaration, native functionality and accessibility. I would like to begin by saying all these things. However, they’re not true. I think we spent the year debating about what file extension CSS should be written in, or something. Or was that last year? Maybe I’m thinking of next year. Returning to reality, styling form controls is more tricky and time consuming these days rather than flat out “hard”. In fact, depending on the length of the styling-leash a particular browser provides, there are controls you can style quite a bit. As for browsers with shorter leashes, there are other options to force their controls closer to the visual design you’re tasked to match. However, when striving for custom styled controls, one must be careful not to forget about the inherent functionality and accessibility that many provide. People expect and deserve the products and services they use and pay for to work for them. If these services are visually pleasing, but only function for those who fit the handful of personas they’ve been designed for, then we’ve potentially deprived many people the experiences they deserve. Quick level setting Getting down to brass tacks, when creating custom styled form controls that should retain their expected semantics and functionality, we have to consider the following: Many form elements can be styled directly through standard and browser specific selectors, as well as through some clever styling of markup patterns. We should leverage these native options before reinventing any wheels. It is important to preserve the underlying semantics of interactive controls. We must not unintentionally exclude people who use assistive technologies (ATs) that rely on these semantics. Make sure you test what you create. There is a lot of underlying complexity to form controls which may not be immediately apparent if they’re judged solely by their visual presentation in a single browser, or with limited AT testing. Visually resetting and restyling form controls Over the course of 2018, I worked on a project where I tested and reported on the accessibility impact of styling various form controls. In conducting my research, I reviewed many of the form controls available in HTML, testing to see how malleable they were to direct styling from standardized CSS selectors. As I expected, controls such as the various text fields could be restyled rather easily. However, other controls like radio buttons and checkboxes, or sub-elements of special text fields like date, search, and number spinners were resistant to standard-based styling. These particular controls and their sub-elements required specific pseudo-elements to reset and allow for restyling of some of their default presentation. See the Pen form control styling comparisons by Scott (@scottohara) on CodePen. https://codepen.io/scottohara/pen/gZOrZm/ Over the years, the ability to directly style form controls has been something many people have clamored for. However, one should realize the benefits of being able to restyle some of these controls may involve more effort than originally anticipated. If you want to restyle a control from the ground up, then you must also recreate any :active, :focus, and :hover states for the control—all those things that were previously taken care of by browsers. Not only that, but anything you restyle should also work with Windows High Contrast mode, styling for dark mode, and other OS-level settings that browser respect without you even realizing. You ever try playing with the accessibility settings of your display on macOS, or similar Windows setting? It is also worth mentioning that any browser prefixed pseudo-elements are not standardized CSS selectors. As MDN mentions at the top of their pages documenting these pseudo-elements: Non-standard This feature is non-standard and is not on a standards track. Do not use it on production sites facing the Web: it will not work for every user. There may also be large incompatibilities between implementations and the behavior may change in the future. While this may be a deterrent for some, it’s my opinion the risks are often only skin-deep. By which I mean if a non-standard selector does change, the control may look a bit quirky, but likely won’t cease to function. A bug report which requires a CSS selector change can be an easy JIRA ticket to close, after all. Can’t make it? Fake it. Internet Explorer 11 (IE11) is still neck-and-neck with other browsers in vying for the number 2 spot in desktop browser share. Due to IE not recognizing vendor-prefixed appearance properties, some essential controls like checkboxes won’t render as intended. Additionally, some controls like select boxes, file uploads, and sub-elements of date fields (calendar popups) cannot be modified by just relying on styling their HTML selectors alone. This means that unless your company designs and develops with a progressive enhancement, or graceful degradation mindset, you’ll need to take a different approach in styling. Getting clever with markup and CSS The following CodePen demonstrates how we can create a custom checkbox markup pattern. By mindfully utilizing CSS sibling selectors and positioning of the native control, we can create custom visual styling while also retaining the functionality and accessibility expectations of a native checkbox. See the Pen Accessible Styled Native Checkbox by Scott (@scottohara) on CodePen. https://codepen.io/scottohara/pen/RqEayN/ Customizing checkboxes by visually hiding the input and styling well-placed markup with sibling selectors may seem old hat to some. However, many variations of these patterns do not take into account how their method of visually hiding the checkboxes can create discovery issues for certain screen reader navigation methods. For instance, if someone is using a mobile device and exploring by touch, how will they be able to drag their finger over an input that has been reduced to a single pixel, or positioned off screen? As we move away from the simplicity of declaring a single HTML element and using clever CSS and markup patterns to create restyled form controls, we increase the need for additional testing to ensure no expected behaviors are lost. In other words, what should work in theory may not work in practice when you introduce the various different ways people may engage with a form control. It’s worth remembering: what might be typical interactions for ourselves may be problematic if not impossible for others. Limitations to cleverness Creative coding will allow us to apply more consistent custom styles to some of the more problematic form controls. There will be a varied amount of custom markup, CSS, and sometimes JavaScript that will be needed to preserve the control’s inherent usability and accessibility for each control we take this approach to. However, this method of restyling still doesn’t solve for the lack of feature parity across different browsers. Nor is it a means to account for controls which don’t have a native HTML element equivalent, such as a switch or multi-thumb range slider? Maybe there’s a control that calls for a visual design or proposed user experience that would require too much fighting with a native control’s behavior to be worth the level of effort to implement. Here’s where we need to take another approach. Using ARIA when appropriate Sometimes we have no other option than to roll up our sleeves and start building custom form controls from scratch. Fair warning though: just because we’re not leveraging a native HTML control as our foundation, it doesn’t mean we have carte blanche to throw semantics out the window. Enter Accessible Rich Internet Applications (ARIA). ARIA is a set of attributes that can modify existing elements, or extend HTML to include roles, properties and states that aren’t native to the language. While divs and spans have no meaningful semantic information for us to leverage, with help from the ARIA specification and ARIA Authoring Practices we can incorporate these elements to help create the UI that we need while still following the first rule of Using ARIA: If you can use a native HTML element or attribute with the semantics and behavior you require already built in, instead of re-purposing an element and adding an ARIA role, state or property to make it accessible, then do so. By using these documents as guidelines, and testing our custom controls with people of various abilities, we can do our best to make sure a custom control performs as expected for as many people as possible. Exceptions to the rule One example of a control that allows for an exception to the first rule of Using ARIA would be a switch control. Switches and checkboxes are similar components, in that they have both on/checked and off/unchecked states. However, checkboxes are often expected within the context of forms, or used to filter search queries on e-commerce sites. Switches are typically used to instantly enable or deactivate a particular setting at a component or app-based level, as this is their behavior in the native mobile apps in which they were popularized. While a switch control could be created by visually restyling a checkbox, this does not automatically mean that the underlying semantics and functionality will match the visual representation of the control. For example, the following CodePen restyles checkboxes to look like a switch control, but the semantics of the checkboxes remain which communicate a different way of interacting with the control than what you might expect from a native switch control. See the Pen Switch Boxes - custom styled checkboxes posing as switches by Scott (@scottohara) on CodePen. https://codepen.io/scottohara/pen/XyvoeE/ By adding a role="switch" to these checkboxes, we can repurpose the inherent checked/unchecked states of the native control, it’s inherent ability to be focused by Tab key, and Space key to toggle state. But while this is a valid approach to take in building a switch, how does this actually match up to reality? Does it pass the test(s)? Whether deconstructing form controls to fully restyle them, or leveraging them and other HTML elements as a base to expand on, or create, a non-native form control, building it is just the start. We must test that what we’ve restyled or rebuilt works the way people expect it to, if not better. What we must do here is run a gamut of comparative tests to document the functionality and usability of native form controls. For example: Is the control implemented in all supported browsers? If not: where are the gaps? Will it be necessary to implement a custom solution for the situations that degrade to a standard text field? If so: is each browser’s implementation a good user experience? Is there room for improvement that can be tested against the native baseline? Test with multiple input devices. Where the control is implemented, what is the quality of the user experience when using different input devices, such as mouse, touchscreen, keyboard, speech recognition or switch device, to name a few. You’ll find some HTML5 controls (like date pickers and number spinners) have additional UI elements that may not be announced to AT, or even allow keyboard accessibility. Often these controls can be adjusted by other means, such as text entry, or using arrow keys to increase or decrease values. If restyling or recreating a custom version of a control like these, it may make sense to maintain these native experiences as well. How well does the control take to custom styles? If a control can be styled enough to not need to be rebuilt from scratch, that’s great! But make sure that there are no adverse affects on the accessibility of it. For instance, range sliders can be restyled and maintain their functionality and accessibility. However, elements like progress bars can be negatively affected by direct styling. Always test with different browser and AT pairings to ensure nothing is lost when controls are restyled. Do specifications match reality? If recreating controls to get around native limitations, such as the inability to style the options of a select element, or requiring a Switch control which is not native to HTML, do your solutions match user expectations? For instance, selects have unique picker interfaces on touch devices. And switches have varied levels of support for different browser and screen reader pairings. Test with real people, and check your analytics. If these experiences don’t match people’s expectations, then maybe another solution is in order? Wrapping up While styling form controls is definitely easier than it’s ever been, that doesn’t mean that it’s at all simple, nor will it likely ever be. The level of difficulty you’re going to face is going to depend entirely on what it is you’re hoping to style, add-on to, or recreate. And even if you build your custom control exactly to specification, you’ll still be reliant on browsers and assistive technologies being able to fully understand the component they’ve been presented. Forms and their controls are an incredibly important part of what we need the Internet for. Paying bills, scheduling appointments, ordering groceries, renewing your license or even ordering gifts for the holidays. These are all important tasks that people should be able to complete with as little effort as possible. Especially since for some, completing these tasks online might be their only option. 2018 didn’t end up being the year we got full customization of form controls sorted out. But that’s OK. If we can continue to mindfully work with what we have, and instead challenge ourselves to follow inclusive design principles, well thought out Form Design Patterns, and solve problems with an accessibility first approach, we may come to realize that we can get along just fine without fully branded drop downs. And hey. There’s always next year, right? 2018 Scott O'Hara scottohara 2018-12-13T00:00:00+00:00 https://24ways.org/2018/inclusive-considerations-when-restyling-form-controls/ code