81 |
Science! |
Sometimes we want to capture people’s attention at a glance to communicate something fast. At other times we want to have the interface fade away into the background, letting people paint pictures in their minds with our words (if you’ll forgive a little flowery festive flourish).
I tend to distinguish between these two broad objectives as designing for impact on the one hand, and designing for immersion on the other. What defines them is interruption. Impact needs an attention-grabbing interruption. Immersion requires us to remove interruption from the interface. Careful design deliberately interrupts but doesn’t accidentally disrupt. If that seems to make sense to you, then you’ll find the following snippets of science as useful as I did.
Saccades and fixations
As you’re reading this your eyes are skipping along the lines in tiny jumps. During each jump everything is blurred. Each jump ends in a small pause so your brain can take a snapshot of the letters. It arranges them into words, and then parses out the meaning — fast — in around a quarter of a second.
The jumps are called saccades. The pauses are called fixations. Sometimes we take regressive saccades, skipping back to reread. There’s a simple example in the excellent little book, Detail in Typography, by Jost Hochuli.
If you want to explore the science of reading in much more depth, I recommend the excellent paper, “The Science of Word Recognition”, by Dr Kevin Larson of Microsoft.
To design for legibility and readability is to design for saccades and fixations. It’s the craft of making it easy for people’s brains to extract meaning, using techniques like good contrast, font size, spacing and structure, and only interrupting the reading experience deliberately.
Scan paths
At some point when visiting 24 ways you probably scanned the screen to get orientated. The journey your eyes took is known as a scan path. Scan paths are made up of saccades and fixations. Right now you’re following a scan path as you read, along one line, and down to the next. This is a map of the scan paths found by Olivier Le Meur from observing people looking at Rembrandt’s Leçon d’anatomie:
For websites, the scan path is a little different. This is an aggregate scan path of Google from LC Technologies:
The average shape of a website scan path becomes clearer in this average scan path taken by forty-six people during research by the Poynter Institute, the Estlow Center for Journalism & New Media, and Eyetools:
Just like when we read text arranged left to right in a vertical column, scan paths follow a roughly Z-shaped pattern from the top left to bottom right. Sometimes we skip back to reread a word or sentence, or glance again at a specific element, but the Z-shaped scan path persists.
Designing for scan paths is to organise content to help people move through an interface to get orientated, and to read.
The elements that are important enough to need impact must interrupt the scan path and clearly call attention to themselves. However, they don’t always need to clip people round the ear from multiple directions at once to get attention. It helps to list elements by importance. That gives us an interruption hierarchy to work with. Elements can then interrupt the design with degrees of contrast to the rest of the content using either positioning, treatment, or both. Ta-da! Impact achieved, but gently. No clips round the ear required.
Swinging mood
Human beings are resilient. Among the immersion and occasional interruptions, we even like a little disruption, especially if it’s absurd and funny. The Ling’s Cars website proves it. In fact, we’re so resilient that we can work around all kinds of mayhem to get a seemingly simple task done.
In one study, “The Aesthetics of Reading” (PDF, 480Kb), Dr Kevin Larson of Microsoft and Dr Rosalind Picard of MIT explored the effect of good typography on mood. Two versions of the New Yorker ePeriodical were created. One was typeset well and the other poorly.
They engaged twenty volunteers — half male, half female — and showed the good version to half of the participants. The other half saw the poor version.
The good doctors found that, “there are important differences between good and poor typography that appear to have little effect on common performance measures such as reading speed and comprehension.” In short, good typography didn’t help people read faster or comprehend better.
Oh. On the face of it that seems to invalidate what we designers do. Hold your horses, though! They also found that “the participants who received the good typography performed better on relative subjective duration and on certain cognitive tasks”, and that “good typography induces a good mood.”
This means that even though there were no actual differences in reading speed and comprehension, the people who read the version with good typography thought that it took less time to read, and were induced into a good mood by doing so. Not only that, but by being in a good mood, people were more capable of completing creative tasks faster.
That was a revelation to me. It means that the study showed there is a positive, measurable, emotional and perceptual benefit to good typography and design. To paraphrase: time and tasks fly when you’re having fun!
Source: Nationaal Archief of the Netherlands: Cheering man after the first goal, Netherlands vs. Belgium, Amsterdam, 1931.
So, among all my talk of saccades, fixations, scan paths and typesetting, there is science, and the science helps us qualify our design decisions when we need to, and do our jobs better. The science helps us understand how people will interact with our work, and what the actual benefits are for them, and the products or organisations we serve. Good design equals a subjectively quicker experience, a good mood, objectively faster completion of tasks, and happiness for everyone. Thank you, science! |
2012 |
Jon Tan |
jontan |
2012-12-24T00:00:00+00:00 |
https://24ways.org/2012/science/ |
design |
84 |
Responsive Responsive Design |
Now more than ever, we’re designing work meant to be viewed along a gradient of different experiences. Responsive web design offers us a way forward, finally allowing us to “design for the ebb and flow of things.”
With those two sentences, Ethan closed the article that introduced the web to responsive design. Since then, responsive design has taken the web by storm. Seemingly every day, some company is touting their new responsive redesign. Large brands such as Microsoft, Time and Disney are getting in on the action, blowing away the once common criticism that responsive design was a technique only fit for small blogs.
Certainly, this is a good thing. As Ethan and John Allsopp before him, were right to point out, the inherent flexibility of the web is a feature, not a bug. The web’s unique ability to be consumed and interacted with on any number of devices, with any number of input methods is something to be embraced.
But there’s one part of the web’s inherent flexibility that seems to be increasingly overlooked: the ability for the web to be interacted with on any number of networks, with a gradient of bandwidth constraints and latency costs, on devices with varying degrees of hardware power.
A few months back, Stephanie Rieger tweeted
“Shoot me now…responsive design has seemingly become confused with an opportunity to reduce performance rather than improve it.”
I would love to disagree, but unfortunately the evidence is damning. Consider the size and number of requests for four highly touted responsive sites that were launched this year:
74 requests, 1,511kb
114 requests, 1,200kb
99 requests, 1,298kb
105 requests, 5,942kb
And those numbers were for the small screen versions of each site!
These sites were praised for their visual design and responsive nature, and rightfully so. They’re very easy on the eyes and a lot of thought went into their appearance. But the numbers above tell an inconvenient truth: for all the time spent ensuring the visual design was airtight, seemingly very little (if any) attention was given to their performance.
It would be one thing if these were the exceptions, but unfortunately they’re not. Guy Podjarny, who has done a lot of research around responsive performance, discovered that 86% of the responsive sites he tested were either the same size or larger on the small screen as they were on the desktop.
The reality is that high performance should be a requirement on any web project, not an afterthought. Poor performance has been tied to a decrease in revenue, traffic, conversions, and overall user satisfaction. Case study after case study shows that improving performance, even marginally, will impact the bottom line. The situation is no different on mobile where 71% of people say they expect sites to load as quickly or faster on their phone when compared to the desktop.
The bottom line: performance is a fundamental component of the user experience.
So, given it’s extreme importance in the success of any web project, why is it that we’re seeing so many bloated responsive sites?
First, I adamantly disagree with the belief that poor performance is inherent to responsive design. That’s not a rule – it’s a cop-out. It’s an example of blaming the technique when we should be blaming the implementation. This argument also falls flat because it ignores the fact that the trend of fat sites is increasing on the web in general. While some responsive sites are the worst offenders, it’s hardly an issue resigned to one technique.
To fix the issue, we need to stop making excuses and start making improvements instead. Here, then, are some things we can do to start improving the state of responsive performance, and performance in general, right now.
Create a culture of performance
If you understand just how important performance is to the success of a project, the natural next step is to start creating a culture where high performance is a key consideration.
One of the things you can do is set a baseline. Determine the maximum size and number of requests you are going to allow, and don’t let a page go live if either of those numbers is exceeded. The BBC does this with its responsive mobile site.
A variation of that, which Steve Souders discussed in a recent podcast is to create a performance budget based on those numbers. Once you have that baseline set, if someone comes along and wants to add a something to the page, they have to make sure the page remains under budget. If it exceeds the budget, you have three options:
Optimize an existing feature or asset on the page
Remove an existing feature or asset from the page
Don’t add the new feature or asset
The idea here is that you make performance part of the process instead of something that may or may not get tacked on at the end.
Embrace the pain
This troubling trend of web bloat can be blamed in part on the lack of pain associated with poor performance. Most of us work on high-speed connections with low latency. When we fire up a 4Mb site, it doesn’t feel so bad.
When I tested the previously mentioned 5,942kb site on a 3G network, it took over 93 seconds to load. A minute and a half just staring at a white screen. Had anyone working on that project experienced that, you can bet the site wouldn’t have launched in that state.
Don’t just crunch numbers. Fire up your site on a slower network and see what it feels like to wait. If you don’t have access to a slow network, simulate one using a tool like Slowy, Throttle or the Network Conditioner found in Mac OS X 10.7.
Watch for low-hanging fruit
There are a bunch of general performance improvements that apply to any site (responsive or not) but often aren’t made. A great starting point is to refer to Yahoo!‘s list of rules.
Some of this might sound complicated or intimidating, but it doesn’t have to be. You can grab an .htaccess file from HTML 5 Boilerplate or use Sergey Chernyshev’s drop-in .htaccess file. You can use tools like SpriteMe to simplify the creation of sprites, and ImageOptim to compress images.
Just by implementing these simple optimizations you will achieve a noticeable improvement in terms of weight and page load time.
Be careful with images
The most common offender for poor responsive performance is downloading unnecessarily large images, or worse yet, multiple sizes of the same image.
For background images, simply being careful with where and how you include the image can ensure you don’t get caught in the trap of multiple background images being downloaded without being used. Don’t count on display:none to help. While it may hide elements from displaying on screen, those images will still be requested and downloaded.
Content images can be a little trickier. Whatever you do, don’t serve a large image that works on a large screen display to small screens. It’s wasteful, not only in terms of adding weight to the page, but also in wasting precious memory. Instead, use a tool like Adaptive Images or src.sencha.io to make sure only appropriately sized images are being downloaded.
The new <picture> element that has been so often discussed is another excellent solution if you’re feeling particularly future-oriented. A picture polyfill exists so that you can start using the element now without any worries about support.
Conditional loading
Don’t load any more than you absolutely need to. If a script isn’t needed at certain sizes, use the matchMedia polyfill to ensure it only loads when needed. Use eCSSential to do the same for unnecessary CSS files.
Last year on 24 ways, Jeremy Keith wrote an article about conditional loading of content in a responsive design based on the screen width. The technique was later refined by the Filament Group into what they dubbed the Ajax-Include Pattern. It’s a powerful and simple way to lighten the load on small screens as well as reduce clutter.
Go vanilla?
If you take a look at the HTTP Archive you’ll see that other than image size, JavaScript is the heaviest asset on a page weighing in at 215kb on average. It also boasts the fifth highest correlation to load time as well as the second highest correlation to render time.
Much of the weight can be attributed to our industry’s increasing reliance on frameworks. This is especially a concern on mobile devices. PPK recently exclaimed that current JavaScript libraries are just “too heavy for mobile”. “Research from Stoyan Stefanov on parse times supports this. On some Android and iOS devices, it can take as long as 200-300ms just to parse jQuery.
There’s nothing wrong about using a framework, but the problem is that they’ve become the default. Before dropping another framework or plugin into a page, we should stop to consider the value it adds and whether we could accomplish what we need to do using a combination of vanilla JavaScript and CSS instead. (This is a great example of a scenario where a performance budget could help.)
Start thinking beyond visual aesthetics
We love to tout the web’s universality when discussing the need for responsive design. But that universality is not limited simply to screen size. Networks and hardware capabilities must factor in as well.
The web is an incredibly dynamic and interactive medium, and designing for it demands that we consider more than just visual aesthetics. Let’s not forget to give those other qualities the attention they deserve. |
2012 |
Tim Kadlec |
timkadlec |
2012-12-05T00:00:00+00:00 |
https://24ways.org/2012/responsive-responsive-design/ |
design |
93 |
Design Systems |
The most important part of responsive web design is that, no matter what the viewport width, the content is accessible in an optimum display. The best responsive designs are those that allow you to go from one optimised display to another, but with the feeling that these experiences are part of a greater product whole.
Responsive design: where we’ve been going wrong
Responsive web design was a shock to my web designer system. Those of us who had already been designing sites for mobile probably had the biggest leap to make. We might have been detecting user agents in order to deliver a mobile-specific site, or using the slightly more familiar Bushido technique to deliver sites optimised for device type and viewport size, but either way our focus was on devices. A site was optimised for either a mobile phone or a desktop.
Responsive web design brought us back to pre-table layout fluid sites that expanded or contracted to fit the viewport. This was a big difference to get our heads around when we were so used to designing for fixed-width layouts. Suddenly, an element could be any width or, at least, we needed to consider its maximum and minimum widths. Pixel perfection, while pretty, became wholly unrealistic, and a whole load of designers who prided themselves in detailed and precise designs got a bit scared.
Hanging on to our previous processes and typical deliverables led us to continue to optimise our sites for particular devices and provide pixel-perfect mockups for those device widths.
With all this we were concentrating on devices, not content, deliverables and not process, and making assumptions about users and their devices based on nothing but the width of the viewport.
I don’t think this is a crime, I think it was inevitable.
We can be up to date with our principles and ideals, but it’s never as easy in practice. That’s why it’s more important than ever to share our successful techniques and processes. Let’s drag each other into modern web design.
Design systems: the principles
What are design systems?
A visual design system is built out of the core components of typography, layout, shape or form, and colour. When considering the design of a whole product, a design system should also include patterns in user flow, content strategy, copy, and tone of voice. These concepts, design decisions or rules, created around the core components are used consistently across your product to create a cohesive feel, whether it’s from one element to another, page to page, or viewport width to viewport width.
Responsive design is one of the most important considerations in the components of a design system. For each component, you must decide what will unite the design across the viewports to maintain that consistent feel, and what parts of the design will differentiate in order to provide a flexible and optimal experience for different viewport sizes.
Components you might keep the same across viewports
typeface
base unit
colour
shape/form
Components you might differentiate across viewports
grids
layout
font size
measure (line length)
leading (line height)
Content: it must always be the same
The focus of a design system is the optimum display of content. As Mark Boulton put it, designing “content out, not canvas in.” Chris Armstrong puts the emphasis on not designing for viewports but for content – “we need to build on what we do know: content.” In order to do this, we must share the same content across all devices and focus on how best to display and represent content through design system components.
The practical: core visual components
Typography first
When you work with a lot of text content, typography is the easiest way to set the visual tone of the design across all viewport widths. It’s likely that you’ll choose one or two typefaces to use across the whole system, but you might change the most legible font size, balanced with the most comfortable measure, as the viewport width changes.
Where typography meets layout
The unit on which you choose to base the grid and layout design, font sizes and leading could be based on the typeface, an optimal reading size, or something more arbitrary. Sometimes I’ll choose a unit based on multiples of ten because it makes the maths in the CSS easier. Tim Brown suggests trying a modular scale. Chris Armstrong suggests basing it on your ideal measure, or the width of a fixed item of content such as an ad unit.
Grids and layouts
Sensible grid design can be a flexible yet solid foundation for your design system layout component. But you must be wary in responsive design that a grid might not work across all widths: even four columns could make for very cramped content and one-word measures on smaller screens.
Maybe the grid columns are something you differentiate across widths, but you can keep the concept of the grid consistent. If the content has blocks in groups of three, you might decide on a three-column grid which folds down to one column for narrow viewports. If the grid focuses on the idea of symmetry and has a four-column grid on larger viewports, it might fold down to two columns for narrower viewports. These consistencies may seem subtle, not at all obvious to many except the designer, but it’s all these little constants and patterns across the whole of the design system that makes design decisions easier to make (as they adhere to the guiding concepts of your system), and give the product a uniform feel no matter what the device.
Shape or form
The shape or form components are concepts you already use in fixed-width web design for a strong, consistent look and feel.
Since CSS border-radius became widely supported by browsers, a lot of designs feature circle themes. These are very distinctive and can be used across viewport widths giving them the same united feel, even if they’re not used in the same way. This could also apply to border styles, consistent shadows and any number of decorative details and textures. These are the elements that make up the shape or form of a design system.
Colour
Colour is the most basic way to reinforce a brand and unite experiences across viewports. The same hex colour used system-wide is instantly recognisable, no matter what the viewport width.
The process
While using a design system isn’t necessarily attached to any particular process, it does lend itself to some process ideals.
Detaching design considerations from viewport widths
A design system allows you to focus separately on the components that make up the system, disconnecting the look and feel from the layout. This helps prevent us getting stuck in the rut of the Apple breakpoints (brilliantly coined by Simon Foster) of mobile, tablet and desktop. It also forces us to design for variation in viewport experiences side by side, not one after the other.
Design in the browser
I can’t start off designing in the browser – it just doesn’t seem to bring out my creative side (and I’m incredibly envious of you if you can; I just have to start on paper) – but static mock-ups aren’t the only alternative. Style guides and style tiles are perfect for expressing the concepts of your design system. Pattern libraries could also work well.
Mock-ups and breakpoints
At some point, whether it’s to test your system ideas, or because a client needs help visualising how your system might work, you may end up producing some static mock-ups. It’s not the end of the world, but you must ensure that these consider all the viewports, not just those of the iDevices, or even the devices currently on the market. You need to decide the breakpoints where the states of your design change. The blocks within your content will always have optimum points for their display (based on their hierarchy, density, width, or type of interaction) and so your breakpoints should be based around these points.
These are probably the ideal points at which to produce static mockups; treat them as snapshots. They’re not necessarily mock-ups, so much as a way of capturing how your design system would be interpreted when frozen at that particular viewport width.
The future
Creating design systems will give us the flexibility we need for working with the unknown devices of the future. It may be a change in process, but it shouldn’t be too much of a difference in thinking. The pioneers in responsive design have a hard job. Some of these problems may have already been solved in other technologies or industries, but it’s up to the pioneers to find those connections and help us formulate solutions and standards that will make responsive design the best it can possibly be. We need to keep experimenting and communicating, particularly in the area of design, as good user experiences are the true sign of whether our products are a success. |
2012 |
Laura Kalbag |
laurakalbag |
2012-12-12T00:00:00+00:00 |
https://24ways.org/2012/design-systems/ |
design |
102 |
Art Directing with Looking Room |
Using photographic composition techniques to start to art direct on the template-driven web.
Think back to last night. There you are, settled down in front of the TV, watching your favourite soap opera, with nice hot cup of tea in hand. Did you notice – whilst engrossed in the latest love-triangle – that the cameraman has worked very hard to support your eye’s natural movement on-screen? He’s carefully framed individual shots to create balance.
Think back to last week. There you were, sat with your mates watching the big match. Did you notice that the cameraman frames the shot to go with the direction of play? A player moving right will always be framed so that he is on the far left, with plenty of ‘room’ to run into.
Both of these cameramen use a technique called Looking Room, sometimes called Lead Room. Looking Room is the space between the subject (be it a football, or a face), and the edge of the screen. Specifically, Looking Room is the negative space on the side the subject is looking or moving. The great thing is, it’s not just limited to photography, film or television; we can use it in web design too.
Basic Framing
Before we get into Looking Room, and how it applies to web, we need to have a look at some basics of photographic composition.
Many web sites use imagery, or photographs, to enhance the content. But even with professionally shot photographs, without a basic understanding of framing or composition, you can damage how the image is perceived.
A simple, easy way to make photographs more interesting is to fill the frame.
Take this rather mundane photograph of a horse:
A typical point and click affair. But, we can work with this.
By closely cropping, and filling the frame, we can instantly change the mood of the shot.
I’ve also added Looking Room on the right of the horse. This is space that the horse would be walking into. It gives the photograph movement.
Subject, Space, and Movement
Generally speaking, a portrait photograph will have a subject and space around them. Visual interest in portrait photography can come from movement; how the eye moves around the shot. To get the eye moving, the photographer modifies the space around the subject.
Look at this portrait:
The photography has framed the subject on the right, allowing for whitespace, or Looking Room, in the direction the subject is looking. The framing of the subject (1), with the space to the left (2) – the Looking Room – creates movement, shown by the arrow (3).
Note the subject is not framed centrally (shown by the lighter dotted line).
If the photographer had framed the subject with equal space either side, the resulting composition is static, like our horse.
If the photographer framed the subject way over on the left, as she is looking that way, the resulting whitespace on the right leads a very uncomfortable composition.
The root of this discomfort is what the framing is telling our eye to do. The subject, looking to the left, suggests to us that we should do the same. However, the Looking Room on the right is telling our eye to occupy this space. The result is a confusing back and forth.
How Looking Room applies to the web
We can apply the same theory to laying out a web page or application. Taking the three same elements – Subject, Space, and resulting Movement – we can guide a user’s eye to the elements we need to. As designers, or content editors, framing photographs correctly can have a subtle but important effect on how a page is visually scanned. Take this example:
The BBC homepage uses great photography as a way of promoting content. Here, they have cropped the main photograph to guide the user’s eye into the content.
By applying the same theory, the designer or content editor has applied considerable Looking Room (2) to the photograph to create balance with the overall page design, but also to create movement of the user’s eye toward the content (1)
If the image was flipped horizontally. The Looking Room is now on the right. The subject of the photograph is looking off the page, drawing the user’s eye away from the content. Once again, this results in a confusing back and forth as your eye fights its way over to the left of the page.
A little bit of Art Direction
Art Direction can be described as the act or process of managing the visual presentation of content. Art Direction is difficult to do on the web, because content and presentation are, more often than not, separated. But where there are images, and when we know the templates that those images will populate, we can go a little way to bridging the gap between content and presentation.
By understanding the value of framing and Looking Room, and the fact that it extends beyond just a good looking photograph, we can start to see photography playing more of an integral role in the communication of content.
We won’t just be populating templates. We’ll be art directing.
Photo credits:
Portrait by Carsten Tolkmit
Horse by Mike Pedroncelli |
2008 |
Mark Boulton |
markboulton |
2008-12-05T00:00:00+00:00 |
https://24ways.org/2008/art-directing-with-looking-room/ |
design |
108 |
A Festive Type Folly |
‘Tis the season to be jolly, so the carol singers tell us. At 24 ways, we’re keeping alive another British tradition that includes the odd faux-Greco-Roman building dotted around the British countryside, Tower Bridge built in 1894, and your Dad’s Christmas jumper with the dancing reindeer motif. ‘Tis the season of the folly!
24 Ways to impress your friends
The example is not an image, just text. You may wish to see a screenshot in Safari to compare with your own operating system and browser rendering.
Like all follies this is an embellishment — a bit of web typography fun. It’s similar to the masthead text at my place, but it’s also a hyperlink. Unlike the architectural follies of the past, no child labour was used to fund or build it, just some HTML flavoured with CSS, and a heavy dose of Times New Roman. Why Times New Roman, you ask? Well, after a few wasted hours experimenting with heaps of typefaces, seeking an elusive consistency of positioning and rendering across platforms, it proved to be the most consistent. Who’d‘a thought? To make things more interesting, I wanted to use a traditional scale and make the whole thing elastic by using relative lengths that would react to a person’s font size. So, to the meat of this festive frippery:
There are three things we rely on to create this indulgence:
Descendant selectors
Absolute positioning
Inheritance
HTML & Descendant Selectors
The markup for the folly might seem complex at first glance. To semantics pedants and purists it may seem outrageous. If that’s you, read on at your peril! Here it is with lots of whitespace:
<div id="type">
<h1>
<a href="/">
<em>2
<span>4
<span>w
<span>a
<span>y
<span>s</span>
</span>
</span>
</span>
</span>
</em>
<strong>to
<span>i
<span>m
<span>pre
<span>s
<span>s
<span>your
<span>friends</span>
</span>
</span>
</span>
</span>
</span>
</span>
</strong>
</a>
</h1>
</div>
Why so much markup? Well, we want to individually style many of the glyphs. By nesting the elements, we can pick out the bits we need as descendant selectors.
To retain a smidgen of semantics, the text is wrapped in <h1> and <a> elements. The two phrases, “24 ways” and “to impress your friends” are wrapped in <em> and <strong> tags, respectively. Within those loving arms, their descendant <span>s cascade invisibly, making a right mess of our source, but ready to be picked out in our CSS rules.
So, to select the “2” from the example we can simply write, #type h1 em{ }. Of course, that selects everything within the <em> tags, but as we drill down the document tree, selecting other glyphs, any property / value styles can be reset or changed as required.
Pixels Versus Ems
Before we get stuck into the CSS, I should say that the goal here is to have everything expressed in relative “em” lengths. However, when I’m starting out, I use pixels for all values, and only convert them to ems after I’ve finished. It saves re-calculating the em length for every change I make as the folly evolves, but still makes the final result elastic, without relying on browser zoom.
To skip ahead, see the complete CSS.
Absolutely Positioned Glyphs
If a parent element has position: relative, or position: absolute applied to it, all children of that parent can be positioned absolutely relative to it. (See Dave Shea’s excellent introduction to this.) That’s exactly how the folly is achieved. As the parent, #type also has a font-size of 16px set, a width and height, and some basic style with a background and border:
#type{
font-size: 16px;
text-align: left;
background: #e8e9de;
border: 0.375em solid #fff;
width: 22.5em;
height: 13.125em;
position: relative;
}
The h1 is also given a default style with a font-size of 132px in ems relative to the parent font-size of 16px:
#type h1{
font-family: "Times New Roman", serif;
font-size: 8.25em; /* 132px */
line-height: 1em;
font-weight: 400;
margin: 0;
padding: 0;
}
To get the em value, we divide the required size in pixels by the actual parent font-size in pixels
132 ÷ 16 = 8.25
We also give the descendants of the h1 some default properties. The line height, style and weight are normalised, they are positioned absolutely relative to #type, and a border and padding is applied:
#type h1 em,
#type h1 strong,
#type h1 span{
line-height: 1em;
font-style: normal;
font-weight: 400;
position: absolute;
padding: 0.1em;
border: 1px solid transparent;
}
The padding ensures that some browsers don’t forget about parts of a glyph that are drawn outside of their invisible container. When this happens, IE will trim the glyph, cutting off parts of descenders, for example. The border is there to make sure the glyphs have layout. Without this, positioning can be problematic. IE6 will not respect the transparent border colour — it uses the actual text colour — but in all other respects renders the example. You can hack around it, but it seemed unnecessary for this example.
Once these defaults are established, the rest is trial and error. As a quick example, the numeral “2” is first to be positioned:
#type h1 a em{
font-size: 0.727em; /* (2) 96px */
left: 0.667em;
top: 0;
}
Every element of the folly is positioned in exactly the same way as you can see in the complete CSS. When converting pixels to ems, the font-size is set first. Then, because we know what that is, we calculate the equivalent x- and y-position accordingly.
Inheritance
CSS inheritance gave me a headache a long time ago when I first encountered it. After the penny dropped I came to experience something disturbingly close to affection for this characteristic. What it basically means is that children inherit the characteristics of their parents. For example:
We gave #type a font-size of 16px.
For #type h1 we changed it by setting font-size: 8.25em;. Than means that #type h1 now has a computed font-size of 8.25 × 16px = 132px.
Now, all children of #type h1 in the document tree will inherit a font-size of 132px unless we explicitly change it as we did for #type h1 a em.
The “2” in the example — selected with #type h1 a em — is set at 96px with left and top positioning calculated relatively to that. So, the left position of 0.667em is 0.667 × 96 = 64px, approximately (three decimal points in em lengths don’t always give exact pixel equivalents).
One way to look at inheritance is as a cascade of dependancy: In our example, the computed font size of any given element depends on that of the parent, and the absolute x- and y-position depends on the computed font size of the element itself.
Link Colours
The same descendant selectors we use to set and position the type are also used to apply the colour by combining them with pseudo-selectors like :focus and :hover. Because the descendant selectors are available to us, we can pretty much pick out any glyph we like. First, we need to disable the underline:
#type h1 a:link,
#type h1 a:visited{
text-decoration: none;
}
In our example, the “24” has a unique default state (colour):
#type h1 a:link em,
#type h1 a:visited em{
color: #624;
}
The rest of the “Ways” text has a different colour, which it shares with the large “s” in “impress”:
#type h1 a:link em span span,
#type h1 a:visited em span span,
#type h1 a:link strong span span span span,
#type h1 a:visited strong span span span span{
color: #b32720;
}
“24” changes on :focus, :hover and :active. Critically though, the whole of the “24 Ways” text, and the large “s” in “impress” all have the same style in this instance:
#type h1 a:focus em,
#type h1 a:hover em,
#type h1 a:active em,
#type h1 a:focus em span span,
#type h1 a:hover em span span,
#type h1 a:active em span span,
#type h1 a:focus strong span span span span,
#type h1 a:hover strong span span span span,
#type h1 a:active strong span span span span{
color: #804;
}
If a descendant selector has a :link and :visited state set as a pseudo element, it needs to also have the corresponding :focus, :hover and :active states set.
A Final Note About Web Typography
From grids to basic leading to web fonts, and even absolute positioning, there’s a wealth of things we can do to treat type on the Web with love and respect. However, experiments like this can highlight the vagaries of rasterisation and rendering that limit our ability to achieve truly subtle and refined results. At the operating system level, the differences in type rendering are extreme, and even between sequential iterations in Windows — from Standard to ClearType — they can be daunting. Add to that huge variations in screen quality, and even the paper we print our type onto has many potential variations. Compare our example in Safari 3.2.1 / OS X 10.5.5 (left) and IE7 / Win XP (right). Both rendered on a 23” Apple Cinema HD (LCD):
Browser developers continue to make great strides. However, those of us who set type on the Web need more consistency and quality if we want to avoid technologies like Flash and evolve web typography. Although web typography is inevitably — and mistakenly — compared unfavourably to print, it has the potential to achieve the same refinement in a different way. Perhaps one day, the glyphs of our favourite faces, so carefully crafted, kerned and hinted for the screen, will be rendered with the same precision with which they were drawn by type designers and styled by web designers. That would be my wish for the new year. Happy holidays! |
2008 |
Jon Tan |
jontan |
2008-12-17T00:00:00+00:00 |
https://24ways.org/2008/a-festive-type-folly/ |
design |
111 |
Geometric Background Patterns |
When the design is finished and you’re about to start the coding process, you have to prepare your graphics. If you’re working with a pattern background you need to export only the repeating fragment. It can be a bit tricky to isolate a fragment to achieve a seamless pattern background. For geometric patterns there is a method I always follow and that I want to share with you. Take for example a perfect 45° diagonal line pattern.
How do you define this pattern fragment so it will be rendered seamlessly?
Here is the method I usually follow to avoid a mismatch. First, zoom in so you see enough detail and you can distinguish the pixels. Select the Rectangular Marquee Selection tool and start your selection at the intersection of 2 different colors of a diagonal line. Hold down the Shift key while dragging so you drag a perfect square.
Release the mouse when you reach the exact same intesection (as your starting) point at the top right.
Copy this fragment (using Copy Merged: Cmd/Ctrl + Shift + C) and paste the fragment in a new layer. Give this layer the name ‘pattern’. Now hold down the Command Key (Control Key on Windows) and click on the ‘pattern’ layer in the Layers Palette to select the fragment. Now go to Edit > Define Pattern, enter a name for your pattern and click OK. Test your pattern in a new document. Create a new document of 600 px by 400px, hit Cmd/Ctrl + A and go to Edit > Fill… and choose your pattern. If the result is OK, you have created a perfect pattern fragment.
Below you see this pattern enlarged. The guides show the boundaries of the pattern fragment and the red pixels are the reference points. The red pixels at the top right, bottom right and bottom left should match the red pixel at the top left.
This technique should work for every geometric pattern. Some patterns are easier than others, but this, and the Photoshop pattern fill test, has always been my guideline.
Other geometric pattern examples
Example 1
Not all geometric pattern fragments are squares. Some patterns look easy at first sight, because they look very repetitive, but they can be a bit tricky.
Zoomed in pattern fragment with point of reference shown:
Example 2
Some patterns have a clear repeating point that can guide you, such as the blue small circle of this pattern as you can see from this zoomed in screenshot:
Zoomed in pattern fragment with point of reference shown:
Example 3
The different diagonal colors makes a bit more tricky to extract the correct pattern fragment.
The orange dot, which is the starting point of the selection is captured a few times inside the fragment selection: |
2008 |
Veerle Pieters |
veerlepieters |
2008-12-02T00:00:00+00:00 |
https://24ways.org/2008/geometric-background-patterns/ |
design |
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 |
133 |
Gravity-Defying Page Corners |
While working on Stikkit, a “page curl” came to be.
Not being as crafty as Veerle, you see.
I fired up Photoshop to see what could be.
“Another copy is running on the network“ … oopsie.
With license issues sorted out and a concept in mind
I set out to create something flexible and refined.
One background image and code that is sure to be lean.
A simple solution for lazy people like me.
The curl I’ll be showing isn’t a curl at all.
It’s simply a gradient that’s 18 pixels tall.
With a fade to the left that’s diagonally aligned
and a small fade on the right that keeps the illusion defined.
Create a selection with the marquee tool (keeping in mind a reasonable minimum width) and drag a gradient (black to transparent) from top to bottom.
Now drag a gradient (the background color of the page to transparent) from the bottom left corner to the top right corner.
Finally, drag another gradient from the right edge towards the center, about 20 pixels or so.
But the top is flat and can be positioned precisely
just under the bottom right edge very nicely.
And there it will sit, never ever to be busted
by varying sizes of text when adjusted.
<div id="page">
<div id="page-contents">
<h2>Gravity-Defying!</h2>
<p>Lorem ipsum dolor ...</p>
</div>
</div>
Let’s dive into code and in the markup you’ll see
“is that an extra div?” … please don’t kill me?
The #page div sets the width and bottom padding
whose height is equal to the shadow we’re adding.
The #page-contents div will set padding in ems
to scale with the text size the user intends.
The background color will be added here too
but not overlapping the shadow where #page’s padding makes room.
A simple technique that you may find amusing
is to substitute a PNG for the GIF I was using.
For that would be crafty and future-proof, too.
The page curl could sit on any background hue.
I hope you’ve enjoyed this easy little trick.
It’s hardly earth-shattering, and arguably slick.
But it could come in handy, you just never know.
Happy Holidays! And pleasant dreams of web three point oh. |
2006 |
Dan Cederholm |
dancederholm |
2006-12-24T00:00:00+00:00 |
https://24ways.org/2006/gravity-defying-page-corners/ |
design |
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 |
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 |
140 |
Styling hCards with CSS |
There are plenty of places online where you can learn about using the hCard microformat to mark up contact details at your site (there are some resources at the end of the article). But there’s not yet been a lot of focus on using microformats with CSS. So in this installment of 24 ways, we’re going to look at just that – how microformats help make CSS based styling simpler and more logical.
Being rich, quite complex structures, hCards provide designers with a sophisticated scaffolding for styling them. A recent example of styling hCards I saw, playing on the business card metaphor, was by Andy Hume, at http://thedredge.org/2005/06/using-hcards-in-your-blog/. While his approach uses fixed width cards, let’s take a look at how we might style a variable width business card style for our hCards.
Let’s take a common hCard, which includes address, telephone and email details
<div class="vcard">
<p class="fn org">Web Directions North
<a href="http://suda.co.uk/projects/X2V/get-vcard.php?uri=http://north.webdirections.org/contact/">
<img src="images/vcard-add.png" alt="download vcard icon"></a>
</p>
1485 Laperrière Avenue
Ottawa ON K1Z 7S8
Canada
Phone/Fax: Work: 61 2 9365 5007
Email: info@webdirections.org
We’ll be using a variation on the now well established “sliding doors” technique (if you create a CSS technique, remember it’s very important to give it a memorable name or acronym, and bonus points if you get your name in there!) by Douglas Bowman, enhanced by Scott Schiller (see http://www.schillmania.com/projects/dialog/,) which will give us a design which looks like this
The technique, in a nutshell, uses background images on four elements, two at the top, and two at the bottom, to add each rounded corner.
We are going to make this design “fluid” in the sense that it grows and shrinks in proportion with the size of the font that the text of the element is displayed with. This is sometimes referred to as an “em driven design” (we’ll see why in a moment).
To see how this works in practice, here’s the same design with the text “zoomed” up in size
and the same design again, when we zoom the text size down
By the way, the hCard image comes from Chris Messina, and you can download it and other microformat icons from the microformats wiki.
Now, with CSS3, this whole task would be considerably easier, because we can add multiple background images to an element, and border images for each edge of an element. Safari, version 1.3 up, actually supports multiple background images, but sadly, it’s not supported in Firefox 1.5, or even Firefox 2.0 (let’s not mention IE7 eh?). So it’s probably too little supported to use now. So instead we’ll use a technique that only involves CSS2, and works in pretty much any browser.
Very often, developers add div or span elements as containers for these background images, and in fact, if you visit Scott Shiller’s site, that’s what he has done there. But if at all possible we shouldn’t be adding any HTML simply for presentational purposes, even if the presentation is done via CSS. What we can do is to use the HTML we have already, as much as is possible, to add the style we want. This can take some creative thinking, but once you get the hang of this approach it becomes a more natural way of using HTML compared with simply adding divs and spans at will as hooks for style. Of course, this technique isn’t always simple, and in fact sometimes simply not possible, requiring us to add just a little HTML to provide the “hooks” for CSS.
Let’s go to work
The first step is to add a background image to the whole vCard element.
We make this wide enough (for example 1000 or more pixels) and tall enough that no matter how large the content of the vCard grows, it will never overflow this area. We can’t simply repeat the image, because the top left corner will show when the image repeats.
We add this as the background image of the vCard element using CSS.
While we are at it, let’s give the text a sans-serif font, some color so that it will be visible, and stop the image repeating.
.vcard {
background-image: url(images/vcardfill.png);
background-repeat: no-repeat;
color: #666;
font-family: "Lucida Grande", Verdana, Helvetica, Arial, sans-serif;
}
Which in a browser, will look something like this.
Next step we need to add the top right hand corner of the hCard. In keeping with our aim of not adding HTML simply for styling purposes, we want to use the existing structure of the page where possible. Here, we’ll use the paragraph of class fn and org, which is the first child element of the vcard element.
<p class="fn org">Web Directions Conference Pty Ltd <img src="images/vcard-add.png" alt="download vcard icon"></p>
Here’s our CSS for this element
.fn {
background-image: url(images/topright.png);
background-repeat: no-repeat;
background-position: top right;
padding-top: 2em;
font-weight: bold;
font-size: 1.1em;
}
Again, we don’t want it to repeat, but this time, we’ve specified a background position for the image. This will make the background image start from the top, but its right edge will be located at the right edge of the element. I also made the font size a little bigger, and the weight bold, to differentiate it from the rest of the text in the hCard.
Here’s the image we are adding as the background to this element.
So, putting these two CSS statements together we get
We specified a padding-top of 2em to give some space between the content of the fn element and the edge of the fn element. Otherwise the top of the hCard image would be hard against the border. To see this in action, just remove the padding-top: 2em; declaration and preview in a browser.
So, with just two statements, we are well under way. We’ve not even had to add any HTML so far. Let’s turn to the bottom of the element, and add the bottom border (well, the background image which will serve as that border).
Now, which element are we going to use to add this background image to?
OK, here I have to admit to a little, teensie bit of cheating. If you look at the HTML of the hCard, I’ve grouped the email and telephone properties into a div, with a class of telecommunications. This grouping is not strictly requred for our hCard.
<div class="telecommunications">
<p class="tel">Phone/Fax: <span class="tel"><span class="type">Work</span>:
<span class="value">61 2 9365 5007</span></p>
<p class="email">Email: <a class="value" href="mailto:info@webdirections.org">info@webdirections.org</a></p>
</div>
Now, I chose that class name because that is what the vCard specification calls this group of properties. And typically, I do tend to group together related elements using divs when I mark up content. I find it makes the page structure more logical and readable. But strictly speaking, this isn’t necessary, so you may consider it cheating. But my lesson in this would be, if you are going to add markup, try to make it as meaningful as possible.
As you have probably guessed by now, we are going to add one part of the bottom border image to this element. We’re going to add this image as the background-image.
Again, it will be a very wide image, like the top left one, so that no matter how wide the element might get, the background image will still be wide enough. Now, we’ll need to make this image sit in the bottom left of the element we attach it to, so we use a backgound position of left bottom (we put the horizontal position before the vertical). Here’s our CSS statement for this
.telecommunications {
background-image: url(images/bottom-left.png);
background-repeat: no-repeat;
background-position: left bottom;
margin-bottom: 2em;
}
And that will look like this
Not quite there, but well on the way. Time for the final piece in the puzzle.
OK, I admit, I might have cheated just a little bit more in this step. But like the previous step, all valid, and (hopefully) quite justifiable markup. If we look at the HTML again, you’ll find that our email address is marked up like this
<p class="email">Email: <a class="value" href="mailto:info@webdirections.org">info@webdirections.org</a></p>
Typically, in hCard, the value part of this property isn’t required, and we could get away with
<a class="email" href="mailto:info@webdirections.org">info@webdirections.org</a>
The form I’ve used, with the span of class value is however, perfectly valid hCard markup (hard allows for multiple email addresses of different types, which is where this typically comes in handy). Why have I gone to all this trouble? Well, when it came to styling the hCard, I realized I needed a block element to attach the background image for the bottom right hand corner to. Typically the last block element in the containing element is the ideal choice (and sometimes it’s possible to take an inline element, for example the link here, and use CSS to make it a block element, and attach it to that, but that really doesn’t work with this design).
So, if we are going to use the paragraph which contains the email link, we need a way to select it exclusively, which means that with CSS2 at least, we need a class or id as a hook for our CSS selector (in CSS3 we could use the last-child selector, which selects the last child element of a specified element, but again, as last child is not widely supported, we won’t rely on it here.)
So, the least worst thing we could do is take an existing element, and add some reasonably meaningful markup to it. That’s why we gave the paragraph a class of email, and the email address a class of value. Which reminds me a little of a moment in Hamlet
The lady doth protest too much, methinks
OK, let’s get back to the CSS.
We add the bottom right corner image, positioning it in the bottom right of the element, and making sure it doesn’t repeat. We also add some padding to the bottom, to balance out the padding we added to the top of the hCard.
p.email {
background-image: url(images/bottom-right.png);
background-position: right bottom;
background-repeat: no-repeat;
padding-bottom: 2em;
}
Which all goes to make our hCard look like this
It just remains for us to clean up a little.
Let’s start from the top. We’ll float the download image to the right like this
.vcard img {
float: right;
padding-right: 1em;
margin-top: -1em
}
See how we didn’t have to add a class to style the image, we used the fact that the image is a descendent of the vcard element, and a descendent selector. In my experience, the very widely supported, powerful descendent selector is one of the most underused aspects of CSS. So if you don’t use it frequently, look into it in more detail.
We added some space to the right of the image, and pulled it up a bit closer to the top of the hCard, like this
We also want to add some whitespace between the edge of the hCard and the text. We would typically add padding to the left of the containing element, (in this case the vcard element) but this would break our bottom left hand corner, like this
That’s because the div element we added this bottom left background image to would be moved in by the padding on its containing element.
So instead, we add left margin to all the paragraphs in the hCard
.vcard p {
margin-left: 1em;
}
(there is the descendent selector again – it is the swiss army knife of CSS)
Now, we’ve not yet made the width of the hCard a function of the size of the text inside it (or “em driven” as we described it earlier). We do this by giving the hCard a width that is specified in em units. Here we’ll set a width of say 28em, which makes the hCard always roughly as wide as 28 characters (strictly speaking 28 times the width of the letter capital M).
So the statement for our containing vcard element becomes
.vcard {
background-image: url(images/vcardfill.png);
background-repeat: no-repeat;
color: #666;
font-family: "Lucida Grande", Verdana, Helvetica, Arial, sans-serif;
width: 28em;
}
and now our element will look like this
We’ve used almost entirely the existing HTML from our original hCard (adding just a little, and trying as much as possible to keep that additional markup meaningful), and just 6 CSS statements.
Holiday Bonus – a downloadable vCard
Did you notice this part of the HTML
<a href="http://suda.co.uk/projects/X2V/get-vcard.php?uri=http://north.webdirections.org/contact/">
<img src="images/vcard-add.png" alt="download vcard icon"></a>
What’s with the odd looking url
<a href="http://suda.co.uk/projects/X2V/get-vcard.php?uri=http://north.webdirections.org/contact/"
If you click the link, X2V, a nifty web service from Brian Suda, grabs the page at the URL, and if it finds a hCard, converts it to a vCard, and depending on how your system is setup, automatically downloads it and adds it to your address book (Mac OS X) or prompts you whether you’d like to save the vCard and add it to whatever application is the default vCard handler on your system.
What X2V does is take the actual HTML of your hCard, and with the magic of XSLT, converts it to a vCard. So, by simply marking up contact details using hCard, and adding a link like this, you automatically get downloadable vCard – and if you change your contact details, and update the hCard, there’s no vCard file to update as well.
Technorati also have a similar service at http://technorati.com/contact so you might want to use that if you expect any kind of load, as they can probably afford the bandwidth more than Brian!
If you want to play with the HTML and CSS for this design, the code and images can be downloaded.
Hope you enjoyed this, and found it useful. If so, you might like to check out my microformats focussed blog, or get along to Web Directions North, where I’ll be speaking along with Dan Cederholmn and Tantek Çelik in a 2 hour session focussed solely on microformats. And keep an eye out for my microformats book, from which this article has been adapted, coming in the spring of 2007.
A happy festive season, and all the best for 2007
John
Some hCard links
The hCard entry at microformats.org
The hCard Creator
The hCard cheatsheet
The hCard FAQ
Ideas for authoring hCards
Microfomatique – a blog about microformats
Web Directions North – featuring a full 2 hour focussed microformats session |
2006 |
John Allsopp |
johnallsopp |
2006-12-14T00:00:00+00:00 |
https://24ways.org/2006/styling-hcards-with-css/ |
design |
141 |
Compose to a Vertical Rhythm |
“Space in typography is like time in music. It is infinitely divisible, but a few proportional intervals can be much more useful than a limitless choice of arbitrary quantities.” So says the typographer Robert Bringhurst, and just as regular use of time provides rhythm in music, so regular use of space provides rhythm in typography, and without rhythm the listener, or the reader, becomes disorientated and lost.
On the Web, vertical rhythm – the spacing and arrangement of text as the reader descends the page – is contributed to by three factors: font size, line height and margin or padding. All of these factors must calculated with care in order that the rhythm is maintained.
The basic unit of vertical space is line height. Establishing a suitable line height that can be applied to all text on the page, be it heading, body copy or sidenote, is the key to a solid dependable vertical rhythm, which will engage and guide the reader down the page. To see this in action, I’ve created an example with headings, footnotes and sidenotes.
Establishing a suitable line height
The easiest place to begin determining a basic line height unit is with the font size of the body copy. For the example I’ve chosen 12px. To ensure readability the body text will almost certainly need some leading, that is to say spacing between the lines. A line-height of 1.5em would give 6px spacing between the lines of body copy. This will create a total line height of 18px, which becomes our basic unit. Here’s the CSS to get us to this point:
body {
font-size: 75%;
}
html>body {
font-size: 12px;
}
p {
line-height 1.5em;
}
There are many ways to size text in CSS and the above approach provides and accessible method of achieving the pixel-precision solid typography requires. By way of explanation, the first font-size reduces the body text from the 16px default (common to most browsers and OS set-ups) down to the 12px we require. This rule is primarily there for Internet Explorer 6 and below on Windows: the percentage value means that the text will scale predictably should a user bump the text size up or down. The second font-size sets the text size specifically and is ignored by IE6, but used by Firefox, Safari, IE7, Opera and other modern browsers which allow users to resize text sized in pixels.
Spacing between paragraphs
With our rhythmic unit set at 18px we need to ensure that it is maintained throughout the body copy. A common place to lose the rhythm is the gaps set between margins. The default treatment by web browsers of paragraphs is to insert a top- and bottom-margin of 1em. In our case this would give a spacing between the paragraphs of 12px and hence throw the text out of rhythm. If the rhythm of the page is to be maintained, the spacing of paragraphs should be related to the basic line height unit. This is achieved simply by setting top- and bottom-margins equal to the line height.
In order that typographic integrity is maintained when text is resized by the user we must use ems for all our vertical measurements, including line-height, padding and margins.
p {
font-size:1em;
margin-top: 1.5em;
margin-bottom: 1.5em;
}
Browsers set margins on all block-level elements (such as headings, lists and blockquotes) so a way of ensuring that typographic attention is paid to all such elements is to reset the margins at the beginning of your style sheet. You could use a rule such as:
body,div,dl,dt,dd,ul,ol,li,h1,h2,h3,h4,h5,h6,pre,form,fieldset,p,blockquote,th,td {
margin:0;
padding:0;
}
Alternatively you could look into using the Yahoo! UI Reset style sheet which removes most default styling, so providing a solid foundation upon which you can explicitly declare your design intentions.
Variations in text size
When there is a change in text size, perhaps with a heading or sidenotes, the differing text should also take up a multiple of the basic leading. This means that, in our example, every diversion from the basic text size should take up multiples of 18px. This can be accomplished by adjusting the line-height and margin accordingly, as described following.
Headings
Subheadings in the example page are set to 14px. In order that the height of each line is 18px, the line-height should be set to 18 ÷ 14 = 1.286. Similarly the margins above and below the heading must be adjusted to fit. The temptation is to set heading margins to a simple 1em, but in order to maintain the rhythm, the top and bottom margins should be set at 1.286em so that the spacing is equal to the full 18px unit.
h2 {
font-size:1.1667em;
line-height: 1.286em;
margin-top: 1.286em;
margin-bottom: 1.286em;
}
One can also set asymmetrical margins for headings, provided the margins combine to be multiples of the basic line height. In our example, a top margin of 1½ lines is combined with a bottom margin of half a line as follows:
h2 {
font-size:1.1667em;
line-height: 1.286em;
margin-top: 1.929em;
margin-bottom: 0.643em;
}
Also in our example, the main heading is given a text size of 18px, therefore the line-height has been set to 1em, as has the margin:
h1 {
font-size:1.5em;
line-height: 1em;
margin-top: 0;
margin-bottom: 1em;
}
Sidenotes
Sidenotes (and other supplementary material) are often set at a smaller size to the basic text. To keep the rhythm, this smaller text should still line up with body copy, so a calculation similar to that for headings is required. In our example, the sidenotes are set at 10px and so their line-height must be increased to 18 ÷ 10 = 1.8.
.sidenote {
font-size:0.8333em;
line-height:1.8em;
}
Borders
One additional point where vertical rhythm is often lost is with the introduction of horizontal borders. These effectively act as shims pushing the subsequent text downwards, so a two pixel horizontal border will throw out the vertical rhythm by two pixels. A way around this is to specify horizontal lines using background images or, as in our example, specify the width of the border in ems and adjust the padding to take up the slack.
The design of the footnote in our example requires a 1px horizontal border. The footnote contains 12px text, so 1px in ems is 1 ÷ 12 = 0.0833. I have added a margin of 1½ lines above the border (1.5 × 18 ÷ 12 = 2.5ems), so to maintain the rhythm the border + padding must equal a ½ (9px). We know the border is set to 1px, so the padding must be set to 8px. To specify this in ems we use the familiar calculation: 8 ÷ 12 = 0.667.
Hit me with your rhythm stick
Composing to a vertical rhythm helps engage and guide the reader down the page, but it takes typographic discipline to do so. It may seem like a lot of fiddly maths is involved (a few divisions and multiplications never hurt anyone) but good type setting is all about numbers, and it is this attention to detail which is the key to success. |
2006 |
Richard Rutter |
richardrutter |
2006-12-12T00:00:00+00:00 |
https://24ways.org/2006/compose-to-a-vertical-rhythm/ |
design |
146 |
Increase Your Font Stacks With Font Matrix |
Web pages built in plain old HTML and CSS are displayed using only the fonts installed on users’ computers (@font-face implementations excepted). To enable this, CSS provides the font-family property for specifying fonts in order of preference (often known as a font stack). For example:
h1 {font-family: 'Egyptienne F', Cambria, Georgia, serif}
So in the above rule, headings will be displayed in Egyptienne F. If Egyptienne F is not available then Cambria will be used, failing that Georgia or the final fallback default serif font. This everyday bit of CSS will be common knowledge among all 24 ways readers.
It is also a commonly held belief that the only fonts we can rely on being installed on users’ computers are the core web fonts of Arial, Times New Roman, Verdana, Georgia and friends. But is that really true?
If you look in the fonts folder of your computer, or even your Mum’s computer, then you are likely to find a whole load of fonts besides the core ones. This is because many software packages automatically install extra typefaces. For example, Office 2003 installs over 100 additional fonts. Admittedly not all of these fonts are particularly refined, and not all are suitable for the Web. However they still do increase your options.
The Matrix
I have put together a matrix of (western) fonts showing which are installed with Mac and Windows operating systems, which are installed with various versions of Microsoft Office, and which are installed with Adobe Creative Suite.
The matrix is available for download as an Excel file and as a CSV. There are no readily available statistics regarding the penetration of Office or Creative Suite, but you can probably take an educated guess based on your knowledge of your readers.
The idea of the matrix is that use can use it to help construct your font stack. First of all pick the font you’d really like for your text – this doesn’t have to be in the matrix. Then pick the generic family (serif, sans-serif, cursive, fantasy or monospace) and a font from each of the operating systems. Then pick any suitable fonts from the Office and Creative Suite lists.
For example, you may decide your headings should be in the increasingly ubiquitous Clarendon. This is a serif type face. At OS-level the most similar is arguably Georgia. Adobe CS2 comes with Century Old Style which has a similar feel. Century Schoolbook is similar too, and is installed with all versions of Office. Based on this your font stack becomes:
font-family: 'Clarendon Std', 'Century Old Style Std', 'Century Schoolbook', Georgia, serif
Note the ‘Std’ suffix indicating a ‘standard’ OpenType file, which will normally be your best bet for more esoteric fonts.
I’m not suggesting the process of choosing suitable fonts is an easy one. Firstly there are nearly two hundred fonts in the matrix, so learning what each font looks like is tricky and potentially time consuming (if you haven’t got all the fonts installed on a machine to hand you’ll be doing a lot of Googling for previews). And it’s not just as simple as choosing fonts that look similar or have related typographic backgrounds, they need to have similar metrics as well, This is especially true in terms of x-height which gives an indication of how big or small a font looks.
Over to You
The main point of all this is that there are potentially more fonts to consider than is generally accepted, so branch out a little (carefully and tastefully) and bring a little variety to sites out there. If you come up with any novel font stacks based on this approach, please do blog them (tagged as per the footer) and at some point they could all be combined in one place for everyone to consider.
Appendix
What about Linux?
The only operating systems in the matrix are those from Microsoft and Apple. For completeness, Linux operating systems should be included too, although these are many and varied and very much in a minority, so I omitted them for time being. For the record, some Linux distributions come packaged with Microsoft’s core fonts. Others use the Vera family, and others use the Liberation family which comprises fonts metrically identical to Times New Roman and Arial.
Sources
The sources of font information for the matrix are as follows:
Windows XP SP2
Windows Vista
Office 2003
Office 2007
Mac OSX Tiger
Mac OSX Leopard (scroll down two thirds)
Office 2004 (Mac) by inspecting my Microsoft Office 2004/Office/Fonts folder
Office 2008 (Mac) is expected to be as Office 2004 with the addition of the Vista ClearType fonts
Creative Suite 2 (see pdf link in first comment)
Creative Suite 3 |
2007 |
Richard Rutter |
richardrutter |
2007-12-17T00:00:00+00:00 |
https://24ways.org/2007/increase-your-font-stacks-with-font-matrix/ |
design |
148 |
Typesetting Tables |
Tables have suffered in recent years on the web. They were used for laying out web pages. Then, following the Web Standards movement, they’ve been renamed by the populous as `data tables’ to ensure that we all know what they’re for. There have been some great tutorials for the designing tables using CSS for presentation and focussing on the semantics in the displaying of data in the correct way. However, typesetting tables is a subtle craft that has hardly had a mention.
Table design can often end up being a technical exercise. What data do we need to display? Where is the data coming from and what form will it take? When was the last time your heard someone talk about lining numerals? Or designing to the reading direction?
Tables are not read like sentences
When a reader looks at, and tries to understand, tabular data, they’re doing a bunch of things at the same time.
Generally, they’re task based; they’re looking for something.
They are reading horizontally AND vertically
Reading a table is not like reading a paragraph in a novel, and therefore shouldn’t be typeset in the same way. Designing tables is information design, it’s functional typography—it’s not a time for eye candy.
Typesetting tables
Typesetting great looking tables is largely an exercise in restraint. Minimal interference with the legibility of the table should be in the forefront of any designers mind.
When I’m designing tables I apply some simple rules:
Plenty of negative space
Use the right typeface
Go easy on the background tones, unless you’re giving reading direction visual emphasis
Design to the reading direction
By way of explanation, here are those rules as applied to the following badly typeset table.
Your default table
This table is a mess. There is no consideration for the person trying to read it. Everything is too tight. The typeface is wrong. It’s flat. A grim table indeed.
Let’s see what we can do about that.
Plenty of negative space
The badly typeset table has been set with default padding. There has been little consideration for the ascenders and descenders in the type interfering with the many horizontal rules.
The first thing we do is remove most of the lines, or rules. You don’t need them – the data in the rows forms its own visual rules. Now, with most of the rules removed, the ones that remain mean something; they are indicating some kind of hierarchy to the help the reader understand what the different table elements mean – in this case the column headings.
Now we need to give the columns and rows more negative space. Note the framing of the column headings. I’m giving them more room at the bottom. This negative space is active—it’s empty for a reason. The extra air in here also gives more hierarchy to the column headings.
Use the right typeface
The default table is set in a serif typeface. This isn’t ideal for a couple of reasons. This serif typeface has a standard set of text numerals. These dip below the baseline and are designed for using figures within text, not on their own. What you need to use is a typeface with lining numerals. These align to the baseline and are more legible when used for tables.
Sans serif typefaces generally have lining numerals. They are also arguably more legible when used in tables.
Go easy on the background tones, unless you’re giving reading direction visual emphasis
We’ve all seen background tones on tables. They have their use, but my feeling is that use should be functional and not decorative.
If you have a table that is long, but only a few columns wide, then alternate row shading isn’t that useful for showing the different lines of data. It’s a common misconception that alternate row shading is to increase legibility on long tables. That’s not the case. Shaded rows are to aid horizontal reading across multiple table columns. On wide tables they are incredibly useful for helping the reader find what they want.
Background tone can also be used to give emphasis to the reading direction. If we want to emphasis a column, that can be given a background tone.
Hierarchy
As I said earlier, people may be reading a table vertically, and horizontally in order to find what they want. Sometimes, especially if the table is complex, we need to give them a helping hand.
Visually emphasising the hierarchy in tables can help the reader scan the data. Column headings are particularly important. Column headings are often what a reader will go to first, so we need to help them understand that the column headings are different to the stuff beneath them, and we also need to give them more visual importance. We can do this by making them bold, giving them ample negative space, or by including a thick rule above them. We can also give the row titles the same level of emphasis.
In addition to background tones, you can give emphasis to reading direction by typesetting those elements in bold. You shouldn’t use italics—with sans serif typefaces the difference is too subtle.
So, there you have it. A couple of simple guidelines to make your tables cleaner and more readable. |
2007 |
Mark Boulton |
markboulton |
2007-12-07T00:00:00+00:00 |
https://24ways.org/2007/typesetting-tables/ |
design |
149 |
Underpants Over My Trousers |
With Christmas approaching faster than a speeding bullet, this is the perfect time for you to think about that last minute present to buy for the web geek in your life. If you’re stuck for ideas for that special someone, forget about that svelte iPhone case carved from solid mahogany and head instead to your nearest comic-book shop and pick up a selection of comics or graphic novels. (I’ll be using some of my personal favourite comic books as examples throughout).
Trust me, whether your nearest and dearest has been reading comics for a while or has never peered inside this four-colour world, they’ll thank-you for it.
Aside from indulging their superhero fantasies, comic books can provide web designers with a rich vein of inspiring ideas and material to help them create shirt button popping, trouser bursting work for the web. I know from my own personal experience, that looking at aspects of comic book design, layout and conventions and thinking about the ways that they can inform web design has taken my design work in often-unexpected directions.
There are far too many fascinating facets of comic book design that provide web designers with inspiration to cover in the time that it takes to pull your underpants over your trousers. So I’m going to concentrate on one muscle bound aspect of comic design, one that will make you think differently about how you lay out the content of your pages in panels.
A suitcase full of Kryptonite
Now, to the uninitiated onlooker, the panels of a comic book may appear to perform a similar function to still frames from a movie. But inside the pages of a comic, panels must work harder to help the reader understand the timing of a story. It is this method for conveying narrative timing to a reader that I believe can be highly useful to designers who work on the web as timing, drama and suspense are as important in the web world as they are in worlds occupied by costumed crime fighters and superheroes.
I’d like you to start by closing your eyes and thinking about your own process for laying out panels of content on a page. OK, you’ll actually be better off with your eyes open if you’re going to carry on reading.
I’ll bet you a suitcase full of Kryptonite that you often, if not always, structure your page layouts, and decide on the dimensions of those panels according to either:
The base grid that you are working to
The Golden Ratio or another mathematical schema
More likely, I bet that you decide on the size and the number of your panels based on the amount of content that will be going into them. From today, I’d like you to think about taking a different approach. This approach not only addresses horizontal and vertical space, but also adds the dimension of time to your designs.
Slowing down the action
A comic book panel not only acts as a container for its content but also indicates to a reader how much time passes within the panel and as a result, how much time the reader should focus their attention on that one panel.
Smaller panels create swift eye movement and shorter bursts of attention. Larger panels give the perception of more time elapsing in the story and subconsciously demands that a reader devotes more time to focus on it.
Concrete by Paul Chadwick (Dark Horse Comics)
This use of panel dimensions to control timing can also be useful for web designers in designing the reading/user experience. Imagine a page full of information about a product or service. You’ll naturally want the reader to focus for longer on the key benefits of your offering rather than perhaps its technical specifications.
Now take a look at this spread of pages from Watchmen by Alan Moore and Dave Gibbons.
Watchmen by Alan Moore and Dave Gibbons (Diamond Comic Distributors 2004)
Throughout this series of (originally) twelve editions, artist Dave Gibbons stuck rigidly to his 3×3 panels per page design and deviated from it only for dramatic moments within the narrative.
In particular during the last few pages of chapter eleven, Gibbons adds weight to the impending doom by slowing down the action by using larger panels and forces the reader to think longer about what was coming next. The action then speeds up through twelve smaller panels until the final panel: nothing more than white space and yet one of the most iconic and thought provoking in the entire twelve book series.
Watchmen by Alan Moore and Dave Gibbons (Diamond Comic Distributors 2004)
On the web it is common for clients to ask designers to fill every pixel of screen space with content, perhaps not understanding the drama that can be added by nothing more than white space.
In the final chapter, Gibbons emphasises the carnage that has taken place (unseen between chapters eleven and twelve) by presenting the reader with six full pages containing only single, large panels.
Watchmen by Alan Moore and Dave Gibbons (Diamond Comic Distributors 2004)
This drama, created by the artist’s use of panel dimensions to control timing, is a technique that web designers can also usefully employ when emphasising important areas of content.
Think back for a moment to the home page of Apple Inc., during the launch of their iconic iPhone, where the page contained nothing more than a large image and the phrase “Say hello to iPhone”. Rather than fill the page with sales messages, Apple’s designers allowed the space itself to tell the story and created a real sense of suspense and expectation among their readers.
Borders
Whereas on the web, panel borders are commonly used to add emphasis to particular areas of content, in comic books they take on a different and sometimes opposite role.
In the examples so far, borders have contained all of the action. Removing a border can have the opposite effect to what you might at first think. Rather than taking emphasis away from their content, in comics, borderless panels allow the reader’s eyes to linger for longer on the content adding even stronger emphasis.
Concrete by Paul Chadwick (Dark Horse Comics)
This effect is amplified when the borderless content is allowed to bleed to the edges of a page. Because the content is no longer confined, except by the edges of the page (both comic and web) the reader’s eye is left to wander out into open space.
Concrete by Paul Chadwick (Dark Horse Comics)
This type of open, borderless content panel can be highly useful in placing emphasis on the most important content on a page in exactly the very opposite way that we commonly employ on the web today.
So why is time an important dimension to think about when designing your web pages? On one level, we are often already concerned with the short attention spans of visitors to our pages and should work hard to allow them to quickly and easily find and read the content that both they and we think is important. Learning lessons from comic book timing can only help us improve that experience.
On another: timing, suspense and drama are already everyday parts of the web browsing experience. Will a reader see what they expect when they click from one page to the next? Or are they in for a surprise?
Most importantly, I believe that the web, like comics, is about story telling: often the story of the experiences that a customer will have when they use our product or service or interact with our organisation. It is this element of story telling than can be greatly improved by learning from comics.
It is exactly this kind of learning and adapting from older, more established and at first glance unrelated media that you will find can make a real distinctive difference to the design work that you create.
Fill your stockings
If you’re a visual designer or developer and are not a regular reader of comics, from the moment that you pick up your first title, I know that you will find them inspiring.
I will be writing more, and speaking about comic design applied to the web at several (to be announced) events this coming year. I hope you’ll be slipping your underpants over your trousers and joining me then. In the meantime, here is some further reading to pick up on your next visit to a comic book or regular bookshop and slip into your stockings:
Comics and Sequential Art by Will Eisner (Northern Light Books 2001)
Understanding Comics: The Invisible Art by Scott McCloud (Harper Collins 1994)
Have a happy superhero season.
(I would like to thank all of the talented artists, writers and publishers whose work I have used as examples in this article and the hundreds more who inspire me every day with their tall tales and talent.) |
2007 |
Andy Clarke |
andyclarke |
2007-12-14T00:00:00+00:00 |
https://24ways.org/2007/underpants-over-my-trousers/ |
design |
151 |
Get In Shape |
Pop quiz: what’s wrong with the following navigation?
Maybe nothing. But then again, maybe there’s something bugging you about the way it comes together, something you can’t quite put your finger on. It seems well-designed, but it also seems a little… off.
The design decisions that led to this eventual form were no doubt well-considered:
Client: The top level needs to have a “current page” status indicator of some sort.
Designer: How about a white tab?
Client: Great! The second level needs to show up underneath the first level though…
Designer: Okay, but that white tab I just added makes it hard to visually connect the bottom nav to the top.
Client: Too late, we’ve seen the white tab and we love it. Try and make it work.
Designer: Right. So I placed the second level in its own box.
Client: Hmm. They seem too separated. I can’t tell that the yellow nav is the second level of the first.
Designer: How about an indicator arrow?
Client: Brilliant!
The problem is that the end result feels awkward and forced. During the design process, little decisions were made that ultimately affect the overall shape of the navigation. What started out as a neatly contained rounded rectangle ended up as an ambiguous double shape that looks funny, though it’s often hard to pinpoint precisely why.
The Shape of Things
Well the why in this case is because seemingly unrelated elements in a design still end up visually interacting. Adding a new item to a page impacts everything surrounding it. In this navigation example, we’re looking at two individual objects that are close enough to each other that they form a relationship; if we reduce them to strictly their outlines, it’s a little easier to see that this particular combination registers oddly.
The two shapes float with nothing really grounding them. If they were connected, perhaps it would be a different story. The white tab divides the top shape in half, leaving a gap in the middle of it. There’s very little balance in this pairing because the overall shape of the navigation wasn’t considered during the design process.
Here’s another example: Gmail. Great email client, but did you ever closely look at what’s going on in that left hand navigation? The continuous blue bar around the message area spills out into the navigation. If we remove all text, we’re left with this odd configuration:
Though the reasoning for anchoring the navigation highlight against the message area might be sound, the result is an irregular shape that doesn’t correspond with anything in reality. You may never consciously notice it, but once you do it’s hard to miss. One other example courtesy of last.fm:
The two header areas are the same shade of pink so they appear to be closely connected. When reduced to their outlines it’s easy to see that this combination is off-balance: the edges don’t align, the sharp corners of the top shape aren’t consistent with the rounded corners of the bottom, and the part jutting out on the right of the bottom one seems fairly random. The result is a duo of oddly mis-matched shapes.
Design Strategies
Our minds tend to pick out familiar patterns. A clever designer can exploit this by creating references in his or her work to shapes and combinations with which viewers are already familiar. There are a few simple ideas that can be employed to help you achieve this: consistency, balance, and completion.
Consistency
A fairly simple way to unify the various disparate shapes on a page is by designing them with a certain amount of internal consistency. You don’t need to apply an identical size, colour, border, or corner treatment to every single shape; devolving a design into boring repetition isn’t what we’re after here. But it certainly doesn’t hurt to apply a set of common rules to most shapes within your work.
Consider purevolume and its multiple rounded-corner panels. From the bottom of the site’s main navigation to the grey “Extras” panels halfway down the page (shown above), multiple shapes use a common border radius for unity. Different colours, different sizes, different content, but the consistent outlines create a strong sense of similarity. Not that every shape on the site follows this rule; they break the pattern right at the top with a darker sharp-cornered header, and again with the thumbnails below. But the design remains unified, nonetheless.
Balance
Arguably the biggest problem with the last.fm example earlier is one of balance. The area poking out of the bottom shape created a fairly obvious imbalance for no apparent reason. The right hand side is visually emphasized due to the greater area of pink coverage, but with the white gap left beside it, the emphasis seems unwarranted. It’s possible to create tension in your design by mismatching shapes and throwing off the balance, but when that happens unintentionally it can look like a mistake.
Above are a few examples of design elements in balanced and unbalanced configurations. The examples in the top row are undeniably more pleasing to the eye than those in the bottom row. If these were fleshed out into full designs, those derived from the templates in the top row would naturally result in stronger work.
Take a look at the header on 9Rules for a study in well-considered balance. On the left you’ll see a couple of paragraphs of text, on the right you have floating navigational items, and both flank the site’s logo. This unusual layout combines multiple design elements that look nothing alike, and places them together in a way that anchors each so that no one weighs down the header.
Completion
And finally we come to the idea of completion. Shapes don’t necessarily need hard outlines to be read visually as shapes, which can be exploited for various purposes. Notice how Zend’s mid-page “Business Topics” and “News” items (below) fade out to the right and bottom, but the placement of two of these side-by-side creates an impression of two panels rather than three disparate floating columns. By allowing the viewer’s eye to complete the shapes, they’ve lightened up the design of the page and removed inessential lines. In a busy design this technique could prove quite handy.
Along the same lines, the individual shapes within your design may also be combined visually to form outlines of larger shapes. The differently-coloured header and main content/sidebar shapes on Veerle’s blog come together to form a single central panel, further emphasized by the slight drop shadow to the right.
Implementation
Studying how shape can be used effectively in design is simply a starting point. As with all things design-related, there are no hard and fast rules here; ultimately you may choose to bring these principles into your work more often, or break them for effect. But understanding how shapes interact within a page, and how that effect is ultimately perceived by viewers, is a key design principle you can use to impress your friends. |
2007 |
Dave Shea |
daveshea |
2007-12-16T00:00:00+00:00 |
https://24ways.org/2007/get-in-shape/ |
design |
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 |
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 |
173 |
Real Fonts and Rendering: The New Elephant in the Room |
My friend, the content strategist Kristina Halvorson, likes to call content “the elephant in the room” of web design. She means it’s the huge problem that no one on the web development team or client side is willing to acknowledge, face squarely, and plan for.
A typical web project will pass through many helpful phases of research, and numerous beneficial user experience design iterations, while the content—which in most cases is supposed to be the site’s primary focus—gets handled haphazardly at the end. Hence, elephant in the room, and hence also artist Kevin Cornell’s recent use of elephantine imagery to illustrate A List Apart articles on the subject. But I digress.
Without discounting the primacy of the content problem, we web design folk have now birthed ourselves a second lumbering mammoth, thanks to our interest in “real fonts on the web“ (the unfortunate name we’ve chosen for the recent practice of serving web-licensed fonts via CSS’s decade-old @font-face declaration—as if Georgia, Verdana, and Times were somehow unreal).
For the fact is, even bulletproof and mo’ bulletproofer @font-face CSS syntax aren’t really bulletproof if we care about looks and legibility across browsers and platforms.
Hyenas in the Breakfast Nook
The problem isn’t just that foundries have yet to agree on a standard font format that protects their intellectual property. And that, even when they do, it will be a while before all browsers support that standard—leaving aside the inevitable politics that impede all standardization efforts. Those are problems, but they’re not the elephant. Call them the coyotes in the room, and they’re slowly being tamed.
Nor is the problem that workable, scalable business models (of which Typekit‘s is the most visible and, so far, the most successful) are still being shaken out and tested. The quality and ease of use of such services, their stability on heavily visited sites (via massively backed-up server clusters), and the fairness and sustainability of their pricing will determine how licensing and serving “real fonts” works in the short and long term for the majority of designer/developers.
Nor is our primary problem that developers with no design background may serve ugly or illegible fonts that take forever to load, or fonts that take a long time to download and then display as ordinary system fonts (as happens on, say, about.validator.nu). Ugliness and poor optimization on the web are nothing new. That support for @font-face in Webkit and Mozilla browsers (and for TrueType fonts converted to Embedded OpenType in Internet Explorer) adds deadly weapons to the non-designer’s toolkit is not the technology’s fault. JavaScript and other essential web technologies are equally susceptible to abuse.
Beauty is in the Eye of the Rendering Engine
No, the real elephant in the room—the thing few web developers and no “web font” enthusiasts are talking about—has to do with legibility (or lack thereof) and aesthetics (or lack thereof) across browsers and platforms. Put simply, even fonts optimized for web use (which is a whole thing: ask a type designer) will not look good in every browser and OS. That’s because every browser treats hinting differently, as does every OS, and every OS version.
Firefox does its own thing in both Windows and Mac OS, and Microsoft is all over the place because of its need to support multiple generations of Windows and Cleartype and all kinds of hardware simultaneously. Thus “real type” on a single web page can look markedly different, and sometimes very bad, on different computers at the same company. If that web page is your company’s, your opinion of “web fonts” may suffer, and rightfully. (The advantage of Apple’s closed model, which not everyone likes, is that it allows the company to guarantee the quality and consistency of user experience.)
As near as my font designer friends and I can make out, Apple’s Webkit in Safari and iPhone ignores hinting and creates its own, which Apple thinks is better, and which many web designers think of as “what real type looks like.” The forked version of Webkit in Chrome, Android, and Palm Pre also creates its own hinting, which is close to iPhone’s—close enough that Apple, Palm, and Google could propose it as a standard for use in all browsers and platforms. Whether Firefox would embrace a theoretical Apple and Google standard is open to conjecture, and I somehow have difficulty imagining Microsoft buying in—even though they know the web is more and more mobile, and that means more and more of their customers are viewing web content in some version of Webkit.
The End of Simple
There are ways around this ugly type ugliness, but they involve complicated scripting and sniffing—the very nightmares from which web standards and the simplicity of @font-face were supposed to save us. I don’t know that even mighty Typekit has figured out every needed variation yet (although, working with foundries, they probably will).
For type foundries, the complexity and expense of rethinking classic typefaces to survive in these hostile environments may further delay widespread adoption of web fonts and the resolution of licensing and formatting issues. The complexity may also force designers (even those who prefer to own) to rely on a hosted rental model simply to outsource and stay current with the detection and programming required.
Forgive my tears. I stand in a potter’s field of ideas like “Keep it simple,” by a grave whose headstone reads “Write once, publish everywhere.” |
2009 |
Jeffrey Zeldman |
jeffreyzeldman |
2009-12-22T00:00:00+00:00 |
https://24ways.org/2009/real-fonts-and-rendering/ |
design |
174 |
Type-Inspired Interfaces |
One of the things that terrifies me most about a new project is the starting point. How is the content laid out? What colors do I pick? Once things like that are decided, it becomes significantly easier to continue design, but it’s the blank page where I spend the most time.
To that end, I often start by choosing type. I don’t need to worry about colors or layout or anything else… just the right typefaces that support the art direction. (This article won’t focus on how to choose a typeface, but there are some really great resources if you interested in that sort of thing.)
And just like that, all your work is done. “Hold it just a second,” you might say. “All I’ve done is pick type. I still have to do the rest!”
To which I would reply, “Silly rabbit. You already have!” You see, picking the right typeface gets you farther than you might think. Here are a few tips on taking cues from type to design interfaces and interface elements.
Perfecting Web 2.0
If you’re going for that beloved rounded corner look, you might class it up a bit by choosing the wonderful Omnes Pro by Joshua Darden. As the typeface already has a rounded aesthetic, making buttons that fit the style should be pretty easy.
I’ve found that using multiples helps to keep your interfaces looking balanced and proportional. Noticing that the top left edge of the letter “P” has about an 12px corner radius, let’s choose a 24px radius for our button (a multiple of 2), so that we get proper rounded corners. By taking mathematical measurements from the typeface, our button looks more thought out than just “place arbitrary text on arbitrarily-sized button.” Pretty easy, eh?
What’s in a name(plate)?
Rounded buttons are pretty popular buttons nowadays, so let’s try something a bit more stylized.
Have a gander at Brothers, a sturdy face from Emigre. The chiseled edges give us a perfect cue for a stylized button. Using the same slope, you can make plated-looking buttons that fit a different kind of style.
Headlining
You might even take some cues from the style of the typeface itself. Didone serifs are known for their lack of bracketsーthat is, a gradual transition from the stem to the serif. Instead, they typically connect at a right angle. Another common characteristic is the high contrast in the strokes: very thick stems, very thin serifs.
So, when using a high contrast typeface, you can use it to your advantage to enhance hierarchy. Following our “multiples” guideline, a 12px measurement from the stems helps us create a top rule with a height of 24px (a multiple of 2). We can take the exact 1px measurement from the serif—a multiple of 1—to create the bottom rule. Voilà! I use this technique a lot.
Swashbucklers
And don’t forget the importance of visual “speed bumps” to break up long passages of text. A beautiful face like Alejandro Paul’s Ministry Script has over a thousand characters that can be manipulated or even combined to create elegant interface elements. Altering the partial differential character (∂) creates a delightful ornament that can help to guide the eye through content.
Stagger & Swagger
What about layout? How can we use typography to inform how our content is displayed?
Let’s take a typeface like Assembler. We might use this for a design that needs to feel uneasy or uncomfortable. In design terms, that might translate into using irregular shapes and asymmetry. Using the proportional distances and degrees from the perpendiculars, we could easily create a multi-column layout that jives with the general tone. And for all you skeptics that don’t think a layout like this is doable on the web, stranger things have happened.
Background texture generously offered by Bittbox.
Overall Design Direction
Finally, your typography could impact the entire look of the site, from the navigation to the interaction and everything in between. Check out how the (now-defunct) Nike Free site’s typography echoes the product itself, and in turn influences the navigation.
Find Your Type
With thousands of fonts to choose from, the possibilities are ridiculously open. From angles to radii to color to weight, you’ve got endless fodder before you. Great type designers spent countless hours slaving over these detailed letterforms; take advantage of it! Don’t feel like you have to limit yourself to the same old Helvetica and wet floors… unless your design calls for it.
Happy hunting! |
2009 |
Dan Mall |
danmall |
2009-12-07T00:00:00+00:00 |
https://24ways.org/2009/type-inspired-interfaces/ |
design |
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 |
210 |
Stop Leaving Animation to the Last Minute |
Our design process relies heavily on static mockups as deliverables and this makes it harder than it needs to be to incorporate UI animation in our designs. Talking through animation ideas and dancing out the details of those ideas can be fun; but it’s not always enough to really evaluate or invest in animated design solutions.
By including deliverables that encourage discussing animation throughout your design process, you can set yourself (and your team) up for creating meaningful UI animations that feel just as much a part of the design as your colour palette and typeface. You can get out of that “running out of time to add in the animation” trap by deliberately including animation in the early phases of your design process. This will give you both the space to treat animation as a design tool, and the room to iterate on UI animation ideas to come up with higher quality solutions. Two deliverables that can be especially useful for this are motion comps and animated interactive prototypes.
Motion comps - an animation deliverable
Motion comps (also called animatics or motion mock-ups) are usually video representation of UI animations. They are used to explore the details of how a particular animation might play out. And they’re most often made with timeline-based tools like Adobe After Effects, Adobe Animate, or Tumult Hype.
The most useful things about motion comps is how they allow designers and developers to share the work of creating animations. (Instead of pushing all the responsibility of animation on one group or the other.) For example, imagine you’re working on a design that has a content panel that can either be open or closed. You might create a mockup like the one below including the two different views: the closed state and the open state. If you’re working with only static deliverables, these two artboards might be exactly what you handoff to developers along with the instruction to animate between the two.
On the surface that seems pretty straight forward, but even with this relatively simple transition there’s a lot that those two artboards don’t address. There are seven things that change between the closed state and the open state. That’s seven things the developer building this out has to figure out how to move in and out of view, when, and in what order. And all of that is even before starting to write the code to make it work.
By providing only static comps, all the logic of the animation falls on the developer. This might go ok if she has the bandwidth and animation knowledge, but that’s making an awful lot of assumptions.
Instead, if you included a motion mock up like this with your static mock ups, you could share the work of figuring out the logic of the animation between design and development. Designers could work out the logic of the animation in the motion comp, exploring which items move at which times and in which order to create the opening and closing transitions.
The motion comp can also be used to iterate on different possible animation approaches before any production code has to be committed too. Sharing the work and giving yourself time to explore animation ideas before you’re backed up again the deadline will lead to happier teammates and better design solutions.
When to use motion comps
I’m not a fan of making more deliverables just for the sake of having more things to make, so I find it helps to narrow down what question I’m trying answer before choosing which sort of deliverable to make to investigate.
Motion comps can be most helpful for answering questions like:
Exactly how should this animation look?
Which items should move? Where? And when?
Do the animation qualities reflect our brand or our voice and tone?
One of the added bonuses of creating motion comps to answer these questions is that you’ll have a concrete thing to bring to design critiques or reviews to get others’ input on them as well.
Using motion comps as handoff
Motion comps are often used to handoff animation ideas from design to development. They can be super useful for this, but they’re even more useful when you include the details of the motion specs with them. (It’s difficult, if not impossible, to glean these details from playing back a video.)
More specifically, you’ll want to include:
Durations and the properties animated for each animation
Easing curve values or spring values used
Delay values and repeat counts
In many cases you’ll have to collect these details up manually. But this isn’t necessarily something that that will take a lot of time. If you take note of them as you’re creating the motion comp, chances are most of these details will already be top of mind. (Also, if you use After Effects for your motion comps, the Inspector Spacetime plugin might be helpful for this task.)
Animated prototypes - an interactive deliverable
Making prototypes isn’t a new idea for web work by any stretch, but creating prototypes that include animation – or even creating prototypes specifically to investigate potential animation solutions – can go a long way towards having higher quality animations in your final product.
Interactive prototypes are web or app-based, or displayed in a particular tool’s preview window to create a useable version of interactions that might end up in the end product. They’re often made with prototyping apps like Principle, Framer, or coded up in HTML, CSS and JS directly like the example below.
See the Pen Prototype example by Val Head (@valhead) on CodePen.
The biggest different between motion comps and animated prototypes is the interactivity. Prototypes can reposed to taps, drags or gestures, while motion comps can only play back in a linear fashion. Generally speaking, this makes prototypes a bit more of an effort to create, but they can also help you solve different problems. The interactive nature of prototypes can also make them useful for user testing to further evaluate potential solutions.
When to use prototypes
When it comes to testing out animation ideas, animated prototypes can be especially helpful in answering questions like these:
How will this interaction feel to use? (Interactive animations often have different timing needs than animations that are passively viewed.)
What will the animation be like with real data or real content?
Does this animation fit the context of the task at hand?
Prototypes can be used to investigate the same questions that motion comps do if you’re comfortable working in code or your prototyping tool of choice has capabilities to address high fidelity animation details. There are so many different prototyping tools out there at the moment, you’re sure to be able to find one that fits your needs.
As a quick side note: If you’re worried that your coding skills might not be up to par to prototype in code, know that prototype code doesn’t have to be production quality code. Animated prototypes’ main concern is working out the animation details. Once you’ve arrived at a combination of animations that works, the animation specifics can be extracted or the prototype can be refactored for production.
Motion comp or prototype?
Both motion comps and prototypes can be extremely useful in the design process and you can use whichever one (or ones) that best fits your team’s style. The key thing that both offer is a way to make animation ideas visible and sharable. When you and your teammate are both looking at the same deliverable, you can be confident you’re talking about the same thing and discuss its pros and cons more easily than just describing the idea verbally.
Motion comps tend to be more useful earlier in the design process when you want to focus on the motion without worrying about the underlying structure or code yet. Motion comps also be great when you want to try something completely new. Some folks prefer motion comps because the tools for making them feel more familiar to them which means they can work faster.
Prototypes are most useful for animations that rely heavily on interaction. (Getting the timing right for interactions can be tough without the interaction part sometimes.) Prototypes can also be helpful to investigate and optimize performance if that’s a specific concern.
Give them a try
Whichever deliverables you choose to highlight your animation decisions, including them in your design reviews, critiques, or other design discussions will help you make better UI animation choices. More discussion around UI animation ideas during the design phase means greater buy-in, more room for iteration, and higher quality UI animations in your designs. Why not give them a try for your next project? |
2017 |
Val Head |
valhead |
2017-12-08T00:00:00+00:00 |
https://24ways.org/2017/stop-leaving-animation-to-the-last-minute/ |
design |
217 |
Beyond Web Mechanics – Creating Meaningful Web Design |
It was just over three years ago when I embarked on becoming a web designer, and the first opinion piece about the state of web design I came across was a conference talk by Elliot Jay Stocks called ‘Destroy the Web 2.0 Look’. Elliot’s presentation was a call to arms, a plea to web designers the world over to stop the endless reproductions of the so called ‘Web 2.0 look’.
Three and a half years on from Elliot’s talk, what has changed? Well, from an aesthetic standpoint, not a whole lot. The Web 2.0 look has evolved, but it’s still with us and much of the web remains filled with cookie cutter websites that bear a striking resemblance to one another. This wouldn’t matter so much if these websites were selling comparable services or products, but they’re not. They look similar, they follow the same web design trends; their aesthetic style sends out a very similar message, yet they’re selling completely different services or products. How can you be communicating effectively with your users when your online book store is visually indistinguishable from an online cosmetic store? This just doesn’t make sense.
I don’t want to belittle the current version of the Web 2.0 look for the sake of it. I want to talk about the opportunity we have as web designers to create more meaningful experiences for the people using our websites. Using design wisely gives us the ability to communicate messages, ideas and attitudes that our users will understand and connect with.
Being human
As human beings we respond emotionally to everything around us – people, objects, posters, packaging or websites. We also respond in different ways to different kinds of aesthetic design and style. We care about style and aesthetics deeply, whether we realise it or not. Aesthetic design has the power to attract or repel. We often make decisions based purely on aesthetics and style – and don’t retailers the world over know it! We connect attitudes and strongly held beliefs to style. Individuals will proudly associate themselves with a certain style or aesthetic because it’s an expression of who they are. You know that old phrase, ‘Don’t judge a book by its cover’? Well, the problem is that people do, so it’s important we get the cover right.
Much is made of how to structure web pages, how to create a logical information hierarchy, how to use layout and typography to clearly communicate with your users. It’s important, however, not to mistake clarity of information or legibility with getting your message across. Few users actually read websites word by word: it’s far more likely they’ll just scan the page. If the page is copy-heavy and nothing grabs their attention, they may well just move on. This is why it’s so important to create a visual experience that actually means something to the user.
Meaningful design
When we view a poster or website, we make split-second assessments and judgements of what is in front of us. Our first impressions of what a website does or who it is aimed at are provoked by the style and aesthetic of the website. For example, with clever use of colour, typography, graphic design and imagery we can communicate to users that an organisation is friendly, edgy, compassionate, fun or environmentally conscious.
Using a certain aesthetic we can convey the personality of that organisation, target age ranges, different sexes or cultural groups, communicate brand attributes, and more. We can make our users feel like they’re part of something and, perhaps even more importantly, we can make new users want to be a part of something. And we can achieve all this before the user has read a single word.
By establishing a website’s aesthetic and creating a meaningful visual language, a design is no longer just a random collection of pretty gradients that have been plucked out of thin air. There can be a logic behind the design decisions we make. So, before you slap another generic piece of ribbon or an ultra shiny icon into the top-left corner of your website, think about why you are doing it. If you can’t come up with a reason better than “I saw it on another website”, it’s probably a poor application of style.
Design and style
There are a number of reasons why the web suffers from a lack meaningful design. Firstly, there are too many preconceptions of what a website should look like. It’s too easy for designers to borrow styles from other websites, thereby limiting the range of website designs we see on the web. Secondly, many web designers think of aesthetic design as of secondary importance, which shouldn’t be the case. Designing websites that are accessible and easy to use is, of course, very important but this is the very least a web designer should be delivering. Easy to use websites should come as standard – it’s equally important to create meaningful, compelling and beautiful experiences for everyone who uses our websites. The aesthetics of your site are part of the design, and to ignore this and play down the role of aesthetic design is just a wasted opportunity.
No compromise necessary
Easy to use, accessible websites and beautiful, meaningful aesthetics are not mutually exclusive. The key is to apply style and aesthetic design appropriately. We need to think about who and what we’re designing for and ask ourselves why we’re applying a certain kind of aesthetic style to our design. If you do this, there’s no reason why effective, functional design should come at the expense of jaw-dropping, meaningful aesthetics.
Web designers need to understand the differences between functional design and aesthetic design but, even more importantly, they need to know how to make them work together. It’s combining these elements of design successfully that makes for the best web design in the world. |
2010 |
Mike Kus |
mikekus |
2010-12-05T00:00:00+00:00 |
https://24ways.org/2010/beyond-web-mechanics-creating-meaningful-web-design/ |
design |
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 |
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 |
277 |
Raising the Bar on Mobile |
One of the primary challenges of designing for mobile devices is that screen real estate is often in limited supply. Through the advocacy of Luke W and others, we’ve drawn comfort from the idea that this constraint ends up benefiting users and designers alike, from obvious advantages like portability and reach, to influencing our content strategy decisions through focus and restraint. But that doesn’t mean we shouldn’t take advantage of every last pixel of that screen we can snag!
As anyone who has designed a website for use on a smartphone can attest, there’s an awful lot of space on mobile screens dedicated to browser functions that would be better off toggled out of view. Unfortunately, the visibility of some of these elements is beyond our control, such as the buttons fixed to the bottom of the viewport in iOS’s Safari and the WebOS browser. However, in many devices, the address bar at the top can be manually hidden, and its absence frees up enough pixel room for a large, impactful heading, a critical piece of navigation, or even just a little more white space to air things out.
So, as my humble contribution to this most festive of web publications, today I’ll dig into the approach I used to hide the address bar in a browser-agnostic fashion for sites like BostonGlobe.com, and the jQuery Mobile framework.
Surveying the land
First, let’s assess the chromes of some popular, current mobile browsers. For example purposes, the following screen-captures feature the homepage of the Boston Globe site, without any address-bar-hiding logic in place.
Note: these captures are just mockups – actual experience on these platforms may vary.
On the left is iOS5’s Safari (running on iPhone), and on the right is Windows Phone 7 (pre-Mango).
BlackBerry 7 (left), and Android 2.3 (right).
WebOS (left), Opera Mini (middle), and Opera Mobile (right).
Some browsers, such the default browsers on WebOS and BlackBerry 5, hide the bar automatically without any developer intervention, but many of them don’t. Of these, we can only manually hide the address bar on iOS Safari and Android (according to Opera Web Opener, Mike Taylor, some discussion is underway for support in Opera Mini and Mobile as well, which would be great!). This is unfortunate, but iOS and Android are incredibly popular, so let’s direct our focus there.
Great API, or greatest API?
As it turns out, iOS and Android not only allow you to hide the address bar, they use the same JavaScript method to do so, too (this shouldn’t be surprising, given that they are both WebKit browsers, but nothing expected happens in mobile). However, the method they use is not exactly intuitive. You might set out looking for a JavaScript API dedicated to this purpose, like, say, window.toolbar.hide(), but alas, to hide the address bar you need to use the window.scrollTo method!
window.scrollTo(0, 0);
The scrollTo method is not new, it’s just this particular use of it that is. For the uninitiated, scrollTo is designed to scroll a document to a particular set of coordinates, assuming the document is large enough to scroll to that spot. The method accepts two arguments: a left coordinate; and a top coordinate. It’s both simple and supported well pretty much everywhere. In iOS and Android, these coordinates are calculated from the top of the browser’s viewport, just below the address bar (interestingly, it seems that some platforms like BlackBerry 6 treat the top of the browser chrome as 0 instead, meaning the page content is closer to 20px from the top).
Anyway, by passing the coordinates 0, 0 to the scrollTo method, the browser will jump to the top of the page and pull the address bar out of view! Of course, if a quick call to scrollTo was all we need to do to hide the address bar in iOS and Android, this article would be pretty short, and nothing new. Unfortunately, the first issue we need to deal with is that this method alone will not usually do the trick: it must be called after the page has finished loading.
The browser gives us a load event for just that purpose, so we’ll wrap our scrollTo method in it and continue on our merry way! We’ll use the standard, addEventListener method to bind the the load event, passing arguments for event name load, and a callback function to execute when the event is triggered.
window.addEventListener("load",function() {
window.scrollTo(0, 0);
});
For the sake of preventing errors in those using browsers that don’t support addEventListener, such as Internet Explorer 8 and under, let’s make sure that method exists before we use it:
if( window.addEventListener ){
window.addEventListener("load",function() {
window.scrollTo(0, 0);
});
}
Now we’re getting somewhere, but we must also call the method after the load event’s default behavior has been applied. For this, we can use the setTimeout method, delaying its execution to after the load event has run its course.
if( window.addEventListener ){
window.addEventListener("load",function() {
setTimeout(function(){
window.scrollTo(0, 0);
}, 0);
});
}
Sweet sugar of Christmas! Hit this demo in iOS and watch that address bar drift up and away!
Not so fast…
We’ve got a little problem: the approach above does work in iOS but, in some cases, it works a little too well. In the process of applying this behavior, we’ve broken one of the primary tenets of responsible web development: don’t break the browser’s default behaviour. This usability rule of thumb is often violated by developers with even the best of intentions, from breaking the browser’s back button through unrecorded Ajax page refreshes, to fancy momentum touch scrolling scripts that can wreak havoc in all but the most sophisticated of devices. In this case, we’ve prevented the browser’s native support of deep-linking to sections of a page (a hash identifier in the URL matching a page element’s id attribute, for example, http://example.com#contact) from working properly, because our script always scrolls to the top.
To avoid this collision, we’ll need to detect whether a deep link, or hash, is present in the URL before applying our logic. We can do this by ensuring that the location.hash property is falsey:
if( !window.location.hash && window.addEventListener ){
window.addEventListener( "load",function() {
setTimeout(function(){
window.scrollTo(0, 0);
}, 0);
});
}
Still works great! And a quick test using a hash-based URL confirms that our script will not execute when a deep anchor is in play. Now iOS is looking sharp, and we’ve added our feature defensively to avoid conflicts.
Now, on to Android…
Wait. You didn’t expect that we could write code for one browser and be finished, right? Of course you didn’t. I mentioned earlier that Android uses the same method for getting rid of the scrollbar, but I left out the fact that the arguments it prefers vary slightly, but significantly, from iOS. Bah!
Differering from the earlier logic from iOS, to remove the address bar on Android’s default browser, you need to pass a Y coordinate of 1 instead of 0. Aside from being just plain odd, this is particularly unfortunate because to any other browser on the planet, 1px is a very real, however small, distance from the top of the page!
window.scrollTo( 0, 1 );
Looks like we’re going to need a fork…
R UA Android?
At this point, some developers might decide to simply not support this feature in Android, and more determined devs might decide that a quick check of the User Agent string would be a reliable way to determine the browser and tweak the scroll value accordingly. Neither of those decisions would be tragic, but in the spirit of cross-browser and future-friendly development, I’ll propose an alternative.
By this point, it should be clear that neither of the implementations above offer a particularly intuitive way to hide an address bar. As such, one might be skeptical that these approaches will stick around very long in their present state in either browser. Perhaps at some point, Android will decide to use 0 like iOS, making our lives a little easier, or maybe some new browser will decide to model their address bar hiding method after one of these implementations. In any case, detecting the User Agent only allows us to apply logic based on the known present, and in the world of mobile, let’s face it, the present is already the past.
Writing a check
In this next step of today’s technique, we’ll apply some logic to quickly determine the behavior model of the browser we’re using, then capitalize on that model – without caring which browser it happens to come from – by applying the appropriate scroll distance.
To do this, we’ll rely on a fortunate side effect of Android’s implementation, which is when you programatically scroll the page to 1 using scrollTo, Android will report that it’s still at 0 because oddly enough, it is! Of course, any other browser in this situation will report a scroll distance of 1. Thus, by scrolling the page to 1, then asking the browser its scroll distance, we can use this artifact of their wacky implementation to our advantage and scroll to the location that makes sense for the browser in play.
Getting the scroll distance
To pull off our test, we’ll need to ask the browser for its current scroll distance. The methods for getting scroll distance are not entirely standardized across popular browsers, so we’ll need to use some cross-browser logic. The following scroll distance function is similar to what you’d find in a library like jQuery. It checks the few common ways of getting scroll distance before eventually falling back to 0 for safety’s sake (that said, I’m unaware of any browsers that won’t return a numeric value from one of the first three properties).
// scrollTop getter
function getScrollTop(){
return scrollTop = window.pageYOffset ||
document.compatMode === "CSS1Compat" && document.documentElement.scrollTop ||
document.body.scrollTop || 0;
}
In order to execute that code above, the body object (referenced here as document.body) will need to be defined already, or we’ll risk an error. To determine that it’s defined, we can run a quick timer to execute code as soon as that object is defined and ready for use.
var bodycheck = setInterval(function(){
if( document.body ){
clearInterval( bodycheck );
//more logic can go here!!
}
}, 15 );
Above, we’ve defined a 15 millisecond interval called bodycheck that checks if document.body is defined and, if so, clears itself of running again. Within that if statement, we can extend our logic further to run other code, such as our check for the scroll distance, defined via the variable scrollTop below:
var scrollTop,
bodycheck = setInterval(function(){
if( document.body ){
clearInterval( bodycheck );
scrollTop = getScrollTop();
}
}, 15 );
With this working, we can immediately scroll to 1, then check the scroll distance when the body is defined. If the distance reports 1, we’re likely in a non-Android browser, so we’ll scroll back to 0 and clean up our mess.
window.scrollTo( 0, 1 );
var scrollTop,
bodycheck = setInterval(function(){
if( document.body ){
clearInterval( bodycheck );
scrollTop = getScrollTop();
window.scrollTo( 0, scrollTop === 1 ? 0 : 1 );
}
}, 15 );
Cashing in
All of the pieces are written now, so all we need to do is combine them with our previous logic for scrolling when the window is loaded, and we’ll have a cross-browser solution of which John Resig would be proud. Here’s our combined code snippet, with some formatting updates rolled in as well:
(function( win ){
var doc = win.document;
// If there’s a hash, or addEventListener is undefined, stop here
if( !location.hash && win.addEventListener ){
//scroll to 1
window.scrollTo( 0, 1 );
var scrollTop = 1,
getScrollTop = function(){
return win.pageYOffset || doc.compatMode = "CSS1Compat" && doc.documentElement.scrollTop || doc.body.scrollTop || 0;
},
//reset to 0 on bodyready, if needed
bodycheck = setInterval(function(){
if( doc.body ){
clearInterval( bodycheck );
scrollTop = getScrollTop();
win.scrollTo( 0, scrollTop = 1 ? 0 : 1 );
}
}, 15 );
win.addEventListener( “load”, function(){
setTimeout(function(){
//reset to hide addr bar at onload
win.scrollTo( 0, scrollTop === 1 ? 0 : 1 );
}, 0);
} );
}
})( this );
View code example
And with that, we’ve got a bunch more room to play with on both iOS and Android.
Break out the eggnog
…because we’re not done yet! In the spirit of making our script act more defensively, there’s still another use case to consider. It was essential that we used the window’s load event to trigger our scripting, but on pages with a lot of content, its use can come at a cost. Often, a user will begin interacting with a page, scrolling down as they read, before the load event has fired. In those situations, our script will jump the user back to the top of the page, resulting in a jarring experience.
To prevent this problem from occurring, we’ll need to ensure that the page has not been scrolled beyond a certain amount. We can add a simple check using our getScrollTop function again, this time ensuring that its value is not greater than 20 pixels or so, accounting for a small tolerance.
if( getScrollTop() < 20 ){
//reset to hide addr bar at onload
window.scrollTo( 0, scrollTop === 1 ? 0 : 1 );
}
And with that, we’re pretty well protected! Here’s a final demo.
The completed script can be found on Github (full source: https://gist.github.com/1183357 ). It’s MIT licensed. Feel free to use it anywhere or any way you’d like!
Your thoughts?
I hope this article provides you with a browser-agnostic approach to hiding the address bar that you can use in your own projects today. Perhaps alternatively, the complications involved in this approach convinced you that doing this well is more trouble than it’s worth and, depending on the use case, that could be a fair decision. But at the very least, I hope this demonstrates that there’s a lot of work involved in pulling off this small task in only two major platforms, and that there’s a real need for standardization in this area.
Feel free to leave a comment or criticism and I’ll do my best to answer in a timely fashion.
Thanks, everyone!
Some parting notes
I scream, you scream…
At the time of writing, I was not able to test this method on the latest Android 4.0 (Ice Cream Sandwich) build. According to Sencha Touch’s browser scorecard, the browser in 4.0 may have a different way of managing the address bar, so I’ll post in the comments once I get a chance to dig into it further.
Short pages get no love
Today’s technique only works when the page is as tall, or taller than, the device’s available screen height, so that the address bar may be scrolled out of view. On a short page, you might work around this issue by applying a minimum height to the body element ( body { min-height: 460px; } ), but given the variety of screen sizes out there, not to mention changes in orientation, it’s tough to find a value that makes much sense (unless you manipulate it with JavaScript). |
2011 |
Scott Jehl |
scottjehl |
2011-12-20T00:00:00+00:00 |
https://24ways.org/2011/raising-the-bar-on-mobile/ |
design |
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 |
285 |
Composing the New Canon: Music, Harmony, Proportion |
Ohne Musik wäre das Leben ein Irrtum
—Friedrich NIETZSCHE, Götzen-Dämmerung, Sprüche und Pfeile 33, 1889
Somehow, music is hardcoded in human beings. It is something we understand and respond to without prior knowledge. Music exercises the emotions and our imaginative reflex, not just our hearing. It behaves so much like our emotions that music can seem to symbolize them, to bear them from one person to another. Not surprisingly, it conjures memories: the word music derives from Greek μουσική (mousike), art of the Muses, whose mythological mother was Mnemosyne, memory. But it can also summon up the blood, console the bereaved, inspire fanaticism, bolster governments and dissenters alike, help us learn, and make web designers dance. And what would Christmas be without music?
Music moves us, often in ways we can’t explain. By some kind of alchemy, music frees us from the elaborate nuisance and inadequacy of words. Across the world and throughout recorded history – and no doubt well before that – people have listened and made (and made out to) music.
[I]t appears probable that the progenitors of man, either the males or females or both sexes, before acquiring the power of expressing their mutual love in articulate language, endeavoured to charm each other with musical notes and rhythm.
—Charles DARWIN, The Descent of Man, and Selection in Relation to Sex, 1871
It’s so integral to humankind, we’ve sent it into space as a totem for who we are. (Who knows? It might be important.) Music is essential, a universal compulsion; as Nietzsche wrote, without music life would be a mistake.
Music, design and web design
There are some obvious and notable similarities between music and visual design. Both can convey mood and evoke emotion but, even under close scrutiny, how they do that remains to a great extent mysterious. Each has formal qualities or parts that can be abstracted, analysed and discussed, often using the same terminology: composition, harmony, rhythm, repetition, form, theme; even colour, texture and tone.
A possible reason for these shared aspects is that both visual design and music are means to connect with people in deep and lasting ways. Furthermore, I believe the connections to be made can complement direct emotional appeal. Certain aesthetic qualities in music work on an unconscious and, it could be argued, universal level. Using musical principles in our designs, then, can help provide the connectedness between content, device and user that we now seek as web designers.
Yet, when we talk about music and web design, the conversation is almost always about the music designers listen to while working, a theme finding its apotheosis in Designers.MX. Sometimes, articles in that dreary list format seek inspiration from music industry websites. There’s even a service offering pre-templated web designs for bands, and at least one book surveyed the landscape back in 2006. Occasionally, discussions broaden somewhat into whether and how different kinds of music can inspire and influence the design work we produce.
Such enquiries, it seems to me, are beside the point. Do I really design differently when I listen to Bach rather than Bacharach? Will the barely restrained energy of Count Basie’s The Kid from Red Bank mean I choose a lively colour palette, and rural, autumnal shades when inspired by Fleet Foxes? Mahler means a thirteen-column layout? Gillian Welch leads to distressed black and white photography? While reflecting the importance we place in music and how it seems to help us in our work, surveys on musical taste and lists of favourite artists fail to recognize that some of the fundamental aesthetic characteristics of music can be adapted and incorporated into modern web design.
Antiphonal geometry
Over recent years, web designers have embraced grid systems as powerful tools to help create good-looking and intuitive user experiences. With the advent of responsive design, these grids and their contents must adapt to the different screen sizes and properties of all kinds of user devices. Finding and using grid values that can scale well and retain or enhance their proportions and relationships while making the user experience meaningful in several different contexts is more important than ever.
In print, this challenge has always started with the dimensions and proportions of the page. Content can thereby be made to belong inside the page and be bound to it. And music has been used for centuries to further this aim. As Robert Bringhurst says in The Elements of Typographical Style:
Indeed, one of the simplest of all systems of page proportions is based on the familiar intervals of the diatonic scale. Pages that embody these basic musical proportions have been in common use in Europe for more than a thousand years.
Very well. But while he goes on to list (from the full chromatic scale, rather than just diatonic) the proportions and the musical intervals they’re based on, Bringhurst fails to mention what they’re ratios of or their potential effects. Shame. In his favour, however, he later touches on how proportions in print might be considered to work:
The page is a piece of paper. It is also a visible and tangible proportion, silently sounding the thoroughbass of the book. On it lies the textblock, which must answer to the page. The two together – page and textblock – produce an antiphonal geometry. That geometry alone can bond the reader to the book. Or conversely, it can put the reader to sleep, or put the reader’s nerves on edge, or drive the reader away.
So what does Bringhurst mean by antiphonal geometry, a phrase that marries the musical to the spatial? By stating that the textblock “must answer to the page”, the implication is that the relationship between the proportions of the page and the shape of the textblock printed on it embodies a spatial (geometrical) call-and-response (antiphony) that can be appealing or not.
Boulton’s new canon
But, as Mark Boulton has pointed out, on the web “there are no edges. There are no ‘pages’. We’ve made them up.” So, what is to be done? In January 2011 at the New Adventures in Web Design conference, Boulton presented his vision of a new canon of web design, a set of principles to guide us as we design the web. There are three overlapping tenets:
design from the content out
create connectedness between the different content elements
bind the content to the web device
Rather than design from the edges in, we need to design layout systems from the content out. To this end, Boulton asserts that grid system design should begin with a constraint, and he suggests we use the size of a fixed content element, such as an advertising unit or image, as a starting point for online grid calculations. Khoi Vinh advocates the same approach in his book, Ordering Disorder: Grid Principles for Web Design.
Boulton’s second and third tenets, however, are more complex and overlap significantly with each other. Connecting the different parts of the content and binding the content to the device share many characteristics and solutions:
adopting ems and percentages as units of size for layout elements
altering text size, line length and line height for different viewport dimensions
providing higher resolution images for devices with greater pixel densities
fluid layout grids, flexible images and responsive design
All can help relate the presentation of the content to its delivery in a certain context.
But how do we determine the relationship between one element of a layout and another? How can we avoid making arbitrary decisions about the relative sizes of parts of our designs? What can we use to connect the parts of our design to one another, and how can we bind the presentation of the content to the user’s device?
Tim Brown’s application of modular typographic scales hints at an answer. In the very useful tool he created for calculating such scales, Brown includes two musical ratios: the perfect fifth (2:3); and the perfect fourth (3:4). Why? Where do they come from? And what do they mean?
Harmonies musical and visual
Fundamental to music are rhythm and harmony.
As any drummer will tell you, without rhythm there is no music. Even when there’s no regular beat, any tune follows a rhythm, however irregular, simply because a change of note is a point of change in the music. Although rhythm, timing and pacing are all relevant to interaction design, right now it’s harmony we’re interested in.
Sometimes harmony is called the vertical aspect of music, and melody the horizontal. But this conceit overlooks the fact that harmony is both vertical and horizontal. A single melodic line, as it is played, implies various sets of harmonies on which it is grounded, whether or not those harmonies are played. So, harmony doesn’t just sit vertically beneath the horizontal melody, but moves horizontally as well, through harmonic progression.
To stretch this arrangement pixel-thin, we could argue that in onscreen design melody is the content, and the layout and arrangement of the content is the harmony. We sometimes say a design is harmonious when the interplay of different elements of a design is pleasing or balanced or in proportion, and the content (the melody) is set off or conveyed well by or appropriate to the design.
We seem to know instinctively whether a layout is harmonious…
In the design of The Great Discontent, the relationships between different elements combine to form a balanced whole.
…or not.
There’s no harmony in the Department for Education’s website because the different parts of the content don’t feel related to one another.
What is it that makes one design harmonious and another dissonant? It’s not just whether things line up, though that’s a start. I believe there are much deeper aesthetic forces at work, forces we can tap into in our onscreen designs. Now, I’m not going start a difficult discussion about aesthetics. For our purposes, we just need to know that it’s the branch of philosophy dealing with the nature of beauty, and the creation and perception of beauty. And among the key components in the perception of beauty are harmony and proportion. These have been part of traditional western aesthetics since Plato (about 2,500 years).
One of the ways we appreciate the beauty of music is through the harmonic intervals we hear. A musical interval is a combination of two notes and it describes the distance between the two pitches. For example, the distance between C and the G above it (if we take C as the tonic or root) is called a perfect fifth.
Left: C to G, a perfect fifth. Right: C and G, not a perfect fifth.
And, to get superficially scientific for a moment, each musical interval can be expressed as a ratio of the wavelength frequencies of the notes; for our perfect fifth, with every two wavelengths of C, there are three of G. And what is a ratio, if not a proportion of one thing to another?
So, simple musical harmony (using what’s known as just intonation1) affords us a set of proportions, expressed as ratios. Where better to apply these ideas of harmony and proportion from music in web design, than grid systems?
A digression: whither φ?
Quite often in our discussions of pure design and aesthetics, we mention the golden ratio and regurgitate the same justifications for its use: roots in antiquity; embodied in classical and Renaissance architecture and art; occurrence in nature; the New Twitter, and so forth (oh, really?).
Yet the ratios of musical intervals from just intonation are equally venerable and much more widespread: described by Pythagorus; employed in Palladian architecture, and printing, books and art from the Renaissance onwards; in modern times, film and television dimensions; standard international paper sizes (ISO 216, the A and B series); and, again and again, screen dimensions – chances are that screen you’re probably looking at right now has the proportions 2:3 (iPhone and iPod Touch), 3:4 (iPad and Kindle), 3:5 (many smartphones), 5:8 or 16:9 (many widescreen monitors), all ratios of musical intervals.
Back to our theme…
Musical interval ratios
Let’s take a look at most of the ratios within a couple of octaves and crunch some numbers to generate some percentages and other values that we can use in our designs. First, the intervals and their ratios in just intonation and expressed as ratios of one:
Name
Interval in C
Ratio
Ratio (1:x)
unison
C→C
1:1
1:1
minor second
C→D♭
15:16
1:1.067
major second
C→D
8:9
1:1.125
minor third
C→E♭
5:6
1:1.2
major third
C→E
4:5
1:1.25
perfect fourth
C→F
3:4
1:1.333
augmented fourth
or diminished fifth
C→F♯/G♭
1:√2
1:1.414
perfect fifth
C→G
2:3
1:1.5
minor sixth
C→A♭
5:8
1:1.6
major sixth
C→A
3:5
1:1.667
minor seventh
C→B♭
9:16
1:1.778
major seventh
C→B
8:15
1:1.875
octave
C→C↑
1:2
1:2
major tenth
C→E↑
2:5
1:2.5
major eleventh
C→F↑
3:8
1:2.667
major twelfth
C→G↑
1:3
1:3
double octave
C→C↑
1:4
1:4
Name
Interval in C
Ratio
Ratio (1:x)
And now as percentages, of both the larger and smaller values in the ratios:
Name
Ratio
% of larger value
% of smaller value
unison
1:1
100%
100%
minor second
15:16
93.75%
106.667%
major second
8:9
88.889%
112.5%
minor third
5:6
83.333%
120%
major third
4:5
80%
125%
perfect fourth
3:4
75%
133.333%
augmented fourth
or diminished fifth
1:√2
70.711%
141.421%
perfect fifth
2:3
66.667%
150%
minor sixth
5:8
62.5%
160%
major sixth
3:5
60%
166.667%
minor seventh
9:16
56.25%
177.778%
major seventh
8:15
53.333%
187.5%
octave
1:2
50%
200%
major tenth
2:5
40%
250%
major eleventh
3:8
37.5%
266.667%
major twelfth
1:3
33.333%
300%
double octave
1:4
25%
400%
Name
Ratio
% of larger value
% of smaller value
As you can see, the simple musical intervals are expressed as ratios of small whole numbers (integers). We can then normalize them as ratios of one, as well as derive percentage values, both in terms of the smaller value to the larger, and vice versa. These are the numbers we can incorporate into our designs. If you’ve ever written something like body { font: 100%/1.5 "Museo Sans", Helvetica, sans-serif; } in your CSS, you’re already using a musical ratio: the perfect fifth.
Modular scales allow us to generate a set of numbers based on a musical interval that can be used for all kinds of typographic and layout decisions to create harmony in a visual design for the web. As Tim Brown said at the 2010 Build conference:
I think that from that most atomic unit – type – whole experiences can resonate, whole experiences can be harmonious. And whole experiences can have a purpose suited to our design intentions.
Once more, with feeling: connectedness
As well as modular scales, there are other methods of incorporating musical interval ratios into our work. Setting the ratio of font size to line height in CSS is one such example. We could also create a typographic hierarchy using the same principle and combining several ratios that we know harmonize well musically in a chord:
body { font-size: 75%; } /* =12px = base size or tonic */
h1 { font-size: 32px; font-size: 2.667rem; }
/* =32px = 3:8 = major eleventh (C→F↑) */
h2 { font-size: 24px; font-size: 2rem; }
/* =24px = 1:2 = octave (C→C↑) */
h3 { font-size: 20px; font-size: 1.667rem; }
/* =20px = 3:5 = major sixth (C→A) */
figcaption, small { font-size: 9px; font-size : 0.75rem }
/* =9px = 3:4 = perfect fourth (C→F) */
Whoa! Hold your reindeer, Santa! How can we know what interval combinations work well together to form chords? Well, I’m a classically trained musician, so perhaps I have an advantage. To avoid a long, technically complex digression into musical harmony, here are a few basic combinations of intervals that are harmonious in one way or another:
unison; major third; perfect fifth; octave
unison; perfect fourth; major sixth; octave
unison; minor third; minor sixth; octave
unison; minor third; diminished fifth; major sixth; octave
This isn’t to say that other combinations can’t be used to interesting effect and particular purpose – they surely can – but I have to make sure there’s something left for you to experiment with in the wee small hours over the holiday. Bear in mind, though, were I to play you two notes from the same scale to form a minor second, for example, you’d probably say it was dissonant and maybe that quality of the 15:16 ratio would be translated to the design.
In the typographic hierarchy above, you’ll notice I used an interval in the higher octave, which affords a broader range of ratios while retaining the harmony. Thus, a perfect fifth (2:3) becomes a major twelfth (1:3), or a major sixth (3:5) becomes a major thirteenth (3:10).
The harmonic ratios can obviously be used as proportions for layout as well, in several different ways:
image width and height (for example, 450×800px = 9:16 = minor seventh)
main content to page width (67%:100% = 2:3 = perfect fifth)
page width to viewport width (80%:100% = 4:5 = major third)
One great benefit of using such ratios in web design work is that they can be applied in responsive web design. Proportional values, based on percentages or equivalent em units, will scale with changing viewports, so your layout and image proportions can be maintained or deliberately changed, as we’re about to find out, across devices.
Small speakers, tall speakers: binding to the device
The musical interval ratios also provide an opportunity, not only to create connectedness between the parts of a layout, but to bind the content to a device – that elusive antiphonal geometry. Just as a textblock and page resonate together, so too can web content and the screen. Earlier, I mentioned that several common screen aspect ratios match musical interval ratios. It would seem, then, that we have a set of proportions that we can use in different ways to establish and retain a sense of harmony that can be based on and change with those contexts. Using musical interval ratios, we can bind the display of our content to the device it’s displayed on.
If you haven’t met already, let me introduce you to the device-aspect-ratio property of CSS media queries.
@media only screen and (device-aspect-ratio: 3/4) { }
@media only screen and (device-aspect-ratio: 480/640) { }
@media only screen and (device-aspect-ratio: 600/800) { }
@media only screen and (device-aspect-ratio: 768/1024) { }
Regardless of the precise pixel values, each of these media queries would apply to devices whose display area has an aspect ratio of 3:4. It works by comparing the device-width with the device-height. (It’s not to be confused with aspect-ratio, which is defined by the width and height of the browser within the device.) The values in the media query are always presented as width/height, with portrait being the default orientation for smartphones and tablets; that is, to match an iPhone screen, you’d use device-aspect-ratio: 2/3, not 3/2, which won’t work.
Here’s a table of the musical intervals with their corresponding screens.
Name
device-aspect-ratio
Screens
Common resolutions (pixels)
major third
5/4
TFT LCD computer screens
1,280×1,024
perfect fourth
3/4 or 4/3
iPad, Kindle and other tablets, PDAs
320×240, 768×1,024
perfect fifth
2/3
iPhone, iPod Touch
320×480, 640×960
minor sixth
8/5 (16/10)
Many widescreens
1,152×720, 1,440×900, 1,920×1,200
major sixth
3/5
Many smartphones
240×400, 480×800
minor seventh
16/9 or 9/16
Many widescreens and some smartphones
720×1,280, 1,366×768, 1,920×1,080, 2,560×1,440
[You might argue that I’m playing fast and loose with the ratios. I suppose, mathematically speaking, 9:16 is not the same as 16:9: I’m no expert. But let’s not throw the baby out with the bath water, particularly at Christmas.]
With this in mind, we can begin to write media queries that will influence various typographic and layout values in line with the aspect ratios of specific screens and in combination with em-based min-width queries that work from smaller, mobile screens to larger, desktop screens.
Here’s a very simple demo page with only some text, an image with a caption and a little basic layout: no seasonal overindulgence here.
Demo: Sample page using device-aspect-ratio media queries based on musical interval ratios
Our initial styles for all devices are based on the perfect fifth, with the major third and octave rounding things out into a harmonious whole, whether or not media queries are supported. For example:
html { font-size: 100%; line-height: 1.5; }
/* font-size:line-height = 16:24 = 2:3 = perfect fifth */
h1 { font-size: 32px; font-size: 2rem; line-height: 1.25; }
/* font-size:line-height = 32:40 = 4:5 = major third
body:h1 = 16:32 = 1:2 = octave */
While we should really consider methods of delivering images appropriate to the screen size, let’s just stick to a single image for all devices. But why don’t we change its aspect ratio from 4:3 to 3:2, to fit with our harmonic scheme? It’s easy enough to do with overflow:hidden on the <figure> element to hide a part of the image, and a negative margin fudge:
figure img { margin: -8.5% 0 0 0; width: 100%; max-width: 100%; }
Our first break point targets devices 320 pixels wide with an aspect ratio of 2:3, namely the iPhone and iPod Touch:
/* 320px = 20×16 */
@media only screen and (min-width: 20em) and (device-aspect-ratio: 2/3) { }
We’re actually already there, of course, as the intervals we’ve chosen resonate with this aspect ratio – the content is already bound to the device.
Our next media query, then, will make some changes to match a different ratio, the major sixth (3:5), which is same as that of many smartphones:
/* 480px = 30×16 */
@media only screen and (min-width: 30em) and (device-aspect-ratio: 3/5) { }
A different aspect ratio might require a change in harmony. For devices with these proportions, we’ll now use the perfect fourth (3:4) and the major sixth (3:5) along with the octave we already have to create a new resonating harmony. For instance, a slightly wider screen means we can increase the line-height to aid the legibility of longer lines:
html { line-height: 1.667; }
/* font-size:line-height = 16:26.672 = 3:5 = major sixth */
h1 { font-size: 32px; font-size: 2rem; line-height: 1.667; }
/* font-size:line-height = 32:53.333 = 3:5 = major sixth
body:h1 = 16:32 = 1:2 = octave */
and we can remove the negative margin to display our 4:3 image in its entirety.
Each screen displays content styled using relationships related to its own proportions. On the left, an iPhone 4 (2:3); on the right, a Samsung Nexus S (3:5). Your mileage may vary.
Another device, another media query. At 768 pixels, screens are wide enough to add columns. The ratios we’ve used for the 3:5 screens include the perfect fourth (3:4) so we don’t need to change any of the font measurements, but we can base the proportions of the columns on the major sixth interval:
article { float: left; width: 56%; }
/* width of main column 3:5 (60% of 100%, major sixth)
incorporating gutter width */
aside { float : right; width : 36%; }
On devices with a 3:4 aspect ratio, this works even better in landscape orientation.
While not every screen over 768 pixels wide will have 3:4 proportions, the range of intervals informing the design ensure harmonious relationships between the different parts of the layout.
For wide screens proper (break point at 1,280 pixels) we can employ a new set of harmonious intervals. Many laptop and desktop screens have a 16:10 aspect ratio, which boils down to 8:5, equivalent to the minor sixth (5:8). Combined with a minor third (5:6) and the octave (1:2), this creates a new harmony appropriate to these devices. Let’s increase the font size and change the image’s aspect ratio to match:
html { font-size: 120%; line-height: 1.6; }
/* font-size increased for wider screens from 16px to 19.2px
(5:6 = minor third)
font-size:line-height = 19.2:30.72 = 5:8 = minor sixth */
figure img { margin: -12.5% 0 0 ; }
/* using -ve margin combined with overflow:hidden
on the figure element
to crop the image from 4:3 to 8:5 = minor sixth */
A wide screen with a 8:5 (16:10) aspect ratio and an image to match.
With more pixels at our disposal, we can also now use the musical interval ratios to determine the width of the layout, and change the column proportions as well:
section { margin: 0 auto; width: 83.333%; }
/* content width:screen width = 5:6 = minor third */
article { width: 60%; }
/* width of main column 5:8 (62.5% of 100%, minor sixth)
incorporating gutter width */
aside { width: 35%; }
With some carefully targeted media queries, we can begin to reach towards fulfilling the second and third tenets of Boulton’s new canon for web design: connecting the parts of content through relationships embodied in the layout design; and binding the content to the devices people use to access it.
Coda
Musical interval ratios and screen aspect ratios reveal more than convenient correspondence. These proportions work on a deep aesthetic level. Much is claimed for the golden ratio φ, but none of the screens pervading our lives use it. Perhaps that’s an accident of technology, but can making screens to φ’s proportions be more difficult or expensive than 2:3 or 3:4 or 16:10? Here, then, is not just one but a set of proportions with a uniquely human focus, originating in nature, recognized in antiquity, fundamental still.
We find music to be an art steeped with meaning, yet, unlike literary and representational arts, purely instrumental music has no obvious semantic content. It boasts an ability to express emotions while remaining an abstract art in some sense, which makes it very like design. These days, we’re rightly encouraged to design for emotion, to make our users’ experience meaningful, seductive, delightful. Using musical ideas and principles in our designs can help achieve those ends.
Let’s not be naïve, of course; designing web pages is even less like composing music than it’s like designing for print. In visual design, the eye will always be sovereign to the ear; following these principles will only get us so far. We cannot truly claim that a carefully composed web page layout will have the same qualities and effect as any musical patterns that inform it. In music, a set of intervals is always harmonious in relation to other sets of intervals: music rarely stands still. What aspect ratios will future screens take? Already today there is great variation in devices and support for media queries (and within that, support for device-aspect-ratio). And what of non-western musical traditions? Or rhythm, form, tempo and dynamics? What I’ve demonstrated above is only a suggestion, a tentative exploration of one possible way forward.
But as our discipline matures and we become more articulate about what we do, we must look longer and deeper into areas of human endeavour already rich with value. Music is a fertile ground to explore and has the potential to yield up new approaches for web design.
Footnotes
Just intonation is a system of tuning that uses small integers to describe the musical intervals, based initially on the perfect fifth, that most consonant of intervals. Simple instruments such as vibrating strings and natural horns, as well as unaccompanied voices, tend to fall into just intonation naturally. |
2011 |
Owen Gregory |
owengregory |
2011-12-09T00:00:00+00:00 |
https://24ways.org/2011/composing-the-new-canon/ |
design |
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 |
325 |
"Z's not dead baby, Z's not dead" |
While Mr. Moll and Mr. Budd have pipped me to the post with their predictions for 2006, I’m sure they won’t mind if I sneak in another. The use of positioning together with z-index will be one of next year’s hot techniques
Both has been a little out of favour recently. For many, positioned layouts made way for the flexibility of floats. Developers I speak to often associate z-index with Dreamweaver’s layers feature. But in combination with alpha transparency support for PNG images in IE7 and full implementation of position property values, the stacking of elements with z-index is going to be big. I’m going to cover the basics of z-index and how it can be used to create designs which ‘break out of the box’.
No positioning? No Z!
Remember geometry? The x axis represents the horizontal, the y axis represents the vertical. The z axis, which is where we get the z-index, represents /depth/. Elements which are stacked using z-index are stacked from front to back and z-index is only applied to elements which have their position property set to relative or absolute. No positioning, no z-index. Z-index values can be either negative or positive and it is the element with the highest z-index value appears closest to the viewer, regardless of its order in the source. Furthermore, if more than one element are given the same z-index, the element which comes last in source order comes out top of the pile.
Let’s take three <div>s.
<div id="one"></div>
<div id="two"></div>
<div id="three"></div>
#one {
position: relative;
z-index: 3;
}
#two {
position: relative;
z-index: 1;
}
#three {
position: relative;
z-index: 2;
}
As you can see, the <div> with the z-index of 3 will appear closest, even though it comes before its siblings in the source order. As these three <div>s have no defined positioning context in the form of a positioned parent such as a <div>, their stacking order is defined from the root element <html>. Simple stuff, but these building blocks are the basis on which we can create interesting interfaces (particularly when used in combination with image replacement and transparent PNGs).
Brand building
Now let’s take three more basic elements, an <h1>, <blockquote> and <p>, all inside a branding <div> which acts a new positioning context. By enclosing them inside a positioned parent, we establish a new stacking order which is independent of either the root element or other positioning contexts on the page.
<div id="branding">
<h1>Worrysome.com</h1>
<blockquote><p>Don' worry 'bout a thing...</p></blockquote>
<p>Take the weight of the world off your shoulders.</p>
</div>
Applying a little positioning and z-index magic we can both set the position of these elements inside their positioning context and their stacking order. As we are going to use background images made from transparent PNGs, each element will allow another further down the stacking order to show through. This makes for some novel effects, particularly in liquid layouts.
(Ed: We’re using n below to represent whatever values you require for your specific design.)
#branding {
position: relative;
width: n;
height: n;
background-image: url(n);
}
#branding>h1 {
position: absolute;
left: n;
top: n;
width: n;
height: n;
background-image: url(h1.png);
text-indent: n;
}
#branding>blockquote {
position: absolute;
left: n;
top: n;
width: n;
height: n;
background-image: url(bq.png);
text-indent: n;
}
#branding>p {
position: absolute;
right: n;
top: n;
width: n;
height: n;
background-image: url(p.png);
text-indent: n;
}
Next we can begin to see how the three elements build upon each other.
1. Elements outlined
2. Positioned elements overlayed to show context
3. Our final result
Multiple stacking orders
Not only can elements within a positioning context be given a z-index, but those positioning contexts themselves can also be stacked.
Two positioning contexts, each with their own stacking order
Interestingly each stacking order is independent of that of either the root element or its siblings and we can exploit this to make complex layouts from just a few semantic elements. This technique was used heavily on my recent redesign of Karova.com.
Dissecting part of Karova.com
First the XHTML. The default template markup used for the site places <div id="nav_main"> and <div id="content"> as siblings inside their container.
<div id="container">
<div id="content">
<h2></h2>
<p></p>
</div>
<div id="nav_main"></div>
</div>
By giving the navigation <div> a lower z-index than the content <div> we can ensure that the positioned content elements will always appear closest to the viewer, despite the fact that the navigation comes after the content in the source.
#content {
position: relative;
z-index: 2;
}
#nav_main {
position: absolute;
z-index: 1;
}
Now applying absolute positioning with a negative top value to the <h2> and a higher z-index value than the following <p> ensures that the header sits not only on top of the navigation but also the styled paragraph which follows it.
h2 {
position: absolute;
z-index: 200;
top: -n;
}
h2+p {
position: absolute;
z-index: 100;
margin-top: -n;
padding-top: n;
}
Dissecting part of Karova.com
You can see the full effect in the wild on the Karova.com site.
Have a great holiday season! |
2005 |
Andy Clarke |
andyclarke |
2005-12-16T00:00:00+00:00 |
https://24ways.org/2005/zs-not-dead-baby-zs-not-dead/ |
design |
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 |
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 |
9 |
How to Write a Book |
Were you recently inspired to write a book after reading Owen Gregory’s compendium of author insights? Maybe so inspired to strike out on your own and self-publish?
Based on personal experience, writing a book is hard. It requires a great deal of research, experience, and patience. To be able to consolidate your thoughts and what you’ve learned into a sensible and readable tome is an admirable feat. To decide to self-publish and take on yourself all of the design, printing, distribution, and so much more is tantamount to insanity. Again, based on personal experience.
So, why might you want to self-publish?
If you’ve spent many a late night doing cross-browser testing just to know that your site works flawlessly in twenty-four different browsers — including Mosaic, of course — then maybe you’ll understand the fun that comes from doing it all.
Working with a publisher, you’re left to focus on one core thing: writing. That’s a good thing. A good publisher has the right resources to help you get your idea polished and the distribution network to get your book on store shelves around the world. It’s a very proud moment to be able to walk into a book store and see your book sitting there on the shelf.
Self-publishing can also be a wonderful process as you get to own it from beginning to end. Every decision is yours and if you’re a control freak like me, this can be a very rewarding experience.
While there are many aspects to self-publishing, I’m going to speak to just one of them: creating an ebook.
Formats
In creating an ebook, you first need to decide what formats you wish to support. There are three main formats, each with their own pros and cons:
PDF
EPUB
MOBI
PDFs are supported on almost every device (Windows, Mac, Kindle, iPad, Android, etc.) and can even be a stepping stone to creating a print version of your book. PDFs allow for full typographic and design control, but at the cost of needing to fit things into a predefined page layout. Is it US Letter or A4? Or is it a format that isn’t easily printed by readers on their home printers?
EPUB is a more fluid format that is supported by the Apple iPad, iPhone, and now on the desktop with OS X Mavericks. It’s also supported by Google Play for Android devices. While EPUB is supported on other devices, you’re likely to choose EPUB because you’re targeting your book at the Apple audience. The EPUB format is HTML-based with support for some CSS and even video and interactive elements. You can create very rich and exciting experiences using the EPUB format that just aren’t possible with PDF or MOBI. However, if you decide to support multiple file formats, you’ll likely find — as I did — that a consistent experience between all formats is easier to build and maintain, and therefore the extra benefits of interactivity go out the window.
MOBI is a format originally developed for the Mobipocket Reader but more popularly supported by the Amazon Kindle. If you’re looking to attract the Kindle audience or publish to Amazon via the Kindle Direct Publishing platform then the HTML-based MOBI format is the format you’ll want to go with.
Distribution will probably factor in heavily with what format you decide to go with. Many people I know who self-publish go with PDF only due to its ubiquity.
If you want to garner a wider audience by distributing via Amazon or the iBookstore then you’ll need to think about supporting all three formats (as I did).
What tools should I use?
I spent a lot of time figuring out the right toolset and finally got something that suits me just right.
In the past, when working with a publisher, I was given a Microsoft Word template that was passed back and forth between myself, the editor, and tech reviewer. This template has been the bane of any book writer that I’ve spoken to. Not every publisher is like that, though. Some publishers, like O’Reilly, use DocBook, an XML-based format that can be converted into PDF, EPUB, and MOBI.
Publishers already have a style guide and whether it’s DocBook or a Word template, they have the tools already in place to easily convert your work into multiple formats.
Self-publishing means that you’ll likely have to do a lot of tweaking to get things looking and working the way you want them to. I tried DocBook and the open source export tools didn’t create HTML to my liking. Fixing even the most mundane things required fiddling with XSL transformations for hours on end. Not the way I like to spend my time. I can only imagine the hoops I would’ve had to go through to get a PDF to look half-decent.
Tools like Pages or Scrivener offer up the ability to publish to multiple formats, too, but none offered me the control over the output that I truly desired. Have a mentioned that I’m a control freak?
I ended up writing my book using a technology that I already knew quite well: HTML. By writing in HTML, I already had something that I could post on my website, use for the EPUB and use for the MOBI format. All without having to change a thing. (That’s right: the same HTML that is used on SMACSS.com is used in the EPUB and is used in the MOBI.)
What about PDF? I could open up the HTML in a web browser, choose Save as PDF and be done with it but let’s face it: the filename and date attached to every single page doesn’t exactly scream professional. Web browsers actually do a surprisingly poor job with supporting the CSS paged media spec.
I had resorted to copying and pasting the content into Pages and saving as PDF from there. It wasn’t elegant but it worked. However, any changes to my HTML source required redoing those changes in Pages, as well.
Then I met my Prince Charming: Prince XML. It’s pricey but it works incredibly well. It takes HTML and CSS (that very format I’ve been using for all of my other file formats) and will generate a PDF via a command line interface. Prince supports CSS paged media including headers, footers, page counts, and alternating page styles.
From one format, HTML, I can now easily publish to PDF, MOBI, and EPUB, and even my website. I use the PDF version to send to the printer along with cover art to be bound and ready to ship around the world. It’s amazing how versatile HTML (and CSS) is.
To learn more about writing books with HTML and CSS, I recommend reading Building Books with CSS3 over at A List Apart.
Creating an EPUB
Let’s take a step back. Prince gets us from HTML to PDF but how do we make an EPUB out of the HTML?
An EPUB file is essentially a ZIP file with a renamed extension. There are some core files that you need to start with:
Root
META-INF
container.xml
mimetype
content.opf
toc.ncx
After that, you can start adding your content to the project. Be sure to update the toc.ncx (Table of Contents) and content.opf (the ebook manifest) with any changes you make to your project.
You can learn more about the file formats with the EPUB Format Construction Guide.
Once all your files are in place, you’ll need to create the EPUB file by running two commands (on OS X, at least):
zip -X0 your-ebook.epub mimetype
zip -Xur9D your-ebook.epub *
The mimetype needs to be the first file inside the ZIP file and therefore gets added first. Then, the rest of the files are added.
I’ve added a function to my .bash_profile to make this even easier:
function epub()
{
zip -q0X $@ mimetype; zip -qXr9D $@ *
}
Then, within the folder from which I want to create an ebook, I just run epub your-ebook.epub from the Terminal command line and the EPUB file should be ready to go.
Creating the MOBI
We have our EPUB and we have our PDF. The last step is the MOBI file. For this, I call upon Calibre. Calibre can be used as a reader and as a library but I use it exclusively to export my EPUB files to MOBI.
Calibre includes a command line utility to convert from EPUB to MOBI. (To install the command line tools, go to Preferences > Advanced > Miscellaneous and click Install Command Line Tools.)
ebook-convert your-ebook.epub your-ebook.mobi
Spread the joy
Now that you have all of your different file formats, you need to get them into the hands of people who want to (ho-ho-hopefully) buy your book!
There are a number of marketplaces such as Amazon’s Kindle Direct Publishing, iBookstore, Google Play, and NOOK Press.
Some publishers, like PragProg and O’Reilly will also add self-published books to their roster if they feel it’s a good fit for their audience.
With any distribution, you’ll have to give up a percentage of your sales—from 30% to 70% of each sale, so consider your options wisely.
Of course, you can always open your own online store and reap as much of the revenue as possible, assuming you can get the traffic to your site. Handling your own distribution allows you to create a deeper one-on-one connection with your customers, something that is impossible with other distribution channels since you don’t get customer information through other services—even though you are giving them a huge chunk of your sales!
Go forth and prosper
There’s a lot of thought and time that goes into writing a book and just as much thought and time can go into creating, publishing, and marketing your book once you’re done.
In the end, self-publishing can be a very rewarding process and well worth the time that goes into it. |
2013 |
Jonathan Snook |
jonathansnook |
2013-12-19T00:00:00+00:00 |
https://24ways.org/2013/how-to-write-a-book/ |
content |
19 |
In Their Own Write: Web Books and their Authors |
The currency of written communication — words on the page, words on the screen — comprises many denominations. To further our ends in web design and development, we freely spend and receive several: tweets aphoristic and trenchant, banal and perfunctory; blog posts and articles that call us to action or reflection; anecdotes, asides, comments, essays, guides, how-tos, manuals, musings, notes, opinions, stories, thoughts, tips pro and not-so-pro. So many, many words.
Our industry (so much more than this, but what on earth are we, collectively?), our community thrives on writing and sharing knowledge and experience. 24 ways is a case in point. Everyone can learn and contribute through reading and writing — it’s what we’ve always done.
To web authors and readers seeking greater returns, though, broader culture has vouchsafed an enduring and singular artefact: the book.
Last month I asked a small sample of web book authors if they would be prepared to answer a few questions; most of them kindly agreed. In spirit, the survey was informal: I had neither hypothesis nor unground axe. I work closely with writers — and yes, I’ve edited or copy-edited books by several of the authors I surveyed — and wanted to share their thoughts about what it was like to write a book (“…it was challenging to find a coherent narrative”), why they did it (“Who wouldn’t want to?”) and what they learned from the experience (“That I could!”).
Reasons for writing a book
In web development the connection between authors and readers is unusually close and immediate. Working in our medium precipitates a unity that’s rare elsewhere. Yet writing and publishing a book, even during the current books revolution, is something only a few of us attempt and it remains daunting and a little remote. What spurs an author to try it? For some, it’s a deeply held resistance to prevailing trends:
I felt that designers and developers needed to be shaken out of what seemed to me had been years of stagnation.
—Andrew Clarke
Or even a desire to protect us from ourselves:
I felt that without a book that clearly defined progressive enhancement in a very approachable and succinct fashion, the web was at risk. I was seeing Tim Berners-Lee’s vision of universal availability slip away…
—Aaron Gustafson
Sometimes, there’s a knowledge gap to be filled by an author with the requisite excitement and need to communicate. Jon Hicks took his “pet subject” and was “enthused enough to want to spend all that time writing”, particularly because:
…there was a gap in the market for it. No one had done it before, and it’s still on its own out there, with no competition. It felt like I was able to contribute something.
Cennydd Bowles felt a professional itch at a particular point in his career, understanding that
[a]s a designer becomes more senior, they start looking for ways to scale the effects of their work. For some, that leads into management. For others, into writing.
Often, though, it’s also simply a personal challenge and ambition to explore a subject at length and create something substantial. Anna Debenham describes a motivation shared by several authors:
To be able to point to something more tangible than an article and be able to say “I did that.”
That sense of a book’s significance, its heft and gravity even, stems partly from the cultural esteem which honours books and their authors. Books have a long history as sources of wisdom, truth and power. Even with more books being published each year than ever before, writing one is still commonly considered a laudable achievement, including in our field.
Challenges of writing a book
Received wisdom has it that writing online should be brief and chunky and approachable: get to the point; divide it all up; subheadings and lists are our friends; write like you’re talking; no one has time to read. Much of such advice is true. Followed well, it lends our writing punch and pith, vigour and vim. The web is nimble, the web keeps up, and it suits what we write about developing for it. It’s perfect for delivering our observations, queries and investigations into all the various aspects of the work, professional and personal.
Yet even for digital natives like web authors, books printed and electronic retain an attractive glister.
Ideas can be developed more fully, their consequences explored to greater depth and extended with more varied examples, and the whole conveyed with more eloquence, more style. Why shouldn’t authors delay their conclusions if the intervening text is apposite, rich with value and helps to flesh out the skeleton of an argument? Conclusions might or might not be reached, of course, but a writer is at greater liberty in a book to digress in tangential and interesting ways.
Writing a book involves committing time, energy, thought and money. As Brian Suda found, it can be tough “getting the ideas out of my head into a cohesive blob of text.” Some authors end up talking to themselves…
It helps me to keep a real person in mind, someone who I’m talking to as I write. Sometimes I have the same conversations over and over in my head.
—Andrew Clarke
…while others are thinking ahead, concerned with how their book will be received:
Would anyone want to read it? Would they care? Would it be respected by my peers?
—Joe Leech
Challenges that arose time and again included “starting” and “getting words on the page” as well as “knowing when to stop” or “letting go”. Personal organization problems and those caused by publishers were also widely mentioned. Time loomed large. Making time, finding time. Giving up “sleep and some sanity” and realizing “it will take you far, far, far longer than you naively assumed”. Importantly, writing time is time away from gainful employment: Aaron Gustafson found the hardest thing about writing a book to be “the loss of income while I was writing.”
Perils and pleasures of editing
Editing, be it structural, technical or copy editing, is founded on reciprocity. Without openness and a shared belief that the book is worthwhile, work can founder in acrimony and mistrust. Editors are a book’s first and most critical (in every sense) readers. Effective and perceptive editing makes a book as good as it can be, finding the book within the draft like sculpture reveals the statue in the stone.
A good editor calls you out on poor assumptions and challenges you to really clarify your thinking. Whilst it can be difficult during the process to have your thinking challenged, it’s always been worth it — for me personally — in the long run. A good editor also reins you in when you’ve perhaps wandered off track or taken a little too long to make a point.
—Christopher Murphy
Andy Croll found editing “all positive” and Aaron Gustafson loves “working with a strong editor […] I want someone to tell it to me straight.” But it can be a rollercoaster, “both terrifying and the real moment of elation”. Mixed emotions during the editing process are common:
It was very uncomfortable! I knew it was making the work stronger, but it was awkward having my inconsistencies and waffle picked apart.
—Jon Hicks
It can be distressing to have written work looked over by a professional, particularly for first-time book authors whose expertise lies elsewhere:
I was a little nervous because I don’t consider myself a skilled writer — I never dreamed of becoming an author. I’m a designer, after all.
—Geri Coady
Communication is key, particularly when it comes to checking or changing the author’s words.
I like a good banter between me and the tech editor — if we can have a proper argument in Word comments, that’s great.
—Rachel Andrew
But if handled poorly, small battles can break out. Rachel Andrew again:
However, having had plenty of times where the technical editor has done nothing more than give a cursory glance, I started to leave little issues in for them to spot. If they picked them up I knew they were actually testing the code and I could be sure the work was being properly tech edited. If they didn’t spot them, I’d find someone myself to read through and check it!
A major concern for writers is that their voices will be altered, filtered, mangled or otherwise obscured by the editing process. Good copy editing must remain unnoticed while enhancing the author’s voice in print. Donna Spencer appreciated the way her editor “tidied up my work and made it a million times better, but left it sounding exactly like me.” Similarly, Andrew Travers “was incredibly impressed at how well my editor tightened up my own writing without it feeling like another’s voice” and Val Head sums up the consensus that:
the editor was able to help me express what I was trying to say in a better way […] I want to have editors for everything now.
At the keyboard, keep your friends close, but your editors closer.
Publishing and publishers
Conditions ought to militate against the allure of writing a book about web design and development. More books are published each year than ever before, so readerships elude new authors and readers can struggle to find authors to trust in their fields of interest. New spaces for more expansive online writing about working on and with the web are opening up (sites like Contents Magazine and STET), and seminal online web development texts are emerging. Publishing online is simple, far-reaching and immediate.
Much more so than articles and blog posts, books take time to research, write and read; add the complexity of commissioning, editing, designing, proofreading, printing, marketing and distribution processes, and it can take many months, even years to publish. The ceaseless headlong momentum of the web can leave articles more than a few weeks old whimpering in its wake, but updating them at least is straightforward; printed books about web development can depreciate as rapidly as the technology and techniques they describe, while retaining the “terrifying permanence that print bestows: your opinions will follow you forever”.
So much moves on, and becomes out of date. Companies featured get bought by larger companies and die, techniques improve and solutions featured become terribly out of date. Unlike a website, which could be updated continuously, a book represents the thinking ‘at that time’.
—Jon Hicks
Publishers work hard to mitigate these issues, promoting new books and new authors, bringing authors and readers together under a trusted banner. When a publisher packages up and releases a writer’s words, it confers a seal of approval and “badge of quality”, very important to new authors.
Publishers have other benefits to offer, from expert knowledge:
My publisher was extraordinarily supportive (and patient). Her expertise in my chosen subject was both a pressure (I didn’t want to let her down) and a reassurance (if she liked it, I knew it was going to be fine).
—Andrew Travers
…to systems and support mechanisms set up specifically to encourage writers and publish books:
Working as a team means you’re bringing in everyone’s expertise.
—Chui Chui Tan
As a writer, the best part about writing for a publisher was the writing infrastructure offered.
—Christopher Murphy
There can be drawbacks, however, and the occasional horror story:
We were just one small package on a huge conveyor belt. The publisher’s process ruled all.
—Cennydd Bowles
It’s only looking back I realise how poorly some publishers treat writers — especially when the work is so poorly remunerated.My worst experience was when a publisher decided, after I had completed the book, that they wanted to push a different take on the subject than the brief I had been given. Instead of talking to me, they rewrote chunks of my words, turning my advice into something that I would never have encouraged. Ultimately, I refused to let the book go out under my name alone, and I also didn’t really promote the book as I would have had to point out the things I did not agree with that had been inserted!
—Rachel Andrew
Self-publishing is now a realistic option for web authors, and can offers “complete control over the end product” as well as the possibility of earning more than a “pathetic author revenue percentage”. There can be substantial barriers, of course, as self-publishing authors must face for themselves the risks and challenges conventional publishers usually bear. Ideally, creating a book is a collaboration between author and publisher. Geri Coady found that “working with my publisher felt more like working with a partner or co-worker, rather than working for a boss.”
Wise words
So, after meeting the personal costs of writing and publishing a web book — fear, uncertainty, doubt, typing (so much typing) — and then smelling the roses of success, what’s left for an author to say? Some words, perhaps, to people thinking of writing a book.
Donna Spencer identifies a stumbling block common to many writers with an insight into the writing process:
Having talked to a lot of potential authors, I think most have the problem that they haven’t actually figured out the ‘answer’ to their premise yet. They feel like they are stuck in the writing, but they are actually stuck in the thinking.
For some no-nonsense, straightforward advice to cut through any anxiety or inadequacy, Rachel Andrew encourages authors to “treat it like any other work. There is no mystery to writing, you just have to write. Schedule the time, sit down, write words.” Tim Brown notes the importance of the editing process to refine a book and help authors reach their readers:
Hire good editors. Editors are amazing thinkers who can vastly improve the quality and clarity of a piece of writing.
We are too much beholden to the practical demands and challenges of technology, so Aaron Gustafson suggests a writer should “favor philosophies over techniques and your book will have a longer shelf life.”
Most intimations of renown and recognition are nipped in the bud by Joe Leech’s warning: “Don’t expect fame and fortune.” Although Cennydd Bowles’ bitter experience can be discouraging:
The sacrifices required are immense. You probably won’t make it.
…he would do things differently for a future book:
I would approach the book with […] far more concern about conveying the damn joy of what I do for a living.
The pleasure of writing, not just having written is captured by James Chudley when he recalls:
How much I enjoy writing and also how much I enjoy the discipline or having a side project like this. It’s a really good supplement to working life.
And Jon Hicks has words that any author will find comforting:
It will be fine. Everything will be fine. Just get on with it!
As the web expands effortlessly and ceaselessly to make room for all our words, yet it can also discourage the accumulation of any particular theme in one space, dividing rich seams and scattering knowledge across the web’s surface and into its deepest reaches. How many words become weightless and insubstantial, signals lost in the constant white noise of indistinguishable voices, unloved, unlinked? The web forgets constantly, despite the (somewhat empty) promise of digital preservation: articles and data are sacrificed to expediency, profit and apathy; online attention, acknowledgement and interest wax and wane in days, hours even.
Books can encourage deeper engagement in readers, and foster faith in an author, particularly if released under the imprint of a recognized publisher within the field. And books are changing. Although still not widely adopted, EPUB3 is the new standard in ebooks, bringing with it new possibilities for interaction and connection: readers with the text; readers with readers; and readers with authors. EPUB3 is built on HTML, CSS and JavaScript — sound familiar? In the past, we took what we could from the printed page to make the web; now books are rubbing up against what we’ve made.
So: a book.
Ever thought you could write one? Should write one? Would?
I’d like to thank all the authors who wrote their books and answered my questions.
Rachel Andrew · CSS3 Layout Modules, The CSS3 Anthology and more
Cennydd Bowles · Undercover User Experience Design, with James Box
Tim Brown · Combining Typefaces
James Chudley · Usability of Web Photos
Andrew Clarke · Hardboiled Web Design
Geri Coady · Colour Accessibility
Andy Croll · HTML Email
Anna Debenham · Front-end Style Guides
Aaron Gustafson · Adaptive Web Design
Val Head · CSS Animations
Jon Hicks · The Icon Handbook
Joe Leech · Psychology for Designers
Christopher Murphy · The Craft of Words, with Niklas Persson
Donna Spencer · Information Architecture, Card Sorting and How to Write Great Copy for the Web
Brian Suda · Designing with Data
Chui Chui Tan · International User Research
Andrew Travers · Interviewing for Research |
2013 |
Owen Gregory |
owengregory |
2013-12-15T00:00:00+00:00 |
https://24ways.org/2013/web-books/ |
content |
24 |
Kill It With Fire! What To Do With Those Dreaded FAQs |
In the mid-1640s, a man named Matthew Hopkins attempted to rid England of the devil’s influence, primarily by demanding payment for the service of tying women to chairs and tossing them into lakes.
Unsurprisingly, his methods garnered criticism. Hopkins defended himself in The Discovery of Witches in 1647, subtitled “Certaine Queries answered, which have been and are likely to be objected against MATTHEW HOPKINS, in his way of finding out Witches.”
Each “querie” was written in the voice of an imagined detractor, and answered in the voice of an imagined defender (always referring to himself as “the discoverer,” or “him”):
Quer. 14.
All that the witch-finder doth is to fleece the country of their money, and therefore rides and goes to townes to have imployment, and promiseth them faire promises, and it may be doth nothing for it, and possesseth many men that they have so many wizzards and so many witches in their towne, and so hartens them on to entertaine him.
Ans.
You doe him a great deale of wrong in every of these particulars.
Hopkins’ self-defense was an early modern English FAQ.
Digital beginnings
Question and answer formatting certainly isn’t new, and stretches back much further than witch-hunt days. But its most modern, most notorious, most reviled incarnation is the internet’s frequently asked questions page.
FAQs began showing up on pre-internet mailing lists as a way for list members to answer and pre-empt newcomers’ repetitive questions:
The presumption was that new users would download archived past messages through ftp. In practice, this rarely happened and the users tended to post questions to the mailing list instead of searching its archives. Repeating the “right” answers becomes tedious…
When all the users of a system can hear all the other users, FAQs make a lot of sense: the conversation needs to be managed and manageable. FAQs were a stopgap for the technological limitations of the time.
But the internet moved past mailing lists. Online information can be stored, searched, filtered, and muted; we choose and control our conversations. New users no longer rely on the established community to answer their questions for them.
And yet, FAQs are still around. They’re a content anti-pattern, replicated from site to site to solve a problem we no longer have.
What we hate when we hate FAQs
As someone who creates and structures online content – always with the goal of making that content as useful as possible to people – FAQs drive me absolutely batty. Almost universally, FAQs represent the opposite of useful. A brief list of their sins:
Double trouble
Duplicated content is practically a given with FAQs. They’re written as though they’ll be accessed in a vacuum – but search results, navigation patterns, and curiosity ensure that users will seek answers throughout the site. Is our goal to split their focus? To make them uncertain of where to look? To divert them to an isolated microcosm of the website? Duplicated content means user confusion (to say nothing of the duplicated workload for maintaining content).
Leaving the job unfinished
Many FAQs fail before they’re even out of the gate, presenting a list of questions that’s incomplete (too short and careless to be helpful) or irrelevant (avoiding users’ real concerns in favor of soundbites). Alternately, if the right questions are there, the answers may be convoluted, jargon-heavy, or otherwise difficult to understand.
Long lists of not-my-question
Getting a single answer often means sifting through a haystack of questions. For each potential question, the user must read, comprehend, assess, move on, rinse, repeat. That’s a lot of legwork for little reward – and a lot of opportunity for mistakes. Users may miss their question, or they may fail to recognize a differently worded version of their question, or they may not notice when their sought-after answer appears somewhere they didn’t expect.
The ventriloquist act
FAQs shift the point of view. While websites speak on behalf of the organization (“our products,” “our services,” “you can call us for assistance,” etc.), FAQs speak as the user – “I can’t find my password” or “How do I sign up?” Both voices are written from the first-person perspective, but speak for different entities, which is disorienting: it breaks the tone and messaging across the website. It’s also presumptuous: why do you get to speak for the user?
These all underscore FAQs’ fatal flaw: they are content without context, delivered without regard for the larger experience of the website. You can hear the absurdity in the name itself: if users are asking the same questions so frequently, then there is an obvious gulf between their needs and the site content. (And if not, then we have a labeling problem.)
Instead of sending users to a jumble of maybe-it’s-here-maybe-it’s-not questions, the answers to FAQs should be found naturally throughout a website. They are not separated, not isolated, not other. They are the content.
To present it otherwise is to create a runaround, and users know it. Jay Martel’s parody, “F.A.Q.s about F.A.Q.s” captures the silliness and frustration of such a system:
Q: Why are you so rude?
A: For that answer, you would have to consult an F.A.Q.s about F.A.Q.s about F.A.Q.s. But your time might be better served by simply abandoning your search for a magic answer and taking responsibility for your own profound ignorance.
FAQs aren’t magic answers. They don’t resolve a content dilemma or even help users. Yet they keep cropping up, defiant, weedy, impossible to eradicate.
Where are they all coming from?
Blame it on this: writing is hard. When generating content, most of us do whatever it takes to get some words on the screen. And the format of question and answer makes it easy: a reactionary first stab at content development.
After all, the point of website content is to answer users’ questions. So this – to give everyone credit – is a really good move. Content creators who think in terms of questions and answers are actually thinking of their users, particularly first-time users, trying to anticipate their needs and write towards them.
It’s a good start. But it’s scaffolding: writing that helps you get to the writing you’re supposed to be doing. It supports you while you write your way to the heart of your content. And once you get there, you have to look back and take the scaffolding down.
Leaving content in the Q&A format that helped you develop it is missing the point. You’re not there to build scaffolding. You have to see your content in its naked purpose and determine the best method for communicating that purpose – and it usually won’t be what got you there.
The goal (to borrow a lesson from content management systems) is to separate the content from its presentation, to let the meaning of the content inform its display.
This is, of course, a nice theory.
An occasionally necessary evil
I have a lot of clients who adore FAQs. They’ve developed their content over a long period of time. They’ve listened to the questions their users are asking. And they’ve answered them all on a page that I simply cannot get them to part with.
Which means I’ve had to consider that there may be occasions where an FAQ page is appropriate.
As an example: one of my clients is a financial office in a large institution. Because this office manages several third-party systems that serve a range of niche audiences, they had developed FAQs that addressed hyper-specific instances of dysfunction within systems for different users – à la “I’m a financial director and my employee submitted an expense report in such-and-such system and it returned such-and-such error. What do I do?”
Yes, this content could be removed from the question format and rewritten. But I’m not sure it would be an improvement. It won’t necessarily resolve concerns about length and searchability, and the different audiences may complicate the delivery. And since the work of rewriting it didn’t fit into the client workflow (small team, no writers, pressed for time), I didn’t recommend the change.
I’ve had to make peace with not being to torch all the FAQs on the internet. Some content, like troubleshooting information or complex procedures, may be better in that format. It may be the smartest way for a particular client to handle that particular information.
Of course, this has to be determined on a case-by-case basis, taking into account the amount of content, the subject matter, the skill levels of the content creators, the publishing workflow, and the search habits of the users.
If you determine that an FAQ page is the only way to go, ask yourself:
Is there a better label or more specific term for the page (support, troubleshooting, product concerns, etc.)?
Is there way to structure the page, categorize the questions, or otherwise make it easier for users to navigate quickly to the answer they need?
Is a question and answer format absolutely the best way to communicate this information?
Form follows function
Just as a question and answer format isn’t necessarily required to deliver the content, neither is it an inappropriate method in and of itself. Content professionals have developed a knee-jerk reaction: It’s an FAQ page! Quick, burn it! Buuuuurn it!
But there’s no inherent evil in questions and answers. Framing content in an interrogatory construct is no more a deal with the devil than subheads and paragraphs, or narrative arcs, or bullet points.
Yes, FAQs are riddled with communication snafus. They deserve, more often than not, to be tied to a chair and thrown into a lake. But that wouldn’t fix our content problems. FAQs are a shiny and obvious target for our frustration, but they’re not unique in their flaws. In any format, in any display, in any kind of page, weak content can rear its ugly, poorly written head.
It’s not the Q&A that’s to blame, it’s bad content. Content without context will always fail users. That’s the real witch in our midst. |
2013 |
Lisa Maria Martin |
lisamariamartin |
2013-12-08T00:00:00+00:00 |
https://24ways.org/2013/what-to-do-with-faqs/ |
content |
43 |
Content Production Planning |
While everyone agrees that getting the content of a website right is vital to its success, unless you’re lucky enough to have an experienced editor or content strategist on board, planning content production often seems to fall through the cracks. One reason is that, for most of the team, it feels like someone else’s problem. Not necessarily a specific person’s problem. Just someone else’s. It’s only when everyone starts urgently asking when the content is going to be ready, that it becomes clear the answer is, “Not as soon as we’d like it”.
The good news is that there are some quick and simple things you can do, even if you’re not the official content person on a project, to get everyone on the same content planning page.
Content production planning boils down to answering three deceptively simple questions:
What content do you need?
How much of it do you need?
Who’s going to make it?
Even if it’s not your job to come up with the answers, by asking these questions early enough and agreeing who is going to come up with the answers, you’ll be a long way towards avoiding the last-minute content problems which so often plague projects.
How much content do we need?
People tend to underestimate two crucial things about content: how much content they need, and how long that content takes to produce.
When I ask someone how big their website is – how many pages it contains – I usually double or triple the answer I get. That’s because almost everyone’s mental model of their website greatly underestimates its true size. You can see the problem for yourself if you look at a site map. Site maps are great at representing a mental model of a website. But because they’re a deliberate simplification they naturally lead us to underestimate how much content is involved in populating them.
Several years ago I was asked to help a client create a new microsite (their word) which they wanted ready in two weeks for a conference they were attending. Here’s the site map they had in mind. At first glance it looks like a pretty small website. Maybe twenty to thirty pages?
That’s what the client thought.
But see those boxes which are multiple boxes stacked on top of one another, for product categories, descriptions and supporting material? They’re known as page stacks, and page stacks are the content strategy equivalent of Here Be Dragons.
Say we have:
five product categories
each with five products
which all have two or three supporting documents
Those are still fairly small numbers. But small numbers multiplied by other small numbers tend to lead to big numbers.
5 categories = 5 category descriptions
plus
5 categories × 5 products each = 25 product descriptions
plus
25 products × 2.5 (average) supporting documents = 63 supporting documents
equals
93 pages
Suddenly our twenty- or thirty-page website is running towards one hundred.
That’s probably enough to get most project teams to sit up and take notice. But there’s still the danger of underestimating how long it’s going to take to create the content. After all, assuming the supporting documents already exist in some form, there are only about twenty-five to thirty pages of new copy to write.
How much work is it?
Again, we have the problem that small numbers when multiplied by other small numbers tend to lead to big numbers. Let’s make a rough guess that it’ll take four hours to write each product category and description page we need. That feels a little conservative if we’re writing stuff from scratch, but assuming the person doing it already knows the products fairly well it’s not unreasonable.
30 pages × 4 hours each = 120 hours
120 hours ÷ 7.5 working hours a day = 16 days
Ouch.
At this point it’s pretty clear we’re not getting this site launched in two weeks.
The goal is the conversation
By breaking down the site into its content components, and putting some rough estimates on how long each might take to produce, the client instantly realised that there was no way they would be ready to launch it in two weeks. Although we still didn’t know exactly when it would be ready, getting to that realisation right at the start of the project was a major win for everybody. Without it, the design agency would have bust a gut to get the design, front-end and CMS all done in double-quick time, only to find it was all for nothing as barely half the content was ready. As it was, an early discussion about content, albeit a brief one, bought everyone time to tackle the project properly, without pulling any long nights or working weekends.
If you haven’t been able to get people to discuss content plans for the project, these kinds of rough estimates should give you enough evidence to get everyone to start taking it seriously. Your goal is to get everyone on the project to a place where they are ready to talk in detail about who is going to create this content, and how long it’s really going to take them, and to get to those conversations before lack of content becomes a problem.
Be careful though. It’s best to talk in ranges and round numbers when your estimates are this uncertain. And watch those multipliers. Given small numbers multiplied by other small numbers lead to big numbers, changing just one number can greatly change the overall estimate. I like to run a couple of different scenarios to check what things look like if I’ve under- or overestimated either how many pages we’re going to need, or how long they’re going to take to create. For example:
Top end: 30 pages × 5 hours = 150 hours, or 20 days
Bottom end: 25 pages × 4 hours = 100 hours, or 13.3 days
So rather than say, “I estimate the content will take around sixteen days to produce”, I’m going to say, “I think the content will take about three to four weeks to produce”. Even with qualifiers like estimate and around, sixteen days sounds too precise. Whereas three to four weeks instantly conveys that this is just a rough figure.
Who’s going to make it?
So, people tend to underestimate two crucial things about content: how much content they need, and how long content takes to write. At this stage, you’re still in danger of the latter, because it’s tempting to simply estimate how much time content takes to write (or record, if we’re talking audio or visual content), and overlook all the other work that needs to goes on around it.
Take 24 ways as an example. In terms of our three deceptively simple questions: what is practical articles about web design; how many is twenty-four, one for each day of Advent; and who are experts working on the web, one to write each article.
But there’s another who you might not have considered.
Someone needs to select those authors in the first place, make sure they deliver their articles on time (and find someone to replace them if they don’t), review drafts, copy-edit and proofread final versions, upload them to the site, promote them, keep an eye on the comments and make sure there are still presents under the tree on Christmas morning.
Even if each of those tasks only takes an hour or so, it then needs multiplying by twenty-four (except the presents, obviously). And as we’ve already seen, small numbers multiplied by small numbers quickly turn into much bigger numbers. Just a few hours per article, when multiplied by twenty-four articles, easily multiplies up to days or even weeks of effort.
To get a more accurate estimate of how long the different kinds of content are going to take, you need to break down the content production work into its constituent stages, starting with planning, moving on through the main work of creation, to reviewing, approvals and finally publishing. You need to think about who needs to be involved at each step, and how much time they’ll need to do their bit.
Taken together, these things make up your content workflow. The workflow will be different for each organisation, but might look something like this:
Eddie the web editor will work out the key messages and objectives for each page, and agree them with Mo the marketing director.
Eddie will then get Cal, the copywriter, to write the first draft.
As part of that, Cal will interview Sam the subject expert to understand the intricacies of the subject and get all the facts straight.
Once Cal’s done the first draft, it’ll go to Sam to check for accuracy, while Eddie reviews it for style and message.
Once Cal has incorporated their feedback it’s time to get Mo to have a look at the final draft.
If Mo’s happy, it’ll get a final proofread, be uploaded to the CMS, and Mo will give the final sign-off and release it for publishing.
You can plot this on a table, with the stages of the content production process down the side, and the key roles or personnel along with top. Then the team can estimate how much time they think each of them needs at each stage.
Mo (marketing director)
Sam (subject expert)
Eddie (web editor)
Cal (copywriter)
Outline: define key messages and objectives
30 min
Review outline
15 min
First draft
30 min
3 hours
Review 1st draft
30 min
30 min
2nd draft
1 hour
Review 2nd draft
15 min
15 min
15 min
Final amendments
30 min
Proofread
15 min
Upload
15 min
Sign-off
10 min
TOTAL
40 min
1 hour 15 min
1 hour 30 min
4 hours 45 min
You can then bring out your calculator again, and come up with some more big scary numbers showing how much time it’s going to take for the whole team to get all the content needed not just written, but also planned, reviewed, approved and published.
With an experienced team you can run this exercise as a group workshop and get some fairly accurate estimates pretty quickly. If this is all a bit new to you, check out Gather Content’s Content Production Planning for Agencies ebook for a useful guide to common content roles, ballpark estimates for how much time each one needs on a typical piece of content, and how to run a process and estimating workshop to dig into them in more detail.
On a small team, one person might play many roles, but you should still sanity-check your estimates by breaking down the process and putting a rough estimate on each stage. With only a couple of people involved, it’s even easier to only include the core activity like writing or recording in your estimates, and forget to allow time for the planning, reviewing, proofreading, publishing and promoting you’ll still need to do. And even in a team of one, if at all possible you should find at least one other person to act as a second pair of eyes, and give anything you produce a quick once-over and proofread before it’s published.
Depending on the kind of content you’re making, you should also consider what will happen after it’s published. The full content life cycle should include promotion, monitoring and regular reviews to make sure content stays accurate and up to date. Making sure you have the time and resources available to do all those things for each piece of content is essential for creating a sustainable content programme.
The proof of the pudding
Even after digging into workflow and getting the whole team involved in estimating, you’re still largely in the realm of the guesstimate. The good news, though, is that you can quite quickly start finding out if your guesstimates are right or not. As soon as you can, pilot the production process with some real content. This is a double-win: you start finding out how long it really takes to produce all this fab new content, and you get real content to work with in designs and prototypes.
Once you’ve run a few things through your process, you’ll be able to refine your estimates, confirm your workflow, and give everyone involved a clear idea of when it will all be ready, and what you need from them.
Keeping it all on track
At this point I like to pull everything together into the content strategist’s favourite tool: the spreadsheet.
A simple content production checklist is a bit like a content inventory or audit, but for the content you don’t yet have, not the stuff already done. You can grab an example here.
Each piece of content gets its own row, with columns for basic information like page title, ID (which should match the site map), and who’s responsible for making it. You can capture simple details like target audience and key messages here too, though for more complex content, page description tables like those described by Relly Annett-Baker in “Extracting the Content” may be a better tool to use. Just adapt these columns to whatever makes sense for your content.
I then have columns to track where each piece is in the production process. I usually keep this simple, with a column each to mark whether it’s draft, final or uploaded. The status column on the left automatically shows the item’s status, using a simple traffic light colour scheme for whether the item is still to do (red), in draft (amber), or done (green). Seeing the whole thing slowly turn from red to green is a nice motivator.
If you want to track the workflow in more detail, a kanban board in a tool like Trello is a great way for a team to collaborate on content production, track each item’s progress, and keep an eye out for bottlenecks and delays.
Getting to the content strategy conversation
It’s a relatively simple exercise, then, to decide not just what kinds of pages you need, but also how many of them: put some rough estimates of effort on the tasks needed to create those pages – not just the writing, but all the other stages of planning, reviewing, approving, publishing and promoting – and then multiply all those things together. This will quickly bring some reality to grand visions and overambitious plans. Do it early enough, and even when the final big scary number is a lot bigger and scarier than everyone thought, you’ll still have time to do something about it.
As well as getting everyone on board for some proper content planning activities, that big scary number is your opportunity to get to the real core questions of content strategy: do we really need all this content? Where can existing content be reused and repurposed? How do we prioritise our efforts? What really matters to our readers and users?
Time and again, case studies show that less content delivers more: more leads, more sales, more self-service support and savings in the call centre. Although that argument is primarily one you should make from a good-for-the-users perspective, it doesn’t hurt to be able to make it from the cheaper-for-the-business perspective as well, and to have some big scary numbers to back that up. |
2014 |
Sophie Dennis |
sophiedennis |
2014-12-17T00:00:00+00:00 |
https://24ways.org/2014/content-production-planning/ |
content |
57 |
Cooking Up Effective Technical Writing |
Merry Christmas! May your preparations for this festive season of gluttony be shaping up beautifully. By the time you read this I hope you will have ordered your turkey, eaten twice your weight in Roses/Quality Street (let’s not get into that argument), and your Christmas cake has been baked and is now quietly absorbing regular doses of alcohol.
Some of you may be reading this and scoffing Of course! I’ve also made three batches of mince pies, a seasonal chutney and enough gingerbread men to feed the whole street! while others may be laughing Bake? Oh no, I can’t cook to save my life.
For beginners, recipes are the step-by-step instructions that hand-hold us through the cooking process, but even as a seasoned expert you’re likely to refer to a recipe at some point. Recipes tell us what we need, what to do with it, in what order, and what the outcome will be. It’s the documentation behind our ideas, and allows us to take the blueprint for a tasty morsel and to share it with others so they can recreate it. In fact, this is a little like the open source documentation and tutorials that we put out there, similarly aiming to guide other developers through our creations.
The ‘just’ification of documentation
Lately it feels like we’re starting to consider the importance of our words, and the impact they can have on others. Brad Frost warned us of the dangers of “Just” when it comes to offering up solutions to queries:
“Just use this software/platform/toolkit/methodology…”
“Just” makes me feel like an idiot. “Just” presumes I come from a specific background, studied certain courses in university, am fluent in certain technologies, and have read all the right books, articles, and resources. “Just” is a dangerous word.
“Just” by Brad Frost
I can really empathise with these sentiments. My relationship with code started out as many good web tales do, with good old HTML, CSS and JavaScript. University years involved some time with Perl, PHP, Java and C. In my first job I worked primarily with ColdFusion, a bit of ActionScript, some classic ASP and pinch of Java. I’d do a bit of PHP outside work every now and again. .NET came in, but we never really got on, and eventually I started learning some Ruby, Python and Node. It was a broad set of learnings, and I enjoyed the similarities and differences that came with new languages. I don’t develop day in, day out any more, and my interests and work have evolved over the years, away from full-time development and more into architecture and strategy. But I still make things, and I still enjoy learning.
I have often found myself bemoaning the lack of tutorials or courses that cater for the middle level – someone who may be learning a new language, but who has enough programming experience under their belt to not need to revise the concepts of how loops or objects work, and is perfectly adept at googling the syntax for getting a substring. I don’t want snippets out of context; I want an understanding of architectural principles, of the strengths and weaknesses, of the type of applications that work well with the language.
I’m caught in the place between snoozing off when ‘Using the Instagram API with Ruby’ hand-holds me through what REST is, and feeling like I’m stupid and need to go back to dev school when I can’t get my environment and dependencies set up, let alone work out how I’m meant to get any code to run.
It’s seems I’m not alone with this – Erin McKean seems to have been here too:
“Some tutorials (especially coding tutorials) like to begin things in media res. Great for a sense of dramatic action, bad for getting to “Step 1” without tears. It can be really discouraging to fire up a fresh terminal window only to be confronted by error message after error message because there were obligatory steps 0.1.0 through 0.9.9 that you didn’t even know about.”
“Tips for Learning What You Don’t Know You Don’t Know” by Erin McKean
I’m sure you’ve been here too. Many tutorials suffer badly from the fabled ‘how to draw an owl’-itis.
It’s the kind of feeling you can easily get when sifting through recipes as well as with code. Far from being the simple instructions that let us just follow along, they too can be a minefield. Fall in too low and you may be skipping over an explanation of what simmering is, or set your sights too high and you may get stuck at the point where you’re trying to sous vide a steak using your bathtub and a Ziploc bag.
Don’t be a turkey, use your loaf!
My mum is a great cook in my eyes (aren’t all mums?). I love her handcrafted collection of gathered recipes from over the years, including the one below, which is a great example of how something may make complete sense to the writer, but could be impermeable to a reader.
Depending on your level of baking knowledge, you may ask: What’s SR flour? What’s a tsp? Should I use salted or unsalted butter? Do I use sticks of cinnamon or ground? Why is chopped chocolate better? How do I cream things? How big should the balls be? How well is “well spaced”? How much leeway do I have for “(ish!!)”? Does the “20” on the other cookie note mean I’ll end up with twenty? At any point, making a wrong call could lead to rubbish cookies, and lead to someone heading down the path of an I can’t cook mentality.
You may be able to cook (or follow recipes), but you may not understand the local terms for ingredients, may not be able to acquire something and need to know what kind of substitutes you can use, or may need to actually do some prep before you jump into the main bit.
However, if we look at good examples of recipes, I think there’s a lot we can apply when it comes to technical writing on the web. I’ve written before about the benefit of breaking documentation into small, reusable parts, and this will help us, but we can also take it a bit further. Here are my five top tips for better technical writing.
1. Structure and standardise your information
Think of the structure of a recipe. We very often have some common elements and they usually follow roughly the same format. We have standards and conventions that allow us to understand very quickly what a recipe is and how it should be used.
Great recipes help their chefs know what they need to get ready in advance, both in terms of buying ingredients and putting together their kit. They then talk through the process, using appropriate language, and without making assumptions that the person can fill in any gaps for themselves; they explain why things are done the way they are. The best recipes may also suggest how you can take what you’ve done and put your own spin on it. For instance, a good recipe for the simple act of boiling an egg will explain cooking time in relation to your preference for yolk gooiness. There are also different flavour combinations to try, accompaniments, or presentation suggestions.
By breaking down your technical writing into similar sections, you can help your audience understand the elements they’ll be working with, what they need to do once they have these, and how they can move on from your self-contained illustration.
Title
Ensure your title is suitably descriptive and representative of the result. Getting Started with Python perhaps isn’t as helpful as Learn Python: General Syntax and Basics.
Result
Many recipes include a couple of lines as an overview of what you’ll end up with, and many include a photo of the finished dish. With our technical writing we can do the same:
In this tutorial we’re going to learn how to set up our development environment, and we’ll then undertake some exercises to explore the general syntax, finishing by building a mini calculator.
Ingredients
What are the components we’ll be working with, whether in terms of versions, environment, languages or the software packages and libraries you’ll need along the way? Listing these up front gives the reader a great summary of the things they’ll be using, and any gotchas.
Being able to provide a small amount of supporting information will also help less experienced users. Ideally, explain briefly what things are and why we’re using it.
Prep
As we heard from Erin above, not fully understanding the prep needed can be a huge source of frustration. Attempting to run a code snippet without context will often lead to failure when the prerequisites and process aren’t clear. Be sure to include information around any environment set-up, installation or config you’ll need to have done before you start.
Stu Robson’s Simple Sass documentation aims to do this before getting into specifics, although ideally this would also include setting up Sass itself.
Instructions
The body of the tutorial itself is the whole point of our writing. The next four tips will hopefully make your tutorial much more successful.
Variations
Like our ingredients section, as important as explaining why we’re using something in this context is, it’s also great to explain alternatives that could be used instead, and the impact of doing so.
Perhaps go a step further, explaining ways that people can change what you have done in your tutorial/readme for use in different situations, or to provide further reading around next steps. What happens if they want to change your static array of demo data to use JSON, for instance? By giving some thought to follow-up questions, you can better support your readers.
While not in a separate section, the source code for GreenSock’s GSAP JS basics explains:
We’ll use a window.onload for simplicity, but typically it is best to use either jQuery’s $(document).ready() or $(window).load() or cross-browser event listeners so that you’re not limited to one.
Keep in mind to both:
Explain what variations are possible.
Explain why certain options may be more desirable than others in different situations.
2. Small, reusable components
Reusable components are for life, not just for Christmas, and they’re certainly not just for development. If you start to apply the structure above to your writing, you’re probably going to keep coming across the same elements: Do I really have to explain how to install Sass and Node.js again, Sally? The danger with more clarity is that our writing becomes bloated and overly convoluted for advanced readers, those who don’t need to be told how to beat an egg for the hundredth time.
Instead, by making our writing reusable and modular, and by creating smaller, central resources, we can provide context and extra detail where needed without diluting our core message. These could be references we create, or those already created well by others.
This recipe for katsudon makes use of this concept. Rather than explaining how to make tonkatsu or dashi stock, these each have their own page. Once familiar, more advanced readers will likely skip over the instructions for the component parts.
3. Provide context to aid accessibility
Here I’m talking about accessibility in the broadest sense. Small, isolated snippets can be frustrating to those who don’t fully understand the wider context of how our examples work.
Showing an exciting standalone JavaScript function is great, but giving someone the full picture of how and when this is called, and how it should be included in relation to other HTML and CSS is even better. Giving your readers the ability to view a big picture version, and ideally the ability to download a full version of the source, will help to reduce some of the frustrations of trying to get your component to work in their set-up.
4. Be your own tech editor
A good editor can be invaluable to your work, and wherever possible I’d recommend that you try to get a neutral party to read over your writing. This may not always be possible, though, and you may need to rely on yourself to cast a critical eye over your work.
There are many tips out there around general editing, including printing out your work onto paper, or changing the font size: both will force your eyes to review it in a new light. Beyond this, I’d like to encourage you to think about the following:
Explain what things are. For example, instead of referencing Grunt, in the first instance perhaps reference “Grunt (a JavaScript task runner that minimises repetitive activities through automation).”
Explain how you get things, even if this is a link to official installers and documentation. Don’t leave your readers having to search.
Why are you using this approach/technology over other options?
What happens if I use something else? What depends on this?
Avoid exclusionary lingo or acronyms.
Airbnb’s JavaScript Style Guide includes useful pointers around their reasoning:
Use computed property names when creating objects with dynamic property names.
Why? They allow you to define all the properties of an object in one place.
The language we use often makes assumptions, as we saw with “just”. An article titled “ES6 for Beginners” is hugely ambiguous: is this truly for beginner coders, or actually for people who have a good pre-existing understanding of JavaScript but are new to these features? Review your writing with different types of readers in mind. How might you confuse or mislead them? How can you better answer their questions?
This doesn’t necessarily mean supporting everyone – your audience may need to have advanced skills – but even if you’re providing low-level, deep-dive, reference material, trying not to make assumptions or take shortcuts will hopefully lead to better, clearer writing.
5. A picture is worth a thousand words…
…or even better: use a thousand pictures, stitched together into a quick video or animated GIF. People learn in different ways. Just as recipes often provide visual references or a video to work along with, providing your technical information with alternative demonstrations can really help get your point across. Your audience will be able to see exactly what you’re doing, what they should expect as interaction responses, and what the process looks like at different points.
There are many, many options for recording your screen, including QuickTime Player on Mac OS X (File → New Screen Recording), GifGrabber, or Giffing Tool on Windows.
Paul Swain, a UX designer, uses GIFs to provide additional context within his documentation, improving communication:
“My colleagues (from across the organisation) love animated GIFs. Any time an interaction is referenced, it’s accompanied by a GIF and a shared understanding of what’s being designed. The humble GIF is worth so much more than a thousand words; and it’s great for cats.”
Paul Swain
Next time you’re cooking up some instructions for readers, think back to what we can learn from recipes to help make your writing as accessible as possible. Use structure, provide reusable bitesize morsels, give some context, edit wisely, and don’t scrimp on the GIFs. And above all, have a great Christmas! |
2015 |
Sally Jenkinson |
sallyjenkinson |
2015-12-18T00:00:00+00:00 |
https://24ways.org/2015/cooking-up-effective-technical-writing/ |
content |
87 |
Content Planning Demystified |
The first thing you learn as a junior editor is that you can’t do everything yourself. You must rely on someone else to do at least part of what must be done: the long-range planning, the initial drafting or shooting or recording, the editing, the production, the final polish. All of those pieces of work that belong to someone else take quite a lot of time — days, weeks, sometimes months. If you’re the sort of person who wrote college term papers the night before they were due, this can come as a bit of a shock. To my twenty-two-year-old self, it certainly did.
It turns out that the only real way to avoid a trainwreck with editorial work is to get ahead of the trouble, line everything up carefully, and leave oodles of room for all the pieces to connect on time. The same is true of content strategy, content planning, and just about everything to do with content on the web, except for the writing itself — and that, too, usually takes far longer than anyone expects. If you’re not a professional editor and you suddenly find yourself dealing with content creation, you’re almost certainly going to underestimate the time and effort involved, or to skip something important in the planning process that pops up to bite you later.
Without good content, it doesn’t matter how well designed or coded your web project is, because it won’t be doing the thing it’s meant to do. And even if content is far from your specialty, you may well end up being the only one willing to coordinate it far enough in advance to avoid a chaotic ending. Whether you’re hiring writers and editors for a big project, working with a small client, or coaxing some editorial help out of a co-worker, getting the planning work done correctly — and ahead of time — will allow you to orchestrate a glorious ballet of togetherness, instead of feverishly scraping together something to put on your site when the deadline looms. So get out the graph paper and the pocket protector, because we’re going to go Full Nerd on this problem.
Know your poison
Anyone who’s seen a project delayed for six months by content trouble, or derailed by content that’s bland and unhelpful, knows this stuff can make you feel like a dead sock. To get ahead of the problem, you’re going to have to learn to spot common problems and plan your way around them. On web projects without a dedicated editorial lead, you’re likely to encounter content that is:
Useless – Content that doesn’t serve your readers’ needs in some way is pointless. And because it takes up your time and crowds out genuinely helpful things, it’s actually damaging. The logic is simple: you can make content that’s all about you, and that serves your stated messaging goals, but if no one is motivated to read it, it’s a waste of everyone’s time.
Badly written – When you publish articles or instructions or other content that is too stiffly formal, overly wordy, hard to understand, offensive, unintentionally cheesy, or otherwise off in tone or style, you’re doing two things. First, you’re weakening the information you’re trying to convey by making it obscure or annoying. Second — and this one is even more damaging — you’re demonstrating bad taste. When you get the cultural elements of publishing wrong, you encourage your readers to believe that you either don’t understand them or don’t care about getting it wrong.
Gooey – Content strategists have been talking about structured content (that’s chunks versus blobs) for years. If you’re publishing more than a few dozen pages without thinking through the structure of your content, you’re probably missing a chance to improve your long-term efficiency. If you’re publishing more than a couple of thousand pages without taking care of your content structure, you’re probably doing a lot more manual wrangling (or cumbersome CMS work) than you need to be, especially when it comes to cross-platform publishing.
Unregulated – If you’re not tracking what works and what doesn’t — and especially if you don’t know what “works” means for your project or organization — you’re almost certainly getting worse results than you should be, for more work.
Overabundant – As demonstrated by the cinnamon challenge, too much of a delicious thing can be a giant and publicly embarrassing disaster. For most projects and organizations, if you’re making more stuff than your readers can handle, or if you’re spreading your creative and editorial resources too thinly, that’s bad. Spammers, content farms, and barrel-bottom tabloids have their own special math, the side effects of which include insomnia, irritability, and crying in traffic while silently mouthing Wilson Phillips lyrics.
Prevent all preventable damage
Once you know what kind of trouble to look for, you can prevent a lot of it by doing some smart planning well before someone starts writing (or recording or shooting video).
To prevent uselessness: Know your readers and decide what you’re trying to accomplish — with your website as a whole, and with each piece of content, always. Once you know what you’re trying to achieve, you can evaluate your work as you go to make sure that it’s actually doing the right thing. (I’ve written a lot more about this for A List Apart and in The Elements of Content Strategy.)
To prevent bad writing: Establish a consistent and appropriate style using examples (and a style guide if you need one), designate an editor, hire good writers, and make time for quality control. Kate Kiefer’s style guide for MailChimp is a superb example of style-wrangling that everyone can use.
To prevent repulsive goo: Give your content as much structure as possible, and know how structure relates to your entire publishing ecosystem, including all those mobile devices. Sara Wachter-Boettcher’s Content Everywhere and Karen McGrane’s Content Strategy for Mobile offer brilliant yet friendly introductions to the wide world of structured content.
To prevent unregulated chaos: Measure everything that matters to your project, your client, your organization, and especially your readers — not generic measures of someone else’s success. Measure it all regularly. Be disciplined. Adjust at regular intervals. Rick Allen’s series on content strategy analytics is an excellent place to begin (part one; part two).
To prevent overabundance: Stop trying to do everything and focus on giving your readers just a few things they want and genuinely need. Don’t establish a schedule your writers might not be able to keep, and focus on differentiating yourself with quality, not quantity. (And while you’re at it, scratch the auto-posting to social networks and the cross-posting between them. It’s about as engaging as an automated phone system.)
At a slightly higher level, pick the right content person (or team) for the work. If you really only need a few pages of copy, find a smart writer who does good work for multi-platform readers. If you’re slinging tens of thousands of pages of content, get someone with field experience in high-level editorial planning and the ability to turn blobs into chunks and melted goo into Legos. If you’re starting a project that involves making a lot of content over time, bring in someone with journalism experience (or get your client to do so).
“But wait!” you may say. “I’m not hiring anyone. I have to do this all myself.” That’s not uncommon at all. The bad news is, you have to learn a bunch of stuff. The good news is, you get to learn a bunch of awesome stuff. Figure out what the project needs, just as though you were going to hire someone, and then give yourself time to get up to speed. If it’s a really complicated project, you’re probably going to have trouble unless you eventually get professional help. But if it’s small and you can do it in steps, you can certainly do much better by giving yourself a plan and working on the things that matter most.
Plan for the marathon, not the sprint
Launching with awesome content is a tiny fraction of a victory, which is why it’s so important that your content not be gooey or unregulated. It also means that if you don’t plan for a realistic publication schedule, you are going to slam into reality in a really unpleasant way not too long after you’ve begun. If you’re asking people to make words (or videos or whatever) for you, they’re going to have to do less of something else, so plan for that beforehand.
And while you’re at it, unless publishing is your core business, ditch the feed-the-beast plan that leads to fluffy blog posts and spiritless, unhelpful social media content. It’s antisocial for your reading community, offers short-term gains at best, and will burn you out or lower your standards until you don’t even know you’re doing lousy work. Good content is expensive, no matter how you do it, but spreading yourself too thin is a much worse investment than doing a smaller thing well and gradually building up a body of superb content that people want to share and keep and return to. |
2012 |
Erin Kissane |
erinkissane |
2012-12-20T00:00:00+00:00 |
https://24ways.org/2012/content-planning-demystified/ |
content |
172 |
The Construction of Instruction |
If the world were made to my specifications, all your clients would be happy to pay for a web writer to craft every sentence into something as elegant as it was functional, and the client would have planned the content so that you had it just when you asked, but we both know that won’t happen every time. Sometimes you just know they are going to write the About page, two company blog pages and a Facebook fan page before resigning their position as chief content writer and you are going to end up filling in all the details that will otherwise just be Lorem Ipsum.
Welcome to the big world of microcopy:
A man walks into a bar. The bartender nods a greeting and watches as the man scans the bottles behind the bar.
“Er, you have a lot of gin here. Is there one you would recommend?”
“Yes sir.”
Long pause.
“… Never mind, I’ll have the one in the green bottle.”
“Certainly, sir. But you can’t buy it from this part of the bar. You need to go through the double doors there.”
“But they look like they lead into the kitchen.”
“Really, sir? Well, no, that’s where we allow customers to purchase gin.”
The man walks through the doors. On the other side he is greeted by the same bartender.
“Y-you!” he stammers but the reticent bartender is now all but silent.
Unnerved, the man points to a green bottle, “Er, I’d like to buy a shot of that please. With ice and tonic water.”
The bartender mixes the drink and puts it on the bar just out of the reach of the man and looks up.
“Um, do you take cards?” the man asks, ready to present his credit card.
The bartender goes to take the card to put it through the machine.
“Wait! How much was it – with sales tax and everything? Do you take a gratuity?”
The bartender simply shrugs.
The man eyes him for a moment and decides to try his luck at the bar next door.
In the Choose Your Own Adventure version of this story there are plenty of ways to stop the man giving up. You could let him buy the gin right where he was; you could make the price more obvious; you could signpost the place to buy gin. The mistakes made by the bar and bartender are painfully obvious. And yet, there are websites losing users everyday due to the same lack of clear instruction.
A smidgen of well written copy goes a long way to reassure the nervous prospect. Just imagine if our man walked into the bar and the bartender explained that although the bar was here, sales were conducted in the next room because people were not then able to overhear the man’s card details. Instead, he is left to fend for himself. Online, we kick customers through the anonymous double doors with a merry ‘Paypal will handle your transaction!’.
Recently I worked on a site where the default error message, to account for anything happening that the developers hadn’t accounted for, was ‘SOMETHING HAS GONE WRONG!’. It might have been technically accurate but this is not how to inspire confidence in your customers that they can make a successful purchase through you. As everyone knows they can shop just fine, thank you very much, it is your site they will blame. Card declined? It’s the site. Didn’t know my email address has changed? It’s the site. Can’t log in? It’s the site.
Yes, yes. I know. None of these things are related to your site, or you the developer, but drop outs will be high and you’ll get imploring emails from your client asking you to wade knee deep into the site analytics to find a solution by testing 41 shades of blue because if it worked for Google…? Before you try a visual fix involving the Dulux paint chart breeding with a Pantone swatch, take an objective look at the information you are giving customers. How much are you assuming they know? How much are you relying on age-old labels and prompts without clarification?
Here’s a fun example for non-North Americans: ask your Granny to write out her billing address. If she looks at you blankly, tell her it is the address where the bank sends her statements. Imagine how many fewer instances of the wrong address there would be if we routinely added that information when people purchased from the UK? Instead, we rely on a language convention that hasn’t much common usage without explanation because, well, because we always have since the banks told us how we could take payments online.
So. Your client is busying themselves with writing the ultimate Facebook fan page about themselves and here you are left with creating a cohesive signup process or basket or purchase instructions. Here are five simple rules for bending puny humans to your will creating instructive instructions and constructive error messages that ultimately mean less hassle for you.
Plan what you want to say and plan it out as early as possible
This goes for all content. Walk a virtual mile in the shoes of your users. What specific help can you offer customers to actively encourage continuation and ensure a minimal amount of dropouts? Make space for that information. One of the most common web content mistakes is jamming too much into a space that has been defined by physical boundaries rather than planned out. If you manage it, the best you can hope for is that no-one notices it was a last-minute job. Mostly it reads like a bad game of Tetris with content sticking out all over the place.
Use your words
Microcopy often says a lot in a few words but without those words you could leave room for doubt. When doubt creeps in a customer wants reassurance just like Alice:
This time (Alice) found a little bottle… with the words ‘DRINK ME’ beautifully printed on it in large letters. It was all very well to say ‘Drink me,’ but the wise little Alice was not going to do that in a hurry. ‘No, I’ll look first,’ she said, ‘and see whether it’s marked “poison” or not’
Alice in Wonderland, Lewis Carroll.
Value clarity over brevity. Or a little more prosaically, “If in doubt, spell it out.” Thanks, Jeremy!
Be prepared to help
‘Login failed: email/password combination is incorrect.’
Oh.
‘Login failed: email/password combination is incorrect.
Are you typing in all capitals? Caps Lock may be on.
Have you changed your email address recently and not updated your account with us? Try your old email address first.
Can’t remember your password? We can help you reset it.’
Ah!
Be direct and be informative
There is rarely a site that doesn’t suffer from some degree of jargon. Squash it early by setting a few guidelines about what language and tone of voice you will use to converse with your users. Be consistent. Equally, try to be as specific as possible when giving error messages or instructions and allay fears upfront.
Card payments are handled by paypal but you do not need a paypal account to pay.
We will not display your email address but we might need it to contact you.
Sign up for our free trial (no credit card required).
Combine copy and visual cues, learn from others and test new combinations
While visual design and copy can work independently, they work best together. New phrases and designs are being tested all the time so take a peek at abtests.com for more ideas, then test some new ideas and add your own results. Have a look at the microcopy pool on Flickr for some wonderful examples of little words and pictures working together. And yes, you absolutely should join the group and post more examples.
A man walks into a bar. The bartender greets him in a friendly manner and asks him what he would like to drink.
“Gin and Tonic, please.”
“Yes sir, we have our house gin on offer but we also have a particularly good import here too.”
“The import, please.”
“How would you like it? With a slice of lemon? Over ice?”
“Both”
“That’s £3.80. We accept cash, cards or you could open a tab.”
“Card please.”
“Certainly sir. Move just over here so that you can’t be observed. Now, please enter your pin number.”
“Thank you.”
“And here is your drink. Do let me know if there is a problem with it. I shall just be here at the bar. Enjoy.”
Cheers! |
2009 |
Relly Annett-Baker |
rellyannettbaker |
2009-12-08T00:00:00+00:00 |
https://24ways.org/2009/the-construction-of-instruction/ |
content |
198 |
Is Your Website Accidentally Sexist? |
Women make up 51% of the world’s population. More importantly, women make 85% of all purchasing decisions about consumer goods, 75% of the decisions about buying new homes, and 81% of decisions about groceries. The chances are, you want your website to be as attractive to women as it is to men. But we are all steeped in a male-dominated culture that subtly influences the design and content decisions we make, and some of those decisions can result in a website that isn’t as welcoming to women as it could be.
Typography tells a story
Studies show that we make consistent judgements about whether a typeface is masculine or feminine: Masculine typography has a square or geometric form with hard corners and edges, and is emphatically either blunt or spiky. Serif fonts are also considered masculine, as is bold type and capitals.
Feminine typography favours slim lines, curling or flowing shapes with a lot of ornamentation and embellishment, and slanted letters. Sans-serif, cursive and script fonts are seen as feminine, as are lower case letters.
The effect can be so subtle that even choosing between bold and regular styles within a single font family can be enough to indicate masculinity or femininity.
If you want to appeal to both men and women, search for fonts that are gender neutral, or at least not too masculine. When you’re choosing groups of fonts that need to work harmoniously together, consider which fonts you are prioritising in your design. Is the biggest word on the page in a masculine or feminine font? What about the smallest words? Is there an imbalance between the prominence of masculine and feminine fonts, and what does this imply?
Typography is a language in and of itself, so be careful what you say with it.
Colour me unsurprised
Colour also has an obvious gender bias. We associate pinks and purples, especially in combination, with girls and women, and a soft pink has become especially strongly related to breast cancer awareness campaigns. On the other hand, pale blue is strongly associated with boys and men, despite the fact that pastels are usually thought of as more feminine.
These associations are getting stronger and stronger as more and more marketers use them to define products as “for girls” and “for boys”, setting expectations from an incredibly young age — children as young as four understand gender stereotypes. It should be obvious that using these highly gender-associated colours sends an incredibly strong message to your visitors about who you think your target audience is. If you want to appeal to both men and women, then avoid pinks and pale blues.
But men and women also have different colour preferences. Men tend to prefer intense primary colours and deeper colours (shades), and tolerate greys better, whilst women prefer pastels (tints). When choosing colours, consider not just the hue itself, but also tint, tone and shade.
Slightly counterintuitively, everyone likes blue, but no one seems to particularly like brown or orange.
A picture is worth a thousand words, or none
Stock photos are the quickest and easiest way to add a little humanity to your website, directly illustrating the kind of people you believe are in your audience. But the wrong photo can put a woman off before she’s even read your text.
A website about a retirement home will, for example, obviously include photos of older people, and a baby clothes retailer will obviously show photos of babies. But, in the latter case, should they also show only photographs of mothers with their children, or should they include fathers too? It’s true that women take on the majority of childcare responsibilities, but that’s a cultural holdover from a previous era, rather than some rule of law. We are seeing increasing number of stay at home dads as well as single dads, so showing only photographs of women both enforces the stereotype that only women can care, as well as marginalising male carers.
Equally, featuring prominent photographs of women on sites about male-dominated topics such as science, technology or engineering help women feel welcomed and appreciated in those fields. Photos really do speak volumes, so make sure that you also represent other marginalised groups, especially ethnic groups. If people do not see themselves represented on your site, they are not going to engage with it as much as they might.
Another form of picture that we often ignore is the icon. When you do use icons, make sure that they are gender neutral. For example, avoid using a icon of a man to denote engineers, or of a woman to denote nurses. Avoid overly masculine or feminine metaphors, such as a hammer to denote DIY or a flower to denote gardens. Not only are these gendered, they’re also trite and unappealing, so come up with more exciting and novel metaphors.
Use gender-neutral language
Last, but not least, be very careful in your use of gender in language.
Pronouns are an obvious pitfall. A lot of web content is written in the second person, using the cleary gender neutral ‘you’, but if you have to write in the third person, which uses ‘she’, ‘he’, ‘it’, and ‘they’, then be very careful which pronouns you use. The singular ‘they’ is becoming more widely acceptable, and is a useful gender-neutral option. If you must use generic ‘he’ and ‘she’, (as opposed to talking about a specific person), then vary the order that they come in, so don’t always put the male pronoun first.
When you are talking about people, make sure that you use the same level of formality for both men and women. The tendency is to refer to men by their surname and women by their first name so, for example, when people are talking about Ada Lovelace and Charles Babbage, they often talk about “Ada and Babbage”, rather than “Lovelace and Babbage” or “Ada and Charles”. As a rule, it’s best to use people’s surnames in formal and semi-formal writing, and their first names only in very informal writing.
It’s also very important to make sure that you respect people’s honorifics, especially academic titles such as Dr or Professor, and that you use titles consistently. Studies show that women and people of colour are the most likely to have their honorifics dropped, which is not only disrespectful, it gives readers the idea that women and people of colour are less qualified than white men.
If you mention job titles, avoid old-fashioned gendered titles such as ‘chairman’, and instead look for a neutral version, like ‘chair’ or ‘chairperson’. Where neutral terms have strong gender associations, such as nurse or engineer, take special care that the surrounding text, especially pronouns, is diverse and/or neutral. Do not assume engineers are male and nurses female.
More subtle intimations of gender can be found in the descriptors people use. Military metaphors and phrases, out-sized claims, competitive words, and superlatives are masculine, such as ‘ground-breaking’, ‘best’, ‘genius’, ‘world-beating’, or ‘killer’. Excessive unnecessary factual detail is also very masculine.
Women tend to relate to more cooperative, non-competitive, future-focused, and warmer language, paired with more general information. Women’s language includes word like ’global’, ‘responsive’, ‘support’, ‘include’, ‘engage’ and ‘imagine’. Focus more on the kind of relationship you can build with your customers, how you can help make their lives easier, and less on your company or product’s status.
Smash the patriarchy, one assumption at a time
We’re all brought up in a cultural stew that prioritises men’s needs, feelings and assumptions over women’s. This is the patriarchy, and it’s been around for thousands of years. But given women’s purchasing power, adhering to the patriarchy’s norms is unlikely to be good for your business. If you want to tap into the female market, pay attention to the details of your design and content, and make sure that you’re not inadvertently putting women off. A gender neutral website that designs away gender stereotypes will attract both men and women, expanding your market and helping your business flourish. |
2017 |
Suw Charman-Anderson |
suwcharmananderson |
2017-12-20T00:00:00+00:00 |
https://24ways.org/2017/is-your-website-accidentally-sexist/ |
content |
227 |
A Contentmas Epiphany |
The twelve days of Christmas fall between 25 December, Christmas Day, and 6 January, the Epiphany of the Kings. Traditionally, these have been holidays and a lot of us still take a good proportion of these days off. Equally, a lot of us have a got a personal site kicking around somewhere that we sigh over and think, “One day I’ll sort you out!” Why not take this downtime to give it a big ol’ refresh? I know, good idea, huh?
HEY WAIT! WOAH! NO-ONE’S TOUCHING PHOTOSHOP OR DOING ANY CSS FANCYWORK UNTIL I’M DONE WITH YOU!
Be honest, did you immediately think of a sketch or mockup you have tucked away? Or some clever little piece of code you want to fiddle with? Now ask yourself, why would you start designing the container if you haven’t worked out what you need to put inside?
Anyway, forget the content strategy lecture; I haven’t given you your gifts yet.
I present The Twelve Days of Contentmas!
This is a simple little plan to make sure that your personal site, blog or portfolio is not just looking good at the end of these twelve days, but is also a really useful repository of really useful content.
WARNING KLAXON: There are twelve parts, one for each day of Christmas, so this is a lengthy article. I’m not expecting anyone to absorb this in one go. Add to Instapaper. There is no TL;DR for this because it’s a multipart process, m’kay? Even so, this plan of mine cuts corners on a proper applied strategy for content. You might find some aspects take longer than the arbitrary day I’ve assigned. And if you apply this to your company-wide intranet, I won’t be held responsible for the mess.
That said, I encourage you to play along and sample some of the practical aspects of organising existing content and planning new content because it is, honestly, an inspiring and liberating process. For one thing, you get to review all the stuff you have put out for the world to look at and see what you could do next. This always leaves me full of ideas on how to plug the gaps I’ve found, so I hope you are similarly motivated come day twelve.
Let’s get to it then, shall we?
On the first day of Contentmas, Relly gave to me:
1. A (partial) content inventory
I’m afraid being a site owner isn’t without its chores. With great power comes great responsibility and all that. There are the domain renewing, hosting helpline calls and, of course, keeping on top of all the content that you have published.
If you just frowned a little and thought, “Well, there’s articles and images and… stuff”, then I’d like to introduce you to the idea of a content inventory.
A content inventory is a list of all your content, in a simple spreadsheet, that allows you to see at a glance what is currently on your site: articles; about me page; contact form, and so on.
You add the full URL so that you can click directly to any page listed. You add a brief description of what it is and what tags it has. In fact, I’ll show you. I’ve made a Google Docs template for you. Sorry, it isn’t wrapped.
Does it seem like a mammoth task? Don’t feel you have to do this all in one day. But do do it. For one thing, looking back at all the stuff you’ve pushed out into the world gives you a warm fuzzy feeling which keeps the heating bill down.
Grab a glass of mulled cider and try going month-by-month through your blog archives, or project-by-project through your portfolio. Do a little bit each day for the next twelve days and you’ll have done something awesome. The best bit is that this exploration of your current content helps you with the next day’s task.
Bonus gift: for more on content auditing and inventory, check out Jeff Veen’s article on just this topic, which is also suitable for bigger business sites too.
On the second day of Contentmas, Relly gave to me:
2. Website loves
Remember when you were a kid, you’d write to Santa with a wish list that would make your parents squirm, because your biggest hope for your stocking would be either impossible or impossibly expensive. Do you ever get the same thing now as a grown-up where you think, “Wouldn’t it be great if I could make a video blog every week”, or “I could podcast once a month about this”, and then you push it to the back of your mind, assuming that you won’t have time or you wouldn’t know what to talk about anyway?
True fact: content doesn’t just have to be produced when we are so incensed that we absolutely must blog about a topic. Neither does it have to be a drain to a demanding schedule. You can plan for it. In fact, you’re about to.
So, today, get a pen and a notebook. Move away from your computer. My gift to you is to grab a quiet ten minutes between turkey sandwiches and relatives visiting and give your site some of the attention it deserves for 2011.
What would you do with your site if you could? I don’t mean what would you do purely visually – although by all means note those things down too – but to your site as a whole. Here are some jumping off points:
Would you like to individually illustrate and design some of your articles?
What about a monthly exploration of your favourite topic through video or audio?
Who would you like to collaborate with?
What do you want your site to be like for a user?
What tone of voice would you like to use?
How could you use imagery and typography to support your content?
What would you like to create content about in the new year?
It’s okay if you can’t do these things yet. It’s okay to scrub out anything where you think, “Nah, never gonna happen.” But do give some thought to what you might want to do next. The best inspiration for this comes from what you’ve already done, so keep on with that inventory.
Bonus gift: a Think Vitamin article on podcasting using Skype, so you can rope in a few friends to join in, too.
On the third day of Contentmas, Relly gave to me:
3. Red pens
Shock news, just in: the web is not print!
One of the hardest things as a writer is to reach the point where you say, “Yeah, okay, that’s it. I’m done” and send off your beloved manuscript or article to print. I’m convinced that if deadlines didn’t exist, nothing would get finished. Why? Well, at the point you hand it over to the publishing presses, you can make no more changes. At best, you can print an erratum or produce an updated second edition at a later date. And writers love to – no, they live to – tweak their creations, so handing them over is quite a struggle. Just one more comma and…
Online, we have no such constraints. We can edit, correct, test, tweak, twiddle until we’re blooming sick of it. Our red pens never run out of ink. It is time for you to run a more critical eye over your content, especially the stuff already published. Relish in the opportunity to change stuff on the fly. I am not so concerned by blog articles and such (although feel free to apply this concept to those, too), but mainly by your more concrete content: about pages; contact pages; home page navigation; portfolio pages; 404 pages.
Now, don’t go running amok with the cut function yet. First, put all these evergreen pages into your inventory. In the notes section, write a quick analysis of how useful this copy is. Example questions:
Is your contact page up-to-date?
Does your about page link to the right places?
Is your portfolio current?
Does your 404 page give people a way to find what they were looking for?
We’ll come back to this in a few days once we have a clearer idea of how to improve our content.
Bonus gift: the audio and slides of a talk I gave on microcopy and 404 pages at @media WebDirections last year.
On the fourth day of Contentmas, Relly gave to me:
4. Stalling nerds
Actually, I guess more accurately this is something I get given a lot. Designers and developers particularly can find a million ways to extract themselves from the content of a site but, as the site owner, and this being your personal playground and all, you mustn’t. You actually can’t, sorry.
But I do understand that at this point, ‘sorting out your site’ suddenly seems a lot less exciting, especially if you are a visually-minded person and words and lists aren’t really your thing. So far, there has been a lot of not-very-exciting exercises in planning, and there’s probably a nice pile of DVDs and video games that you got from Santa worth investigating.
Stay strong my friend. By now, you have probably hit upon an idea of some sort you are itching to start on, so for every half-hour you spend doing inventory, gift yourself another thirty minutes to play with that idea.
Bonus gift: the Pomodoro Technique. Take one kitchen timer and a to-do list and see how far you can go.
On the fifth day of Contentmas, Relly gave to me:
5. Golden rules
Here are some guidelines for writing online:
Make headlines for tutorials and similar content useful and descriptive; use a subheading for any terrible pun you want to work in.
Create a broad opening paragraph that addresses what your article is about. Part of the creative skill in writing is to do this in a way that both informs the reader and captures their attention. If you struggle with this, consider a boxout giving a summary of the article.
Use headings to break up chunks of text and allow people to scan. Most people will have a scoot about an article before starting at the beginning to give it a proper read. These headings should be equal parts informative and enticing. Try them out as questions that might be posed by the reader too.
Finish articles by asking your reader to take an affirmative action: subscribe to your RSS feed; leave a comment (if comments are your thing – more on that later); follow you on Twitter; link you to somewhere they have used your tutorial or code. The web is about getting excited, making things and sharing with others, so give your readers the chance to do that.
For portfolio sites, this call to action is extra important as you want to pick up new business. Encourage people to e-mail you or call you – don’t just rely on a number in the footer or an e-mail link at the top. Think up some consistent calls-to-action you can use and test them out.
So, my gift to you today is a simplified page table for planning out your content to make it as useful as possible.
Feel free to write a new article or tutorial, or work on that great idea from yesterday and try out these guidelines for yourself.
It’s a simple framework – good headline; broad opening; headings to break up volume; strong call to action – but it will help you recognise if what you’ve written is in good shape to face the world. It doesn’t tell you anything about how to create it – that’s your endeavour – but it does give you a start. No more staring at a blank page.
Bonus gift: okay, you have to buy yourself this one, but it is the gift that keeps on giving: Ginny Reddish’s Letting Go of the Words – the hands down best guide to web writing there is, with a ton of illustrative examples.
On the sixth day of Contentmas, Relly gave to me:
6. Foundation-a-laying
Yesterday, we played with a page table for articles. Today, we are going to set the foundations for your new, spangly, spruced up, relaunched site (for when you’re ready, of course). We’ve checked out what we’ve got, we’ve thought about what we’d like, we have a wish list for the future. Now is the time for a small reality check.
Be realistic with yourself. Can you really give your site some attention every day? Record a short snippet of audio once a week? A photo diary post once a month? Look back at the wish list you made.
What can you do?
What can you aim for?
What just isn’t possible right now?
As much as we’d all love to be producing a slick video podcast and screencast three times a week, it’s better to set realistic expectations and work your way up.
Where does your site sit in your online world?
Do you want it to be the hub of all your social interactions, a lifestream, a considered place of publication or a free for all?
Do you want to have comments (do you have the personal resource to monitor comments?) or would you prefer conversation to happen via Twitter, Facebook or not at all?
Does this apply to all pages, posts and content types or just some?
Get these things straight in your head and it’s easier to know what sort of environment you want to create and what content you’ll need to sustain it.
Get your notebook again and think about specific topics you’d like to cover, or aspects of a project you want to go into more, and how you can go ahead and do just that. A good motivator is to think what you’ll get out of doing it, even if that is “And I’ll finally show the poxy $whatever_community that my $chosen_format is better than their $other_format.”
What topics have you really wanted to get off your chest? Look through your inventory again. What gaps are there in your content just begging to be filled?
Today, you’re going to give everyone the gift of your opinion. Find one of those things where someone on the internet is wrong and create a short but snappy piece to set them straight. Doesn’t that feel good? Soon you’ll be able to do this in a timely manner every time someone is wrong on the internet!
Bonus gift: we’re halfway through, so I think something fun is in order. How about a man sledding naked down a hill in Brighton on a tea tray? Sometimes, even with a whole ton of content planning, it’s the spontaneous stuff that is still the most fun to share.
On the seventh day of Contentmas, Relly gave to me:
7. Styles-a-guiding
Not colour style guides or brand style guides or code style guides. Content style guides. You could go completely to town and write yourself a full document defining every aspect of your site’s voice and personality, plus declaring your view on contracted phrases and the Oxford comma, but this does seem a tad excessive. Unless you’re writing an entire site as a fictional character, you probably know your own voice and vocabulary better than anyone. It’s in your head, after all.
Instead, equip yourself with a good global style guide (I like the Chicago Manual of Style because I can access it fully online, but the Associated Press (AP) Stylebook has a nifty iPhone app and, if I’m entirely honest, I’ve found a copy of Eats, Shoots and Leaves has set me right on all but the most technical aspects of punctuation). Next, pick a good dictionary and bookmark thesaurus.com. Then have a go at Kristina Halvorson’s ‘Voice and Tone’ exercise from her book Content Strategy for the Web, to nail down what you’d like your future content to be like:
To introduce the voice and tone qualities you’re [looking to create], a good approach is to offer contrasting values. For example:
Professional, not academic.
Confident, not arrogant.
Clever, not cutesy.
Savvy, not hipster.
Expert, not preachy.
Take a look around some of your favourite sites and examine the writing and stylistic handling of content. What do you like? What do you want to emulate? What matches your values list?
Today’s gift to you is an idea. Create a ‘swipe file’ through Evernote or Delicious and save all the stuff you come across that, regardless of topic, makes you think, “That’s really cool.” This isn’t the same as an Instapaper list you’d like to read. This is stuff you have read or have seen that is worth looking at in closer detail.
Why is it so good?
What is the language and style like?
What impact does the typography have?
How does the imagery work to enhance the message?
This isn’t about creating a personal brand or any such piffle. It’s about learning to recognise how good content works and how to create something awesome yourself. Obviously, your ideas are brilliant, so take the time to understand how best to spring them on the unsuspecting public for easier world domination.
Bonus gift: a nifty style guide is a must when you do have to share content creation duties with others. Here is Leeds University’s publicly available PDF version for you to take a gander at. I especially like the Rationale sections for chopping off dissenters at the knees.
On the eighth day of Contentmas, Relly gave to me:
8. Times-a-making
You have an actual, real plan for what you’d like to do with your site and how it is going to sound (and probably some ideas on how it’s going to look, too). I hope you are full of enthusiasm and Getting Excited To Make Things. Just before we get going and do exactly that, we are going to make sure we have made time for this creative outpouring.
Have you tried to blog once a week before and found yourself losing traction after a month or two? Are there a couple of podcasts lurking neglected in your archives? Whereas half of the act of running is showing up for training, half of creating is making time rather than waiting for it to become urgent. It’s okay to write something and set a date to come back to it (which isn’t the same as leaving it to decompose in your drafts folder).
Putting a date in your calendar to do something for your site means that you have a forewarning to think of a topic to write about, and space in your schedule to actually do it. Crucially, you’ve actually made some time for this content lark.
To do this, you need to think about how long it takes to get something out of the door/shipped/published/whatever you want to call it. It might take you just thirty minutes to record a podcast, but also a further hour to research the topic beforehand and another hour to edit and upload the clips. Suddenly, doing a thirty minute podcast every day seems a bit unlikely. But, on the flipside, it is easy to see how you could schedule that in three chunks weekly.
Put it in your calendar. Do it, publish it, book yourself in for the next week. Keep turning up.
Today my gift to you is the gift of time. Set up your own small content calendar, using your favourite calendar system, and schedule time to play with new ways of creating content, time to get it finished and time to get it on your site. Don’t let good stuff go to your drafts folder to die of neglect.
Bonus gift: lots of writers swear by the concept of ‘daily pages’. That is, churning out whatever is in your head to see if there is anything worth building upon, or just to lose the grocery list getting in the way. 750words.com is a site built around this concept. Go have a play.
On the ninth day of Contentmas, Relly gave to me:
9. Copy enhancing
An incredibly radical idea for day number nine. We are going to look at that list of permanent pages you made back on day three and rewrite the words first, before even looking at a colour palette or picking a font! Crazy as it sounds, doing it this way round could influence your design. It could shape the imagery you use. It could affect your choice of typography. IMAGINE THE POSSIBILITIES!
Look at the page table from day five. Print out one for each of your homepage, about page, contact page, portfolio, archive, 404 page or whatever else you have. Use these as a place to brainstorm your ideas and what you’d like each page to do for your site. Doodle in the margin, choose words you think sound fun to say, daydream about pictures you’d like to use and colours you think would work, but absolutely, completely and utterly fill in those page tables to understand how much (or how little) content you’re playing with and what you need to do to get to ‘launch’.
Then, use them for guidance as you start to write. Don’t skimp. Don’t think that a fancy icon of an envelope encourages people to e-mail you. Use your words.
People get antsy at this bit. Writing can be hard work and it’s easy for me to say, “Go on and write it then!” I know this. I mean, you should see the faces I pull when I have to do anything related to coding. The closest equivalent would be when scientists have to stick their hands in big gloves attached to a glass box to do dangerous experiments.
Here’s today’s gift, a little something about writing that I hope brings you comfort:
To write something fantastic you almost always have to write a rubbish draft first.
Now, you might get lucky and write a ‘good enough’ draft first time and that’s fab – you’ve cut some time getting to ‘fantastic’. If, however, you’ve always looked at your first attempt to write more than the bare minimum and sighed in despair, and resigned yourself to adding just a title, date and a screenshot, be cheered because you have taken the first step to being able to communicate with clarity, wit and panache.
Keep going. Look at writing you admire and emulate it. Think about how you will lovingly design those words when they are done. Know that you can go back and change them. Check back with your page table to keep you on track. Do that first draft.
Bonus gift: becoming a better writer helps you to explain design concepts to clients.
On the tenth day of Contentmas, Relly gave to me:
10. Ideas for keeping
Hurrah! You have something down on paper, ready to start evolving your site around it. Here’s where the words and visuals and interaction start to come together. Because you have a plan, you can think ahead and do things you wouldn’t be able to pull together otherwise.
How about finding a fresh-faced stellar illustrator on Dribbble to create you something perfect to pep up your contact page or visualize your witty statement on statements of work. A List Apart has been doing it for years and it hasn’t worked out too badly for them, has it?
What about spending this month creating a series of introductory tutorials on a topic, complete with screencasts and audio and give them a special home on your site?
How about putting in some hours creating a glorious about me page, with a biography, nice picture, and where you spend your time online?
You could even do the web equivalent of getting up in the attic and sorting out your site’s search to make it easier to find things in your archives. Maybe even do some manual recommendations for relevant content and add them as calls to action.
How about writing a few awesome case studies with individual screenshots of your favourite work, and creating a portfolio that plays to your strengths? Don’t just rely on the pretty pictures; use your words. Otherwise no-one understands why things are the way they are on that screenshot and BAM! you’ll be judged on someone else’s tastes. (Elliot has a head start on you for this, so get to it!)
Do you have a serious archive of content? What’s it like being a first-time visitor to your site? Could you write them a guide to introduce yourself and some of the most popular stuff on your site? Ali Edwards is a massively popular crafter and every day she gets new visitors who have found her multiple papercraft projects on Flickr, Vimeo and elsewhere, so she created a welcome guide just for them.
What about your microcopy? Can you improve on your blogging platform’s defaults for search, comment submission and labels? I’ll bet you can.
Maybe you could plan a collaboration with other like-minded souls. A week of posts about the more advanced wonders of HTML5 video. A month-long baton-passing exercise in extolling the virtues of IE (shut up, it could happen!). Just spare me any more online advent calendars.
Watch David McCandless’s TED talk on his jawdropping infographic work and make something as awesome as the Billion Dollar O Gram. I dare you.
Bonus gift: Grab a copy of Brian Suda’s Designing with Data, in print or PDF if Santa didn’t put one in your stocking, and make that awesome something with some expert guidance.
On the eleventh day of Contentmas, Relly gave to me:
11. Pixels pushing
Oh, go on then. Make a gorgeous bespoke velvet-lined container for all that lovely content. It’s proper informed design now, not just decoration. Mr. Zeldman says so.
Bonus gift: I made you a movie! If books were designed like websites.
On the twelfth day of Contentmas, Relly gave to me:
12. Delighters delighting
The Epiphany is upon us; your site is now well on its way to being a beautiful, sustainable hub of content and you have a date in your calendar to help you keep that resolution of blogging more. What now?
Keep on top of your inventory. One day it will save your butt, I promise.
Keep making a little bit of time regularly to create something new: an article; an opinion piece; a small curation of related links; a photo diary; a new case study. That’s easier than an annual content bootcamp for sure.
And today’s gift: look for ways to play with that content and make something a bit special. Stretch yourself a little. It’ll be worth it.
Bonus gift: Paul Annett’s presentation on Ooh, that’s clever: Delighters in design from SxSW 09.
All my favourite designers and developers have their own unique styles and touches. It’s what sets them apart. My very, very favourites have an eloquence and expression that they bring to their sites and to their projects. I absolutely love to explore a well-crafted, well-written site – don’t we all? I know the time it takes. I appreciate the time it takes. But the end results are delicious. Do please share your spangly, refreshed sites with me in the comments.
Catch me on Twitter, I’m @RellyAB, and I’ve been your host for these Twelve Days of Contentmas. |
2010 |
Relly Annett-Baker |
rellyannettbaker |
2010-12-21T00:00:00+00:00 |
https://24ways.org/2010/a-contentmas-epiphany/ |
content |
251 |
The System, the Search, and the Food Bank |
Imagine a warehouse, half the length of a football field, with a looped conveyer belt down the center.
On the belt are plastic bins filled with assortments of shelf-stable food—one may have two bags of potato chips, seventeen pudding cups, and a box of tissues; the next, a dozen cans of beets. The conveyer belt is ringed with large, empty cardboard boxes, each labeled with categories like “Bottled Water” or “Cereal” or “Candy.”
Such was the scene at my local food bank a few Saturdays ago, when some friends and I volunteered for a shift sorting donated food items. Our job was to fill the labeled cardboard boxes with the correct items nabbed from the swiftly moving, randomly stocked plastic bins.
I could scarcely believe my good fortune of assignments. You want me to sort things? Into categories? For several hours? And you say there’s an element of time pressure? Listen, is there some sort of permanent position I could be conscripted into.
Look, I can’t quite explain it: I just know that I love sorting, organizing, and classifying things—groceries at a food bank, but also my bookshelves, my kitchen cabinets, my craft supplies, my dishwasher arrangement, yes I am a delight to live with, why do you ask?
The opportunity to create meaning from nothing is at the core of my excitement, which is why I’ve tried to build a career out of organizing digital content, and why I brought a frankly frightening level of enthusiasm to the food bank. “I can’t believe they’re letting me do this,” I whispered in awe to my conveyer belt neighbor as I snapped up a bag of popcorn for the Snacks box with the kind of ferocity usually associated with birds of prey.
The jumble of donated items coming into the center need to be sorted in order for the food bank to be able to quantify, package, and distribute the food to those who need it (I sense a metaphor coming on). It’s not just a nice-to-have that we spent our morning separating cookies from carrots—it’s a crucial step in the process. Organization makes the difference between chaos and sense, between randomness and usefulness, whether we’re talking about donated groceries or—there it is—web content.
This happens through the magic of criteria matching. In order for us to sort the food bank donations correctly, we needed to know not only the categories we were sorting into, but also the criteria for each category. Does canned ravioli count as Canned Soup? Does enchilada sauce count as Tomatoes? Do protein bars count as Snacks? (Answers: yes, yes, and only if they are under 10 grams of protein or will expire within three months.)
Is X a Y? was the question at the heart of our food sorting—but it’s also at the heart of any information-seeking behavior. When we are organizing, or looking for, any kind of information, we are asking ourselves:
What is the criteria that defines Y?
Does X meet that criteria?
We don’t usually articulate it so concretely because it’s a background process, only leaping to consciousness when we encounter a stumbling block. If cans of broth flew by on the conveyer belt, it didn’t require much thought to place them in the Canned Soup box. Boxed broth, on the other hand, wasn’t allowed, causing a small cognitive hiccup—this X is NOT a Y—that sometimes meant having to re-sort our boxes.
On the web, we’re interested—I would hope—in reducing cognitive hiccups for our users. We are interested in making our apps easy to use, our websites easy to navigate, our information easy to access. After all, most of the time, the process of using the internet is one of uniting a question with an answer—Is this article from a trustworthy source? Is this clothing the style I want? Is this company paying their workers a living wage? Is this website one that can answer my question? Is X a Y?
We have a responsibility, therefore, to make information easy for our users to find, understand, and act on. This means—well, this means a lot of things, and I’ve got limited space here, so let’s focus on these three lessons from the food bank:
Use plain, familiar language. This advice seems to be given constantly, but that’s because it’s solid and it’s not followed enough. Your menu labels, page names, and headings need to reflect the word choice of your users. Think how much harder it would have been to sort food if the boxes were labeled according to nutritional content, grocery store aisle number, or Latin name. How much would it slow sorting down if the Tomatoes box were labeled Nightshades? It sounds silly, but it’s not that different from sites that use industry jargon, company lingo, acronyms (oh, yes, I’ve seen it), or other internally focused language when trying to provide wayfinding for users. Choose words that your audience knows—not only will they be more likely to spot what they’re looking for on your site or app, but you’ll turn up more often in search results.
Create consistency in all things. Missteps in consistency look like my earlier chicken broth example—changing up how something looks, sounds, or functions creates a moment of cognitive dissonance, and those moments add up. The names of products, the names of brands, the names of files and forms and pages, the names of processes and procedures and concepts—these all need to be consistently spelled, punctuated, linked, and referenced, no matter what section or level the user is in. If submenus are visible in one section, they should be visible in all. If calls-to-action are a graphic button in one section, they are the same graphic button in all. Every affordance, every module, every design choice sets up user expectations; consistency keeps those expectations afloat, making for a smoother experience overall.
Make the system transparent. By this, I do not mean that every piece of content should be elevated at all times. The horror. But I do mean that we should make an effort to communicate the boundaries of the digital space from any given corner within. Navigation structures operate just as much as a table of contents as they do a method of moving from one place to another. Page hierarchies help explain content relationships, communicating conceptual relevancy and relative importance. Submenus illustrate which related concepts may be found within a given site section. Take care to show information that conveys the depth and breadth of the system, rather than obscuring it.
This idea of transparency was perhaps the biggest challenge we experienced in food sorting. Imagine us volunteers as users, each looking for a specific piece of information in the larger system. Like any new visitor to a website, we came into the system not knowing the full picture. We didn’t know every category label around the conveyer belt, nor what criteria each category warranted.
The system wasn’t transparent for us, so we had to make it transparent as we went. We had to stop what we were doing and ask questions. We’d ask staff members. We’d ask more seasoned volunteers. We’d ask each other. We’d make guesses, and guess wrongly, and mess up the boxes, and correct our mistakes, and learn.
The more we learned, the easier the sorting became. That is, we were able to sort more quickly, more efficiently, more accurately. The better we understood the system, the better we were at interacting with it.
The same is true of our users: the better they understand digital spaces, the more effective they are at using them. But visitors to our apps and websites do not have the luxury of learning the whole system. The fumbling trial-and-error method that I used at the food bank can, on a website, drive users away—or, worse, misinform or hurt them.
This is why we must make choices that prioritize transparency, consistency, and familiarity. Our users want to know if X is a Y—well-sorted content can give them the answer. |
2018 |
Lisa Maria Martin |
lisamariamartin |
2018-12-16T00:00:00+00:00 |
https://24ways.org/2018/the-system-the-search-and-the-food-bank/ |
content |
252 |
Turn Jekyll up to Eleventy |
Sometimes it pays not to over complicate things. While many of the sites we use on a daily basis require relational databases to manage their content and dynamic pages to respond to user input, for smaller, simpler sites, serving pre-rendered static HTML is usually a much cheaper — and more secure — option.
The JAMstack (JavaScript, reusable APIs, and prebuilt Markup) is a popular marketing term for this way of building websites, but in some ways it’s a return to how things were in the early days of the web, before developers started tinkering with CGI scripts or Personal HomePage. Indeed, my website has always served pre-rendered HTML; first with the aid of Movable Type and more recently using Jekyll, which Anna wrote about in 2013.
By combining three approachable languages — Markdown for content, YAML for data and Liquid for templating — the ergonomics of Jekyll found broad appeal, influencing the design of the many static site generators that followed. But Jekyll is not without its faults. Aside from notoriously slow build times, it’s also built using Ruby. While this is an elegant programming language, it is yet another ecosystem to understand and manage, and often alongside one we already use: JavaScript. For all my time using Jekyll, I would think to myself “this, but in Node”. Thankfully, one of Santa’s elves (Zach Leatherman) granted my Atwoodian wish and placed such a static site generator under my tree.
Introducing Eleventy
Eleventy is a more flexible alternative Jekyll. Besides being written in Node, it’s less strict about how to organise files and, in addition to Liquid, supports other templating languages like EJS, Pug, Handlebars and Nunjucks. Best of all, its build times are significantly faster (with future optimisations promising further gains).
As content is saved using the familiar combination of YAML front matter and Markdown, transitioning from Jekyll to Eleventy may seem like a reasonable idea. Yet as I’ve discovered, there are a few gotchas. If you’ve been considering making the switch, here are a few tips and tricks to help you on your way1.
Note: Throughout this article, I’ll be converting Matt Cone’s Markdown Guide site as an example. If you want to follow along, start by cloning the git repository, and then change into the project directory:
git clone https://github.com/mattcone/markdown-guide.git
cd markdown-guide
Before you start
If you’ve used tools like Grunt, Gulp or Webpack, you’ll be familiar with Node.js but, if you’ve been exclusively using Jekyll to compile your assets as well as generate your HTML, now’s the time to install Node.js and set up your project to work with its package manager, NPM:
Install Node.js:
Mac: If you haven’t already, I recommend installing Homebrew, a package manager for the Mac. Then in the Terminal type brew install node.
Windows: Download the Windows installer from the Node.js website and follow the instructions.
Initiate NPM: Ensure you are in the directory of your project and then type npm init. This command will ask you a few questions before creating a file called package.json. Like RubyGems’s Gemfile, this file contains a list of your project’s third-party dependencies.
If you’re managing your site with Git, make sure to add node_modules to your .gitignore file too. Unlike RubyGems, NPM stores its dependencies alongside your project files. This folder can get quite large, and as it contains binaries compiled to work with the host computer, it shouldn’t be version controlled. Eleventy will also honour the contents of this file, meaning anything you want Git to ignore, Eleventy will ignore too.
Installing Eleventy
With Node.js installed and your project setup to work with NPM, we can now install Eleventy as a dependency:
npm install --save-dev @11ty/eleventy
If you open package.json you should see the following:
…
"devDependencies": {
"@11ty/eleventy": "^0.6.0"
}
…
We can now run Eleventy from the command line using NPM’s npx command. For example, to covert the README.md file to HTML, we can run the following:
npx eleventy --input=README.md --formats=md
This command will generate a rendered HTML file at _site/README/index.html. Like Jekyll, Eleventy shares the same default name for its output directory (_site), a pattern we will see repeatedly during the transition.
Configuration
Whereas Jekyll uses the declarative YAML syntax for its configuration file, Eleventy uses JavaScript. This allows its options to be scripted, enabling some powerful possibilities as we’ll see later on.
We’ll start by creating our configuration file (.eleventy.js), copying the relevant settings in _config.yml over to their equivalent options:
module.exports = function(eleventyConfig) {
return {
dir: {
input: "./", // Equivalent to Jekyll's source property
output: "./_site" // Equivalent to Jekyll's destination property
}
};
};
A few other things to bear in mind:
Whereas Jekyll allows you to list folders and files to ignore under its exclude property, Eleventy looks for these values inside a file called .eleventyignore (in addition to .gitignore).
By default, Eleventy uses markdown-it to parse Markdown. If your content uses advanced syntax features (such as abbreviations, definition lists and footnotes), you’ll need to pass Eleventy an instance of this (or another) Markdown library configured with the relevant options and plugins.
Layouts
One area Eleventy currently lacks flexibility is the location of layouts, which must reside within the _includes directory (see this issue on GitHub).
Wanting to keep our layouts together, we’ll move them from _layouts to _includes/layouts, and then update references to incorporate the layouts sub-folder. We could update the layout: frontmatter property in each of our content files, but another option is to create aliases in Eleventy’s config:
module.exports = function(eleventyConfig) {
// Aliases are in relation to the _includes folder
eleventyConfig.addLayoutAlias('about', 'layouts/about.html');
eleventyConfig.addLayoutAlias('book', 'layouts/book.html');
eleventyConfig.addLayoutAlias('default', 'layouts/default.html');
return {
dir: {
input: "./",
output: "./_site"
}
};
}
Determining which template language to use
Eleventy will transform Markdown (.md) files using Liquid by default, but we’ll need to tell Eleventy how to process other files that are using Liquid templates. There are a few ways to achieve this, but the easiest is to use file extensions. In our case, we have some files in our api folder that we want to process with Liquid and output as JSON. By appending the .liquid file extension (i.e. basic-syntax.json becomes basic-syntax.json.liquid), Eleventy will know what to do.
Variables
On the surface, Jekyll and Eleventy appear broadly similar, but as each models its content and data a little differently, some template variables will need updating.
Site variables
Alongside build settings, Jekyll let’s you store common values in its configuration file which can be accessed in our templates via the site.* namespace. For example, in our Markdown Guide, we have the following values:
title: "Markdown Guide"
url: https://www.markdownguide.org
baseurl: ""
repo: http://github.com/mattcone/markdown-guide
comments: false
author:
name: "Matt Cone"
og_locale: "en_US"
Eleventy’s configuration uses JavaScript which is not suited to storing values like this. However, like Jekyll, we can use data files to store common values. If we add our site-wide values to a JSON file inside a folder called _data and name this file site.json, we can keep the site.* namespace and leave our variables unchanged.
{
"title": "Markdown Guide",
"url": "https://www.markdownguide.org",
"baseurl": "",
"repo": "http://github.com/mattcone/markdown-guide",
"comments": false,
"author": {
"name": "Matt Cone"
},
"og_locale": "en_US"
}
Page variables
The table below shows a mapping of common page variables. As a rule, frontmatter properties are accessed directly, whereas derived metadata values (things like URLs, dates etc.) get prefixed with the page.* namespace:
Jekyll
Eleventy
page.url
page.url
page.date
page.date
page.path
page.inputPath
page.id
page.outputPath
page.name
page.fileSlug
page.content
content
page.title
title
page.foobar
foobar
When iterating through pages, frontmatter values are available via the data object while content is available via templateContent:
Jekyll
Eleventy
item.url
item.url
item.date
item.date
item.path
item.inputPath
item.name
item.fileSlug
item.id
item.outputPath
item.content
item.templateContent
item.title
item.data.title
item.foobar
item.data.foobar
Ideally the discrepancy between page and item variables will change in a future version (see this GitHub issue), making it easier to understand the way Eleventy structures its data.
Pagination variables
Whereas Jekyll’s pagination feature is limited to paginating posts on one page, Eleventy allows you to paginate any collection of documents or data. Given this disparity, the changes to pagination are more significant, but this table shows a mapping of equivalent variables:
Jekyll
Eleventy
paginator.page
pagination.pageNumber
paginator.per_page
pagination.size
paginator.posts
pagination.items
paginator.previous_page_path
pagination.previousPageHref
paginator.next_page_path
pagination.nextPageHref
Filters
Although Jekyll uses Liquid, it provides a set of filters that are not part of the core Liquid library. There are quite a few — more than can be covered by this article — but you can replicate them by using Eleventy’s addFilter configuration option. Let’s convert two used by our Markdown Guide: jsonify and where.
The jsonify filter outputs an object or string as valid JSON. As JavaScript provides a native JSON method, we can use this in our replacement filter. addFilter takes two arguments; the first is the name of the filter and the second is the function to which we will pass the content we want to transform:
// {{ variable | jsonify }}
eleventyConfig.addFilter('jsonify', function (variable) {
return JSON.stringify(variable);
});
Jekyll’s where filter is a little more complicated in that it takes two additional arguments: the key to look for, and the value it should match:
{{ site.members | where: "graduation_year","2014" }}
To account for this, instead of passing one value to the second argument of addFilter, we can instead pass three: the array we want to examine, the key we want to look for and the value it should match:
// {{ array | where: key,value }}
eleventyConfig.addFilter('where', function (array, key, value) {
return array.filter(item => {
const keys = key.split('.');
const reducedKey = keys.reduce((object, key) => {
return object[key];
}, item);
return (reducedKey === value ? item : false);
});
});
There’s quite a bit going on within this filter, but I’ll try to explain. Essentially we’re examining each item in our array, reducing key (passed as a string using dot notation) so that it can be parsed correctly (as an object reference) before comparing its value to value. If it matches, item remains in the returned array, else it’s removed. Phew!
Includes
As with filters, Jekyll provides a set of tags that aren’t strictly part of Liquid either. This includes one of the most useful, the include tag. LiquidJS, the library Eleventy uses, does provide an include tag, but one using the slightly different syntax defined by Shopify. If you’re not passing variables to your includes, everything should work without modification. Otherwise, note that whereas with Jekyll you would do this:
<!-- page.html -->
{% include include.html value="key" %}
<!-- include.html -->
{{ include.value }}
in Eleventy, you would do this:
<!-- page.html -->
{% include "include.html", value: "key" %}
<!-- include.html -->
{{ value }}
A downside of Shopify’s syntax is that variable assignments are no longer scoped to the include and can therefore leak; keep this in mind when converting your templates as you may need to make further adjustments.
Tweaking Liquid
You may have noticed in the above example that LiquidJS expects the names of included files to be quoted (else it treats them as variables). We could update our templates to add quotes around file names (the recommended approach), but we could also disable this behaviour by setting LiquidJS’s dynamicPartials option to false. Additionally, Eleventy doesn’t support the include_relative tag, meaning you can’t include files relative to the current document. However, LiquidJS does let us define multiple paths to look for included files via its root option.
Thankfully, Eleventy allows us to pass options to LiquidJS:
eleventyConfig.setLiquidOptions({
dynamicPartials: false,
root: [
'_includes',
'.'
]
});
Collections
Jekyll’s collections feature lets authors create arbitrary collections of documents beyond pages and posts. Eleventy provides a similar feature, but in a far more powerful way.
Collections in Jekyll
In Jekyll, creating collections requires you to add the name of your collections to _config.yml and create corresponding folders in your project. Our Markdown Guide has two collections:
collections:
- basic-syntax
- extended-syntax
These correspond to the folders _basic-syntax and _extended-syntax whose content we can iterate over like so:
{% for syntax in site.extended-syntax %}
{{ syntax.title }}
{% endfor %}
Collections in Eleventy
There are two ways you can set up collections in 11ty. The first, and most straightforward, is to use the tag property in content files:
---
title: Strikethrough
syntax-id: strikethrough
syntax-summary: "~~The world is flat.~~"
tag: extended-syntax
---
We can then iterate over tagged content like this:
{% for syntax in collections.extended-syntax %}
{{ syntax.data.title }}
{% endfor %}
Eleventy also allows us to configure collections programmatically. For example, instead of using tags, we can search for files using a glob pattern (a way of specifying a set of filenames to search for using wildcard characters):
eleventyConfig.addCollection('basic-syntax', collection => {
return collection.getFilteredByGlob('_basic-syntax/*.md');
});
eleventyConfig.addCollection('extended-syntax', collection => {
return collection.getFilteredByGlob('_extended-syntax/*.md');
});
We can extend this further. For example, say we wanted to sort a collection by the display_order property in our document’s frontmatter. We could take the results of collection.getFilteredByGlob and then use JavaScript’s sort method to sort the result:
eleventyConfig.addCollection('example', collection => {
return collection.getFilteredByGlob('_examples/*.md').sort((a, b) => {
return a.data.display_order - b.data.display_order;
});
});
Hopefully, this gives you just a hint of what’s possible using this approach.
Using directory data to manage defaults
By default, Eleventy will maintain the structure of your content files when generating your site. In our case, that means /_basic-syntax/lists.md is generated as /_basic-syntax/lists/index.html. Like Jekyll, we can change where files are saved using the permalink property. For example, if we want the URL for this page to be /basic-syntax/lists.html we can add the following:
---
title: Lists
syntax-id: lists
api: "no"
permalink: /basic-syntax/lists.html
---
Again, this is probably not something we want to manage on a file-by-file basis but again, Eleventy has features that can help: directory data and permalink variables.
For example, to achieve the above for all content stored in the _basic-syntax folder, we can create a JSON file that shares the name of that folder and sits inside it, i.e. _basic-syntax/_basic-syntax.json and set our default values. For permalinks, we can use Liquid templating to construct our desired path:
{
"layout": "syntax",
"tag": "basic-syntax",
"permalink": "basic-syntax/{{ title | slug }}.html"
}
However, Markdown Guide doesn’t publish syntax examples at individual permanent URLs, it merely uses content files to store data. So let’s change things around a little. No longer tied to Jekyll’s rules about where collection folders should be saved and how they should be labelled, we’ll move them into a folder called _content:
markdown-guide
└── _content
├── basic-syntax
├── extended-syntax
├── getting-started
└── _content.json
We will also add a directory data file (_content.json) inside this folder. As directory data is applied recursively, setting permalink to false will mean all content in this folder and its children will no longer be published:
{
"permalink": false
}
Static files
Eleventy only transforms files whose template language it’s familiar with. But often we may have static assets that don’t need converting, but do need copying to the destination directory. For this, we can use pass-through file copy. In our configuration file, we tell Eleventy what folders/files to copy with the addPassthroughCopy option. Then in the return statement, we enable this feature by setting passthroughFileCopy to true:
module.exports = function(eleventyConfig) {
…
// Copy the `assets` directory to the compiled site folder
eleventyConfig.addPassthroughCopy('assets');
return {
dir: {
input: "./",
output: "./_site"
},
passthroughFileCopy: true
};
}
Final considerations
Assets
Unlike Jekyll, Eleventy provides no support for asset compilation or bundling scripts — we have plenty of choices in that department already. If you’ve been using Jekyll to compile Sass files into CSS, or CoffeeScript into Javascript, you will need to research alternative options, options which are beyond the scope of this article, sadly.
Publishing to GitHub Pages
One of the benefits of Jekyll is its deep integration with GitHub Pages. To publish an Eleventy generated site — or any site not built with Jekyll — to GitHub Pages can be quite involved, but typically involves copying the generated site to the gh-pages branch or including that branch as a submodule. Alternatively, you could use a continuous integration service like Travis or CircleCI and push the generated site to your web server. It’s enough to make your head spin! Perhaps for this reason, a number of specialised static site hosts have emerged such as Netlify and Google Firebase. But remember; you can publish a static site almost anywhere!
Going one louder
If you’ve been considering making the switch, I hope this brief overview has been helpful. But it also serves as a reminder why it can be prudent to avoid jumping aboard bandwagons.
While it’s fun to try new software and emerging technologies, doing so can require a lot of work and compromise. For all of Eleventy’s appeal, it’s only a year old so has little in the way of an ecosystem of plugins or themes. It also only has one maintainer. Jekyll on the other hand is a mature project with a large community of maintainers and contributors supporting it.
I moved my site to Eleventy because the slowness and inflexibility of Jekyll was preventing me from doing the things I wanted to do. But I also had time to invest in the transition. After reading this guide, and considering the specific requirements of your project, you may decide to stick with Jekyll, especially if the output will essentially stay the same. And that’s perfectly fine!
But these go to 11.
Information provided is correct as of Eleventy v0.6.0 and Jekyll v3.8.5 ↩ |
2018 |
Paul Lloyd |
paulrobertlloyd |
2018-12-11T00:00:00+00:00 |
https://24ways.org/2018/turn-jekyll-up-to-eleventy/ |
content |
275 |
Context First: Web Strategy in Four Handy Ws |
Many, many years ago, before web design became my proper job, I trained and worked as a journalist. I studied publishing in London and spent three fun years learning how to take a few little nuggets of information and turn them into a story. I learned a bunch of stuff that has all been a huge help to my design career. Flatplanning, layout, typographic theory. All of these disciplines have since translated really well to web design, but without doubt the most useful thing I learned was how to ask difficult questions.
Pretty much from day one of journalism school they hammer into you the importance of the Five Ws. Five disarmingly simple lines of enquiry that eloquently manage to provide the meat of any decent story. And with alliteration thrown in too. For a young journo, it’s almost too good to be true.
Who? What? Where? When? Why? It seems so obvious to almost be trite but, fundamentally, any story that manages to answer those questions for the reader is doing a pretty good job. You’ll probably have noticed feeling underwhelmed by certain news pieces in the past – disappointed, like something was missing. Some irritating oversight that really lets the story down. No doubt it was one of the Ws – those innocuous little suckers are generally only noticeable by their absence, but they sure get missed when they’re not there.
Question everything
I’ve always been curious. An inveterate tinkerer with things and asker of dopey questions, often to the point of abject annoyance for anyone unfortunate enough to have ended up in my line of fire. So, naturally, the Five Ws started drifting into other areas of my life. I’d scrutinize everything, trying to justify or explain my rationale using these Ws, but I’d also find myself ripping apart the stuff that clearly couldn’t justify itself against the same criteria.
So when I started working as a designer I applied the same logic and, sure enough, the Ws pretty much mapped to the exact same needs we had for gathering requirements at the start of a project. It seemed so obvious, such a simple way to establish the purpose of a product. What was it for? Why we were making it? And, of course, who were we making it for? It forced clients to stop and think, when really what they wanted was to get going and see something shiny. Sometimes that was a tricky conversation to have, but it’s no coincidence that those who got it also understood the value of strategy and went on to have good solid products, while those that didn’t often ended up with arrogantly insular and very shiny but ultimately unsatisfying and expendable products. Empty vessels make the most noise and all that…
Content first
I was both surprised and pleased when the whole content first idea started to rear its head a couple of years back. Pleased, because without doubt it’s absolutely the right way to work. And surprised, because personally it’s always been the way I’ve done it – I wasn’t aware there was even an alternative way. Content in some form or another is the whole reason we were making the things we were making. I can’t even imagine how you’d start figuring out what a site needs to do, how it should be structured, or how it should look without a really good idea of what that content might be. It baffles me still that this was somehow news to a lot of people. What on earth were they doing? Design without purpose is just folly, surely?
It’s great to see the idea gaining momentum but, having watched it unfold, it occurred to me recently that although it’s fantastic to see a tangible shift in thinking – away from those bleak times, where making things up was somehow deemed an appropriate way to do things – there’s now a new bad guy in town.
With any buzzword solution of the moment, there’s always a catch, and it seems like some have taken the content first approach a little too literally. By which I mean, it’s literally the first thing they do. The project starts, there’s a very cursory nod towards gathering requirements, and off they go, cranking content. Writing copy, making video, commissioning illustrations.
All that’s happened is that the ‘making stuff up’ part has shifted along the line, away from layout and UI, back to the content.
Starting is too easy
I can’t remember where I first heard that phrase, but it’s a great sentiment which applies to so much of what we do on the web. The medium is so accessible and to an extent disposable; throwing things together quickly carries far less burden than in any other industry. We’re used to tweaking as we go, changing bits, iterating things into shape. The ubiquitous beta tag has become the ultimate caveat, and has made the unfinished and unpolished acceptable. Of course, that can work brilliantly in some circumstances. Occasionally, a product offers such a paradigm shift it’s beyond the level of deep planning and prelaunch finessing we’d ideally like. But, in the main, for most client sites we work on, there really is no excuse not to do things properly. To ask the tricky questions, to challenge preconceptions and really understand the Ws behind the products we’re making before we even start.
The four Ws
For product definition, only four of the five Ws really apply, although there’s a lot of discussion around the idea of when being an influencing factor. For example, the context of a user’s engagement with your product is something you can make a call on depending on the specifics of the project.
So, here’s my take on the four essential Ws. I’ll point out here that, of course, these are not intended to be autocratic dictums. Your needs may differ, your clients’ needs may differ, but these four starting points will get you pretty close to where you need to be.
Who
It’s surprising just how many projects start without a real understanding of the intended audience. Many clients think they have an idea, but without really knowing – it’s presumptive at best, and we all know what presumption is the mother of, right? Of course, we can’t know our audiences in the same way a small shop owner might know their customers. But we can at least strive to find out what type of people are likely to be using the product. I’m not talking about deep user research. That should come later.
These are the absolute basics. What’s the context for their visit? How informed are they? What’s their level of comprehension? Are they able to self-identify and relate to categories you have created? I could go on, and it changes on a per-project basis. You’ll only find this out by speaking to them, if not in person, then indirectly through surveys, questionnaires or polls. The mechanism is less important than actually reaching out and engaging with them, because without that understanding it’s impossible to start to design with any empathy.
What
Once you become deeply involved directly with a product or service, it’s notoriously difficult to see things as an outsider would. You learn the thing inside and out, you develop shortcuts and internal phraseology. Colloquialisms creep in. You become too close. So it’s no surprise when clients sometimes struggle to explain what it is their product actually does in a way that others can understand.
Often products are complex but, really, the core reasons behind someone wanting to use that product are very simple. There’s a value proposition for the customer and, if they choose to engage with it, there’s a value exchange. If that proposition or exchange isn’t transparent, then people become confused and will likely go elsewhere. Make sure both your client and you really understand what that proposition is and, in turn, what the expected exchange should be. In a nutshell: what is the intended outcome of that engagement? Often the best way to do this is strip everything back to nothing. Verbosity is rife on the web. Just because it’s easy to create content, that shouldn’t be a reason to do so. Figure out what the value proposition is and then reintroduce content elements that genuinely help explain or present that to a level that is appropriate for the audience.
Why
In advertising, they talk about the truths behind a product or service. Truths can be both tangible or abstract, but the most important part is the resonance those truths hit with a customer. In a digital product or service those truths are often exposed as benefits. Why is this what I need? Why will it work for me? Why should I trust you? The why is one of the more fluffy Ws, yet it’s such an important one to nail. Clients can get prickly when you ask them to justify the why behind their product, but it’s a fantastic way to make sure the value proposition is clear, realistic and meets with the expectations of both client and customer.
It’s our job as designers to question things: we’re not just a pair of hands for clients. Just recently I spoke to a potential client about a site for his business. I asked him why people would use his product and also why his product seemed so fractured in its direction. He couldnt answer that question so, instead of ploughing on regardless, he went back to his directors and is now re-evaluating that business. It was awkward but he thanked me and hopefully he’ll have a better product as a result.
Where
In this instance, where is not so much a geographical thing, although in some cases that level of context may indeed become a influencing factor… The where we’re talking about here is the position of the product in relation to others around it. By looking at competitors or similar services around the one you are designing, you can start to get a sense for many of the things that are otherwise hard to pin down or have yet to be defined. For example, in a collection of sites all selling cars, where does yours fit most closely? Where are the overlaps? How are they communicating to their customers? How is the product range presented or categorized?
It’s good to look around and see how others are doing it. Not in a quest for homogeneity but more to reference or to avoid certain patterns that may or may not make sense for your own particular product. Clients often strive to be different for the sake of it. They feel they need to provide distinction by going against the flow a bit. We know different. We know users love convention. They embrace familiar mental models. They’re comfortable with things that they’ve experienced elsewhere. By showing your client that position is a vital part of their strategy, you can help shape their product into something great.
To conclude
So there we have it – the four Ws. Each part tells a different and vital part of the story you need to be able to make a really good product. It might sound like a lot of work, particularly when the client is breathing down your neck expecting to see things, but without those pieces in place, the story you’re building your product on, and the content that you’re creating to form that product can only ever fit into one genre. Fiction. |
2011 |
Alex Morris |
alexmorris |
2011-12-10T00:00:00+00:00 |
https://24ways.org/2011/context-first/ |
content |
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 |
291 |
Information Literacy Is a Design Problem |
Information literacy, wrote Dr. Carol Kulthau in her 1987 paper “Information Skills for an Information Society,” is “the ability to read and to use information essential for everyday life”—that is, to effectively navigate a world built on “complex masses of information generated by computers and mass media.”
Nearly thirty years later, those “complex masses of information” have only grown wilder, thornier, and more constant. We call the internet a firehose, yet we’re loathe to turn it off (or even down). The amount of information we consume daily is staggering—and yet our ability to fully understand it all remains frustratingly insufficient.
This should hit a very particular chord for those of us working on the web. We may be developers, designers, or strategists—we may not always be responsible for the words themselves—but we all know that communication is much more than just words. From fonts to form fields, every design decision that we make changes the way information is perceived—for better or for worse.
What’s more, the design decisions that we make feed into larger patterns. They don’t just affect the perception of a single piece of information on a single site; they start to shape reader expectations of information anywhere. Users develop cumulative mental models of how websites should be: where to find a search bar, where to look at contact information, how to filter a product list.
And yet: our models fail us. Fundamentally, we’re not good at parsing information, and that’s troubling. Our experience of an “information society” may have evolved, but the skills Dr. Kuhlthau spoke of are even more critical now: our lives depend on information literacy.
Patterns from words
Let’s start at the beginning: with the words. Our choice of words can drastically alter a message, from its emotional resonance to its context to its literal meaning. Sometimes we can use word choice for good, to reinvigorate old, forgotten, or unfairly besmirched ideas.
One time at a wedding bbq we labeled the coleslaw BRASSICA MIXTA so people wouldn’t skip it based on false hatred.— Eileen Webb (@webmeadow) November 27, 2016
We can also use clever word choice to build euphemisms, to name sensitive or intimate concepts without conjuring their full details. This trick gifts us with language like “the beast with two backs” (thanks, Shakespeare!) and “surfing the crimson wave” (thanks, Cher Horowitz!).
But when we grapple with more serious concepts—war, death, human rights—this habit of declawing our language gets dangerous. Using more discrete wording serves to nullify the concepts themselves, euphemizing them out of sight and out of mind.
The result? Politicians never lie, they just “misspeak.” Nobody’s racist, but plenty of people are “economically anxious.” Nazis have rebranded as “alt-right.”
I’m not an asshole, I’m just alt-nice.— Andi Zeisler (@andizeisler) November 22, 2016
The problem with euphemisms like these is that they quickly infect everyday language. We use the words we hear around us. The more often we see “alt-right” instead of “Nazi,” the more likely we are to use that phrase ourselves—normalizing the term as well as the terrible ideas behind it.
Patterns from sentences
That process of normalization gets a boost from the media, our main vector of information about the world outside ourselves. Headlines control how we interpret the news that follows—even if the story contradicts it in the end. We hear the framing more clearly than the content itself, coloring our interpretation of the news over time.
Even worse, headlines are often written to encourage clicks, not to convey critical information. When headline-writing is driven by sensationalism, it’s much, much easier to build a pattern of misinformation. Take this CBS News headline: “Donald Trump: ‘Millions’ voted illegally for Hillary Clinton.” The headline makes no indication that this an objectively false statement; instead, this word choice subtly suggestions that millions did, in fact, illegally vote for Hillary Clinton.
Headlines like this are what make lying a worthwhile political strategy. https://t.co/DRjGeYVKmW— Binyamin Appelbaum (@BCAppelbaum) November 27, 2016
This is a deeply dangerous choice of words when headlines are the primary way that news is conveyed—especially on social media, where it’s much faster to share than to actually read the article. In fact, according to a study from the Media Insight Project, “roughly six in 10 people acknowledge that they have done nothing more than read news headlines in the past week.”
If a powerful person asserts X there are 2 responsible ways to cover:1. “X is true”2. “Person incorrectly thinks X”Never “Person says X”— Helen Rosner (@hels) November 27, 2016
Even if we do, in fact, read the whole article, there’s no guarantee that we’re thinking critically about it. A study conducted by Stanford found that “82 percent of students could not distinguish between a sponsored post and an actual news article on the same website. Nearly 70 percent of middle schoolers thought they had no reason to distrust a sponsored finance article written by the CEO of a bank, and many students evaluate the trustworthiness of tweets based on their level of detail and the size of attached photos.”
Friends: our information literacy is not very good. Luckily, we—workers of the web—are in a position to improve it.
Sentences into design
Consider the presentation of those all-important headlines in social media cards, as on Facebook. The display is a combination of both the card’s design and the article’s source code, and looks something like this:
A large image, a large headline; perhaps a brief description; and, at the bottom, in pale gray, a source and an author’s name.
Those choices convey certain values: specifically, they suggest that the headline and the picture are the entire point. The source is so deemphasized that it’s easy to see how fake news gains a foothold: daily exposure to this kind of hierarchy has taught us that sources aren’t important.
And that’s the message from the best-case scenario. Not every article shows every piece of data. Take this headline from the BBC: “Wisconsin receives request for vote recount.”
With no image, no description, and no author, there’s little opportunity to signal trust or provide nuance. There’s also no date—ever—which presents potentially misleading complications, especially in the context of “breaking news.”
And lest you think dates don’t matter in the light-speed era of social media, take the headline, “Maryland sidesteps electoral college.” Shared into my feed two days after the US presidential election, that’s some serious news with major historical implications. But since there’s no date on this card, there’s no way for readers to know that the “Tuesday” it refers to was in 2007. Again, a design choice has made misinformation far too contagious.
More recently, I posted my personal reaction to the death of Fidel Castro via a series of twenty tweets. Wanting to share my thoughts with friends and family who don’t use Twitter, I then posted the first tweet to Facebook. The card it generated was less than ideal:
The information hierarchy created by this approach prioritizes the name of the Twitter user (not even the handle), along with the avatar. Not only does that create an awkward “headline” (at least when you include a full stop in your name), but it also minimizes the content of the tweet itself—which was the whole point.
The arbitrary elevation of some pieces of content over others—like huge headlines juxtaposed with minimized sources—teaches readers that these values are inherent to the content itself: that the headline is the news, that the source is irrelevant. We train readers to stop looking for the information we don’t put in front of them.
These aren’t life-or-death scenarios; they are just cases where design decisions noticeably dictate the perception of information. Not every design decision makes so obvious an impact, but the impact is there. Every single action adds to the pattern.
Design with intention
We can’t necessarily teach people to read critically or vet their sources or stop believing conspiracy theories (or start believing facts). Our reach is limited to our roles: we make websites and products for companies and colleges and startups.
But we have more reach there than we might realize. Every decision we make influences how information is presented in the world. Every presentation adds to the pattern. No matter how innocuous our organization, how lowly our title, how small our user base—every single one of us contributes, a little bit, to the way information is perceived.
Are we changing it for the better?
While it’s always been crucial to act ethically in the building of the web, our cultural climate now requires dedicated, individual conscientiousness. It’s not enough to think ourselves neutral, to dismiss our work as meaningless or apolitical. Everything is political. Every action, and every inaction, has an impact.
As Chappell Ellison put it much more eloquently than I can:
Every single action and decision a designer commits is a political act. The question is, are you a conscious actor?— Chappell Ellison🤔 (@ChappellTracker) November 28, 2016
As shapers of information, we have a responsibility: to create clarity, to further understanding, to advance truth. Every single one of us must choose to treat information—and the society it builds—with integrity. |
2016 |
Lisa Maria Martin |
lisamariamartin |
2016-12-14T00:00:00+00:00 |
https://24ways.org/2016/information-literacy-is-a-design-problem/ |
content |
8 |
Coding Towards Accessibility |
“Can we make it AAA-compliant?” – does this question strike fear into your heart? Maybe for no other reason than because you will soon have to wade through the impenetrable WCAG documentation once again, to find out exactly what AAA-compliant means?
I’m not here to talk about that.
The Web Content Accessibility Guidelines are a comprehensive and peer-reviewed resource which we’re lucky to have at our fingertips. But they are also a pig to read, and they may have contributed to the sense of mystery and dread with which some developers associate the word accessibility.
This Christmas, I want to share with you some thoughts and some practical tips for building accessible interfaces which you can start using today, without having to do a ton of reading or changing your tools and workflow.
But first, let’s clear up a couple of misconceptions.
Dreary, flat experiences
I recently built a front-end framework for the Post Office. This was a great gig for a developer, but when I found out about my client’s stringent accessibility requirements I was concerned that I’d have to scale back what was quite a complex set of visual designs.
Sites like Jakob Neilsen’s old workhorse useit.com and even the pioneering GOV.UK may have to shoulder some of the blame for this. They put a premium on usability and accessibility over visual flourish. (Although, in fairness to Mr Neilsen, his new site nngroup.com is really quite a snazzy affair, comparatively.)
Of course, there are other reasons for these sites’ aesthetics — and it’s not because of the limitations of the form. You can make an accessible site look as glossy or as plain as you want it to look. It’s always our own ingenuity and attention to detail that are going to be the limiting factors.
Synecdoche
We must always guard against the tendency to assume that catering to screen readers means we have the whole accessibility ballgame covered.
There’s so much more to accessibility than assistive technology, as you know. And within the field of assistive technology there are plenty of other devices for us to consider.
Planning to accommodate all these users and devices can be daunting. When I first started working in this field I thought that the breadth of technology was prohibitive. I didn’t even know what a screen reader looked like. (I assumed they were big and heavy, perhaps like an old typewriter, and certainly they would be expensive and difficult to fathom.) This is nonsense, of course. Screen reader emulators are readily available as browser extensions and can be activated in seconds. Chromevox and Fangs are both excellent and you should download one or the other right now.
But the really good news is that you can emulate many other types of assistive technology without downloading a byte. And this is where we move from misconceptions into some (hopefully) useful advice.
The mouse trap
The simplest and most effective way to improve your abilities as a developer of accessible interfaces is to unplug your mouse.
Keyboard operation has its own WCAG chapter, because most users of assistive technology are navigating the web using only their keyboards. You can go some way towards putting yourself into their shoes so easily — just by ditching a peripheral.
Learning this was a lightbulb moment for me. When I build interfaces I am constantly flicking between code and the browser, testing or viewing the changes I have made. Now, instead of checking a new element once, I check it twice: once with my mouse and then again without.
Don’t just :hover
The reality is that when you first start doing this you can find your site becomes unusable straightaway. It’s easy to lose track of which element is in focus as you hit the tab key repeatedly.
One of the easiest changes you can make to your coding practice is to add :focus and :active pseudo-classes to every hover state that you write. I’m still amazed at how many sites fail to provide a decent focus state for links (and despite previous 24 ways authors in 2007 and 2009 writing on this same issue!).
You may find that in some cases it makes sense to have something other than, or in addition to, the hover state on focus, but start with the hover state that your designer has taken the time to provide you with. It’s a tiny change and there is no downside. So instead of this:
.my-cool-link:hover {
background-color: MistyRose ;
}
…try writing this:
.my-cool-link:hover,
.my-cool-link:focus,
.my-cool-link:active {
background-color: MistyRose ;
}
I’ve toyed with the idea of making a Sass mixin to take care of this for me, but I haven’t yet. I worry that people reading my code won’t see that I’m explicitly defining my focus and active states so I take the hit and write my hover rules out longhand.
JavaScript can play, too
This was another revelation for me. Keyboard-only navigation doesn’t necessitate a JavaScript-free experience, and up-to-date screen readers can execute JavaScript. So we’re able to create complex JavaScript-driven interfaces which all users can interact with.
Some of the hard work has already been done for us. First, there are already conventions around keyboard-driven interfaces. Think about the last time you viewed a photo album on Facebook. You can use the arrow keys to switch between photos, and the escape key closes whichever lightbox-y UI thing Facebook is showing its photos in this week. Arrow keys (up/down as well as left/right) for progression through content; Escape to back out of something; Enter or space bar to indicate a positive intention — these are established keyboard conventions which we can apply to our interfaces to improve their accessiblity.
Of course, by doing so we are improving our interfaces in general, giving all users the option to switch between keyboard and mouse actions as and when it suits them.
Second, this guy wants to help you out. Hans Hillen is a developer who has done a great deal of work around accessibility and JavaScript-powered interfaces. Along with The Paciello Group he has created a version of the jQuery UI library which has been fully optimised for keyboard navigation and screen reader use. It’s a fantastic reference which I revisit all the time
I’m not a huge fan of the jQuery UI library. It’s a pain to style and the code is a bit bloated. So I’ve not used this demo as a code resource to copy wholesale. I use it by playing with the various components and seeing how they react to keyboard controls. Each component is also fully marked up with the relevant ARIA roles to improve screen reader announcement where possible (more on this below).
Coding for accessibility promotes good habits
This is a another observation around accessibility and JavaScript. I noticed an improvement in the structure and abstraction of my code when I started adding keyboard controls to my interface elements.
Your code has to become more modular and event-driven, because any number of events could trigger the same interaction. A mouse-click, the Enter key and the space bar could all conceivably trigger the same open function on a collapsed accordion element. (And you want to keep things DRY, don’t you?)
If you aren’t already in the habit of separating out your interface functionality into discrete functions, you will be soon.
var doSomethingCool = function(){
// Do something cool here.
}
// Bind function to a button click - pretty vanilla
$('.myCoolButton').on('click', function(){
doSomethingCool();
return false;
});
// Bind the same function to a range of keypresses
$(document).keyup(function(e){
switch(e.keyCode) {
case 13: // enter
case 32: // spacebar
doSomethingCool();
break;
case 27: // escape
doSomethingElse();
break;
}
});
To be honest, if you’re doing complex UI stuff with JavaScript these days, or if you’ve been building any responsive interfaces which rely on JavaScript, then you are most likely working with an application framework such as Backbone, Angular or Ember, so an abstraced and event-driven application structure will be familar to you. It should be super easy for you to start helping out your keyboard-only users if you aren’t already — just add a few more event bindings into your UI layer!
Manipulating the tab order
So, you’ve adjusted your mindset and now you test every change to your codebase using a keyboard as well as a mouse. You’ve applied all your hover states to :focus and :active so you can see where you’re tabbing on the page, and your interactive components react seamlessly to a mixture of mouse and keyboard commands. Feels good, right?
There’s another level of optimisation to consider: manipulating the tab order. Certain DOM elements are naturally part of the tab order, and others are excluded. Links and input elements are the main elements included in the tab order, and static elements like paragraphs and headings are excluded. What if you want to make a static element ‘tabbable’?
A good example would be in an expandable accordion component. Each section of the accordion should be separated by a heading, and there’s no reason to make that heading into a link simply because it’s interactive.
<div class="accordion-widget">
<h3>Tyrannosaurus</h3>
<p>Tyrannosaurus; meaning "tyrant lizard"...<p>
<h3>Utahraptor</h3>
<p>Utahraptor is a genus of theropod dinosaurs...<p>
<h3>Dromiceiomimus</h3>
<p>Ornithomimus is a genus of ornithomimid dinosaurs...<p>
</div>
Adding the heading elements to the tab order is trivial. We just set their tabindex attribute to zero. You could do this on the server or the client. I prefer to do it with JavaScript as part of the accordion setup and initialisation process.
$('.accordion-widget h3').attr('tabindex', '0');
You can apply this trick in reverse and take elements out of the tab order by setting their tabindex attribute to −1, or change the tab order completely by using other integers. This should be done with great care, if at all. You have to be sure that the markup you remove from the tab order comes out because it genuinely improves the keyboard interaction experience. This is hard to validate without user testing. The danger is that developers will try to sweep complicated parts of the UI under the carpet by taking them out of the tab order. This would be considered a dark pattern — at least on my team!
A farewell ARIA
This is where things can get complex, and I’m no expert on the ARIA specification: I feel like I’ve only dipped my toe into this aspect of coding for accessibility. But, as with WCAG, I’d like to demystify things a little bit to encourage you to look into this area further yourself.
ARIA roles are of most benefit to screen reader users, because they modify and augment screen reader announcements.
Let’s take our dinosaur accordion from the previous section. The markup is semantic, so a screen reader that can’t handle JavaScript will announce all the content within the accordion, no problem.
But modern screen readers can deal with JavaScript, and this means that all the lovely dino information beneath each heading has probably been hidden on document.ready, when the accordion initialised. It might have been hidden using display:none, which prevents a screen reader from announcing content. If that’s as far as you have gone, then you’ve committed an accessibility sin by hiding content from screen readers. Your user will hear a set of headings being announced, with no content in between. It would sound something like this if you were using Chromevox:
> Tyrannosaurus. Heading Three.
> Utahraptor. Heading Three.
> Dromiceiomimus. Heading Three.
We can add some ARIA magic to the markup to improve this, using the tablist role. Start by adding a role of tablist to the widget, and roles of tab and tabpanel to the headings and paragraphs respectively. Set boolean values for aria-selected, aria-hidden and aria-expanded. The markup could end up looking something like this.
<div class="accordion-widget" role="tablist">
<!-- T-rex -->
<h3 role="tab"
tabindex="0"
id="tab-2"
aria-controls="panel-2"
aria-selected="false">Utahraptor</h3>
<p role="tabpanel"
id="panel-2"
aria-labelledby="tab-2"
aria-expanded="false"
aria-hidden="true">Utahraptor is a genus of theropod dinosaurs...</p>
<!-- Dromiceiomimus -->
</div>
Now, if a screen reader user encounters this markup they will hear the following:
> Tyrannosaurus. Tab not selected; one of three.
> Utahraptor. Tab not selected; two of three.
> Dromiceiomimus. Tab not selected; three of three.
You could add arrow key events to help the user browse up and down the tab list items until they find one they like.
Your accordion open() function should update the ARIA boolean values as well as adding whatever classes and animations you have built in as standard. Your users know that unselected tabs are meant to be interacted with, so if a user triggers the open function (say, by hitting Enter or the space bar on the second item) they will hear this:
> Utahraptor. Selected; two of three.
The paragraph element for the expanded item will not be hidden by your CSS, which means it will be announced as normal by the screen reader.
This kind of thing makes so much more sense when you have a working example to play with. Again, I refer you to the fantastic resource that Hans Hillen has put together: this is his take on an accessible accordion, on which much of my example is based.
Conclusion
Getting complex interfaces right for all of your users can be difficult — there’s no point pretending otherwise. And there’s no substitute for user testing with real users who navigate the web using assistive technology every day. This kind of testing can be time-consuming to recruit for and to conduct. On top of this, we now have accessibility on mobile devices to contend with. That’s a huge area in itself, and it’s one which I have not yet had a chance to research properly.
So, there’s lots to learn, and there’s lots to do to get it right. But don’t be disheartened. If you have read this far then I’ll leave you with one final piece of advice: don’t wait.
Don’t wait until you’re building a site which mandates AAA-compliance to try this stuff out. Don’t wait for a client with the will or the budget to conduct the full spectrum of user testing to come along. Unplug your mouse, and start playing with your interfaces in a new way. You’ll be surprised at the things that you learn and the issues you uncover.
And the next time an true accessibility project comes along, you will be way ahead of the game. |
2013 |
Charlie Perrins |
charlieperrins |
2013-12-03T00:00:00+00:00 |
https://24ways.org/2013/coding-towards-accessibility/ |
code |
11 |
JavaScript: Taking Off the Training Wheels |
JavaScript is the third pillar of front-end web development. Of those pillars, it is both the most powerful and the most complex, so it’s understandable that when 24 ways asked, “What one thing do you wish you had more time to learn about?”, a number of you answered “JavaScript!”
This article aims to help you feel happy writing JavaScript, and maybe even without libraries like jQuery. I can’t comprehensively explain JavaScript itself without writing a book, but I hope this serves as a springboard from which you can jump to other great resources.
Why learn JavaScript?
So what’s in it for you? Why take the next step and learn the fundamentals?
Confidence with jQuery
If nothing else, learning JavaScript will improve your jQuery code; you’ll be comfortable writing jQuery from scratch and feel happy bending others’ code to your own purposes. Writing efficient, fast and bug-free jQuery is also made much easier when you have a good appreciation of JavaScript, because you can look at what jQuery is really doing. Understanding how JavaScript works lets you write better jQuery because you know what it’s doing behind the scenes. When you need to leave the beaten track, you can do so with confidence.
In fact, you could say that jQuery’s ultimate goal is not to exist: it was invented at a time when web APIs were very inconsistent and hard to work with. That’s slowly changing as new APIs are introduced, and hopefully there will come a time when jQuery isn’t needed.
An example of one such change is the introduction of the very useful document.querySelectorAll. Like jQuery, it converts a CSS selector into a list of matching elements. Here’s a comparison of some jQuery code and the equivalent without.
$('.counter').each(function (index) {
$(this).text(index + 1);
});
var counters = document.querySelectorAll('.counter');
[].slice.call(counters).forEach(function (elem, index) {
elem.textContent = index + 1;
});
Solving problems no one else has!
When you have to go to the internet to solve a problem, you’re forever stuck reusing code other people wrote to solve a slightly different problem to your own. Learning JavaScript will allow you to solve problems in your own way, and begin to do things nobody else ever has.
Node.js
Node.js is a non-browser environment for running JavaScript, and it can do just about anything! But if that sounds daunting, don’t worry: the Node community is thriving, very friendly and willing to help.
I think Node is incredibly exciting. It enables you, with one language, to build complete websites with complex and feature-filled front- and back-ends. Projects that let users log in or need a database are within your grasp, and Node has a great ecosystem of library authors to help you build incredible things. Exciting!
Here’s an example web server written with Node. http is a module that allows you to create servers and, like jQuery’s $.ajax, make requests. It’s a small amount of code to do something complex and, while working with Node is different from writing front-end code, it’s certainly not out of your reach.
var http = require('http');
http.createServer(function (req, res) {
res.writeHead(200, {'Content-Type': 'text/plain'});
res.end('Hello World');
}).listen(1337);
console.log('Server running at http://localhost:1337/');
Grunt and other website tools
Node has brought in something of a renaissance in tools that run in the command line, like Yeoman and Grunt. Both of these rely heavily on Node, and I’ll talk a little bit about Grunt here.
Grunt is a task runner, and many people use it for compiling Sass or compressing their site’s JavaScript and images. It’s pretty cool. You configure Grunt via the gruntfile.js, so JavaScript skills will come in handy, and since Grunt supports plug-ins built with JavaScript, knowing it unlocks the bucketloads of power Grunt has to offer.
Ways to improve your skills
So you know you want to learn JavaScript, but what are some good ways to learn and improve? I think the answer to that is different for different people, but here are some ideas.
Rebuild a jQuery app
Converting a jQuery project to non-jQuery code is a great way to explore how you modify elements on the page and make requests to the server for data. My advice is to focus on making it work in one modern browser initially, and then go cross-browser if you’re feeling adventurous. There are many resources for directly comparing jQuery and non-jQuery code, like Jeffrey Way’s jQuery to JavaScript article.
Find a mentor
If you think you’d work better on a one-to-one basis then finding yourself a mentor could be a brilliant way to learn. The JavaScript community is very friendly and many people will be more than happy to give you their time. I’d look out for someone who’s active and friendly on Twitter, and does the kind of work you’d like to do. Introduce yourself over Twitter or send them an email. I wouldn’t expect a full tutoring course (although that is another option!) but they’ll be very glad to answer a question and any follow-ups every now and then.
Go to a workshop
Many conferences and local meet-ups run workshops, hosted by experts in a particular field. See if there’s one in your area. Workshops are great because you can ask direct questions, and you’re in an environment where others are learning just like you are — no need to learn alone!
Set yourself challenges
This is one way I like to learn new things. I have a new thing that I’m not very good at, so I pick something that I think is just out of my reach and I try to build it. It’s learning by doing and, even if you fail, it can be enormously valuable.
Where to start?
If you’ve decided learning JavaScript is an important step for you, your next question may well be where to go from here.
I’ve collected some links to resources I know of or use, with some discussion about why you might want to check a particular site out. I hope this serves as a springboard for you to go out and learn as much as you want.
Beginner
If you’re just getting started with JavaScript, I’d recommend heading to one of these places. They cover the basics and, in some cases, a little more advanced stuff. They’re all reputable sources (although, I’ve included something I wrote — you can decide about that one!) and will not lead you astray.
jQuery’s JavaScript 101 is a great first resource for JavaScript that will give you everything you need to work with jQuery like a pro.
Codecademy’s JavaScript Track is a small but useful JavaScript course. If you like learning interactively, this could be one for you.
HTMLDog’s JavaScript Tutorials take you right through from the basics of code to a brief introduction to newer technology like Node and Angular. [Disclaimer: I wrote this stuff, so it comes with a hazard warning!]
The tuts+ jQuery to JavaScript mentioned earlier is great for seeing how jQuery code looks when converted to pure JavaScript.
Getting in-depth
For more comprehensive documentation and help I’d recommend adding these places to your list of go-tos.
MDN: the Mozilla Developer Network is the first place I go for many JavaScript questions. I mostly find myself there via a search, but it’s a great place to just go and browse.
Axel Rauschmayer’s 2ality is a stunning collection of articles that will take you deep into JavaScript. It’s certainly worth looking at.
Addy Osmani’s JavaScript Design Patterns is a comprehensive collection of patterns for writing high quality JavaScript, particularly as you (I hope) start to write bigger and more complex applications.
And finally…
I think the key to learning anything is curiosity and perseverance. If you have a question, go out and search for the answer, even if you have no idea where to start. Keep going and going and eventually you’ll get there. I bet you’ll learn a whole lot along the way. Good luck!
Many thanks to the people who gave me their time when I was working on this article: Tom Oakley, Jack Franklin, Ben Howdle and Laura Kalbag. |
2013 |
Tom Ashworth |
tomashworth |
2013-12-05T00:00:00+00:00 |
https://24ways.org/2013/javascript-taking-off-the-training-wheels/ |
code |
15 |
Git for Grown-ups |
You are a clever and talented person. You create beautiful designs, or perhaps you have architected a system that even my cat could use. Your peers adore you. Your clients love you. But, until now, you haven’t *&^#^! been able to make Git work. It makes you angry inside that you have to ask your co-worker, again, for that *&^#^! command to upload your work.
It’s not you. It’s Git. Promise.
Yes, this is an article about the popular version control system, Git. But unlike just about every other article written about Git, I’m not going to give you the top five commands that you need to memorize; and I’m not going to tell you all your problems would be solved if only you were using this GUI wrapper or that particular workflow. You see, I’ve come to a grand realization: when we teach Git, we’re doing it wrong.
Let me back up for a second and tell you a little bit about the field of adult education. (Bear with me, it gets good and will leave you feeling both empowered and righteous.) Andragogy, unlike pedagogy, is a learner-driven educational experience. There are six main tenets to adult education:
Adults prefer to know why they are learning something.
The foundation of the learning activities should include experience.
Adults prefer to be able to plan and evaluate their own instruction.
Adults are more interested in learning things which directly impact their daily activities.
Adults prefer learning to be oriented not towards content, but towards problems.
Adults relate more to their own motivators than to external ones.
Nowhere in this list does it include “memorize the five most popular Git commands”. And yet this is how we teach version control: init, add, commit, branch, push. You’re an expert! Sound familiar? In the hierarchy of learning, memorizing commands is the lowest, or most basic, form of learning. At the peak of learning you are able to not just analyze and evaluate a problem space, but create your own understanding in relation to your existing body of knowledge.
“Fine,” I can hear you saying to yourself. “But I’m here to learn about version control.” Right you are! So how can we use this knowledge to master Git? First of all: I give you permission to use Git as a tool. A tool which you control and which you assign tasks to. A tool like a hammer, or a saw. Yes, your mastery of your tools will shape the kinds of interactions you have with your work, and your peers. But it’s yours to control. Git was written by kernel developers for kernel development. The web world has adopted Git, but it is not a tool designed for us and by us. It’s no Sass, y’know? Git wasn’t developed out of our frustration with managing CSS files in an increasingly complex ecosystem of components and atomic design. So, as you work through the next part of this article, give yourself a bit of a break. We’re in this together, and it’s going to be OK.
We’re going to do a little activity. We’re going to create your perfect Git cheatsheet.
I want you to start by writing down a list of all the people on your code team. This list may include:
developers
designers
project managers
clients
Next, I want you to write down a list of all the ways you interact with your team. Maybe you’re a solo developer and you do all the tasks. Maybe you only do a few things. But I want you to write down a list of all the tasks you’re actually responsible for. For example, my list looks like this:
writing code
reviewing code
publishing tested code to your server(s)
troubleshooting broken code
The next list will end up being a series of boxes in a diagram. But to start, I want you to write down a list of your tools and constraints. This list potentially has a lot of noun-like items and verb-like items:
code hosting system (Bitbucket? GitHub? Unfuddle? self-hosted?)
server ecosystem (dev/staging/live)
automated testing systems or review gates
automated build systems (that Jenkins dude people keep referring to)
Brilliant! Now you’ve got your actors and your actions, it’s time to shuffle them into a diagram. There are many popular workflow patterns. None are inherently right or wrong; rather, some are more or less appropriate for what you are trying to accomplish.
Centralized workflow
Everyone saves to a single place. This workflow may mean no version control, or a very rudimentary version control system which only ever has a single copy of the work available to the team at any point in time.
Branching workflow
Everyone works from a copy of the same place, merging their changes into the main copy as their work is completed. Think of the branches as a motorcycle sidecar: they’re along for the ride and probably cannot exist in isolation of the main project for long without serious danger coming to the either the driver or sidecar passenger. Branches are a fundamental concept in version control — they allow you to work on new features, bug fixes, and experimental changes within a single repository, but without forcing the changes onto others working from the same branch.
Forking workflow
Everyone works from their own, independent repository. A fork is an exact duplicate of a repository that a developer can make their own changes to. It can be kept up to date with additional changes made in other repositories, but it cannot force its changes onto another’s repository. A fork is a complete repository which can use its own workflow strategies. If developers wish to merge their work with the main project, they must make a request of some kind (submit a patch, or a pull request) which the project collaborators may choose to adopt or reject. This workflow is popular for open source projects as it enforces a review process.
Gitflow workflow
A specific workflow convention which includes five streams of parallel coding efforts: master, development, feature branches, release branches, and hot fixes. This workflow is often simplified down to a few elements by web teams, but may be used wholesale by software product teams. The original article describing this workflow was written by Vincent Driessen back in January 2010.
But these workflows aren’t about you yet, are they? So let’s make the connections.
From the list of people on your team you identified earlier, draw a little circle. Give each of these circles some eyes and a smile. Now I want you to draw arrows between each of these people in the direction that code (ideally) flows. Does your designer create responsive prototypes which are pushed to the developer? Draw an arrow to represent this.
Chances are high that you don’t just have people on your team, but you also have some kind of infrastructure. Hopefully you wrote about it earlier. For each of the servers and code repositories in your infrastructure, draw a square. Now, add to your diagram the relationships between the people and each of the machines in the infrastructure. Who can deploy code to the live server? How does it really get there? I bet it goes through some kind of code hosting system, such as GitHub. Draw in those arrows.
But wait!
The code that’s on your development machine isn’t the same as the live code. This is where we introduce the concept of a branch in version control. In Git, a repository contains all of the code (sort of). A branch is a fragment of the code that has been worked on in isolation to the other branches within a repository. Often branches will have elements in common. When we compare two (or more) branches, we are asking about the difference (or diff) between these two slivers. Often the master branch is used on production, and the development branch is used on our dev server. The difference between these two branches is the untested code that is not yet deployed.
On your diagram, see if you can colour-code according to the branch names at each of the locations within your infrastructure. You might find it useful to make a few different copies of the diagram to isolate each of the tasks you need to perform. For example: our team has a peer review process that each branch must go through before it is merged into the shared development branch.
Finally, we are ready to add the Git commands necessary to make sense of the arrows in our diagram. If we are bringing code to our own workstation we will issue one of the following commands: clone (the first time we bring code to our workstation) or pull. Remembering that a repository contains all branches, we will issue the command checkout to switch from one branch to another within our own workstation. If we want to share a particular branch with one of our team mates, we will push this branch back to the place we retrieved it from (the origin). Along each of the arrows in your diagram, write the name of the command you are are going to use when you perform that particular task.
From here, it’s up to you to be selfish. Before asking Git what command it would like you to use, sketch the diagram of what you want. Git is your tool, you are not Git’s tool. Draw the diagram. Communicate your tasks with your team as explicitly as you can. Insist on being a selfish adult learner — demand that others explain to you, in ways that are relevant to you, how to do the things you need to do today. |
2013 |
Emma Jane Westby |
emmajanewestby |
2013-12-04T00:00:00+00:00 |
https://24ways.org/2013/git-for-grownups/ |
code |
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 |
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 |
20 |
Make Your Browser Dance |
It was a crisp winter’s evening when I pulled up alongside the pier. I stepped out of my car and the bitterly cold sea air hit my face. I walked around to the boot, opened it and heaved out a heavy flight case. I slammed the boot shut, locked the car and started walking towards the venue.
This was it. My first gig. I thought about all those weeks of preparation: editing video clips, creating 3-D objects, making coloured patterns, then importing them all into software and configuring effects to change as the music did; targeting frequency, beat, velocity, modifying size, colour, starting point; creating playlists of these… and working out ways to mix them as the music played.
This was it. This was me VJing.
This was all a lifetime (well a decade!) ago.
When I started web designing, VJing took a back seat. I was more interested in interactive layouts, semantic accessible HTML, learning all the IE bugs and mastering the quirks that CSS has to offer. More recently, I have been excited by background gradients, 3-D transforms, the @keyframe directive, as well as new APIs such as getUserMedia, indexedDB, the Web Audio API
But wait, have I just come full circle? Could it be possible, with these wonderful new things in technologies I am already familiar with, that I could VJ again, right here, in a browser?
Well, there’s only one thing to do: let’s try it!
Let’s take to the dance floor
Over the past couple of years working in The Lab I have learned to take a much more iterative approach to projects than before. One of my new favourite methods of working is to create a proof of concept to make sure my theory is feasible, before going on to create a full-blown product. So let’s take the same approach here.
The main VJing functionality I want to recreate is manipulating visuals in relation to sound. So for my POC I need to create a visual, with parameters that can be changed, then get some sound and see if I can analyse that sound to detect some data, which I can then use to manipulate the visual parameters. Easy, right?
So, let’s start at the beginning: creating a simple visual. For this I’m going to create a CSS animation. It’s just a funky i element with the opacity being changed to make it flash.
See the Pen Creating a light by Rumyra (@Rumyra) on CodePen
A note about prefixes: I’ve left them out of the code examples in this post to make them easier to read. Please be aware that you may need them. I find a great resource to find out if you do is caniuse.com. You can also check out all the code for the examples in this article
Start the music
Well, that’s pretty easy so far. Next up: loading in some sound. For this we’ll use the Web Audio API. The Web Audio API is based around the concept of nodes. You have a source node: the sound you are loading in; a destination node: usually the device’s speakers; and any number of processing nodes in between. All this processing that goes on with the audio is sandboxed within the AudioContext.
So, let’s start by initialising our audio context.
var contextClass = window.AudioContext;
if (contextClass) {
//web audio api available.
var audioContext = new contextClass();
} else {
//web audio api unavailable
//warn user to upgrade/change browser
}
Now let’s load our sound file into the new context we created with an XMLHttpRequest.
function loadSound() {
//set audio file url
var audioFileUrl = '/octave.ogg';
//create new request
var request = new XMLHttpRequest();
request.open("GET", audioFileUrl, true);
request.responseType = "arraybuffer";
request.onload = function() {
//take from http request and decode into buffer
context.decodeAudioData(request.response, function(buffer) {
audioBuffer = buffer;
});
}
request.send();
}
Phew! Now we’ve loaded in some sound! There are plenty of things we can do with the Web Audio API: increase volume; add filters; spatialisation. If you want to dig deeper, the O’Reilly Web Audio API book by Boris Smus is available to read online free.
All we really want to do for this proof of concept, however, is analyse the sound data. To do this we really need to know what data we have.
Learning the steps
Let’s take a minute to step back and remember our school days and science class. I’m sure if I drew a picture of a sound wave, we would all start nodding our heads.
The sound you hear is caused by pressure differences in the particles in the air. Sound pushes these particles together, causing vibrations. Amplitude is basically strength of pressure. A simple example of change of amplitude is when you increase the volume on your stereo and the output wave increases in size.
This is great when everything is analogue, but the waveform varies continuously and it’s not suitable for digital processing: there’s an infinite set of values. For digital processing, we need discrete numbers.
We have to sample the waveform at set time intervals, and record data such as amplitude and frequency. Luckily for us, just the fact we have a digital sound file means all this hard work is done for us. What we’re doing in the code above is piping that data in the audio context. All we need to do now is access it.
We can do this with the Web Audio API’s analysing functionality. Just pop in an analysing node before we connect the source to its destination node.
function createAnalyser(source) {
//create analyser node
analyser = audioContext.createAnalyser();
//connect to source
source.connect(analyzer);
//pipe to speakers
analyser.connect(audioContext.destination);
}
The data I’m really interested in here is frequency. Later we could look into amplitude or time, but for now I’m going to stick with frequency.
The analyser node gives us frequency data via the getFrequencyByteData method.
Don’t forget to count!
To collect the data from the getFrequencyByteData method, we need to pass in an empty array (a JavaScript typed array is ideal). But how do we know how many items the array will need when we create it?
This is really up to us and how high the resolution of frequencies we want to analyse is. Remember we talked about sampling the waveform; this happens at a certain rate (sample rate) which you can find out via the audio context’s sampleRate attribute. This is good to bear in mind when you’re thinking about your resolution of frequencies.
var sampleRate = audioContext.sampleRate;
Let’s say your file sample rate is 48,000, making the maximum frequency in the file 24,000Hz (thanks to a wonderful theorem from Dr Harry Nyquist, the maximum frequency in the file is always half the sample rate). The analyser array we’re creating will contain frequencies up to this point. This is ideal as the human ear hears the range 0–20,000hz.
So, if we create an array which has 2,400 items, each frequency recorded will be 10Hz apart. However, we are going to create an array which is half the size of the FFT (fast Fourier transform), which in this case is 2,048 which is the default. You can set it via the fftSize property.
//set our FFT size
analyzer.fftSize = 2048;
//create an empty array with 1024 items
var frequencyData = new Uint8Array(1024);
So, with an array of 1,024 items, and a frequency range of 24,000Hz, we know each item is 24,000 ÷ 1,024 = 23.44Hz apart.
The thing is, we also want that array to be updated constantly. We could use the setInterval or setTimeout methods for this; however, I prefer the new and shiny requestAnimationFrame.
function update() {
//constantly getting feedback from data
requestAnimationFrame(update);
analyzer.getByteFrequencyData(frequencyData);
}
Putting it all together
Sweet sticks! Now we have an array of frequencies from the sound we loaded, updating as the sound plays. Now we want that data to trigger our animation from earlier.
We can easily pause and run our CSS animation from JavaScript:
element.style.webkitAnimationPlayState = "paused";
element.style.webkitAnimationPlayState = "running";
Unfortunately, this may not be ideal as our animation might be a whole heap longer than just a flashing light. We may want to target specific points within that animation to have it stop and start in a visually pleasing way and perhaps not smack bang in the middle.
There is no really easy way to do this at the moment as Zach Saucier explains in this wonderful article. It takes some jiggery pokery with setInterval to try to ascertain how far through the CSS animation you are in percentage terms.
This seems a bit much for our proof of concept, so let’s backtrack a little. We know by the animation we’ve created which CSS properties we want to change. This is pretty easy to do directly with JavaScript.
element.style.opacity = "1";
element.style.opacity = "0.2";
So let’s start putting it all together. For this example I want to trigger each light as a different frequency plays. For this, I’ll loop through the HTML elements and change the opacity style if the frequency gain goes over a certain threshold.
//get light elements
var lights = document.getElementsByTagName('i');
var totalLights = lights.length;
for (var i=0; i<totalLights; i++) {
//get frequencyData key
var freqDataKey = i*8;
//if gain is over threshold for that frequency animate light
if (frequencyData[freqDataKey] > 160){
//start animation on element
lights[i].style.opacity = "1";
} else {
lights[i].style.opacity = "0.2";
}
}
See all the code in action here. I suggest viewing in a modern browser :)
Awesome! It is true — we can VJ in our browser!
Let’s dance!
So, let’s start to expand this simple example. First, I feel the need to make lots of lights, rather than just a few. Also, maybe we should try a sound file more suited to gigs or clubs.
Check it out!
I don’t know about you, but I’m pretty excited — that’s just a bit of HTML, CSS and JavaScript!
The other thing to think about, of course, is the sound that you would get at a venue. We don’t want to load sound from a file, but rather pick up on what is playing in real time. The easiest way to do this, I’ve found, is to capture what my laptop’s mic is picking up and piping that back into the audio context. We can do this by using getUserMedia.
Let’s include this in this demo. If you make some noise while viewing the demo, the lights will start to flash.
And relax :)
There you have it. Sit back, play some music and enjoy the Winamp like experience in front of you.
So, where do we go from here? I already have a wealth of ideas. We haven’t started with canvas, SVG or the 3-D features of CSS. There are other things we can detect from the audio as well. And yes, OK, it’s questionable whether the browser is the best environment for this. For one, I’m using a whole bunch of nonsensical HTML elements (maybe each animation could be held within a web component in the future). But hey, it’s fun, and it looks cool and sometimes I think it’s OK to just dance. |
2013 |
Ruth John |
ruthjohn |
2013-12-02T00:00:00+00:00 |
https://24ways.org/2013/make-your-browser-dance/ |
code |
21 |
Keeping Parts of Your Codebase Private on GitHub |
Open source is brilliant, there’s no denying that, and GitHub has been instrumental in open source’s recent success. I’m a keen open-sourcerer myself, and I have a number of projects on GitHub. However, as great as sharing code is, we often want to keep some projects to ourselves. To this end, GitHub created private repositories which act like any other Git repository, only, well, private!
A slightly less common issue, and one I’ve come up against myself, is the desire to only keep certain parts of a codebase private. A great example would be my site, CSS Wizardry; I want the code to be open source so that people can poke through and learn from it, but I want to keep any draft blog posts private until they are ready to go live. Thankfully, there is a very simple solution to this particular problem: using multiple remotes.
Before we begin, it’s worth noting that you can actually build a GitHub Pages site from a private repo. You can keep the entire source private, but still have GitHub build and display a full Pages/Jekyll site. I do this with csswizardry.net. This post will deal with the more specific problem of keeping only certain parts of the codebase (branches) private, and expose parts of it as either an open source project, or a built GitHub Pages site.
N.B. This post requires some basic Git knowledge.
Adding your public remote
Let’s assume you’re starting from scratch and you currently have no repos set up for your project. (If you do already have your public repo set up, skip to the “Adding your private remote” section.)
So, we have a clean slate: nothing has been set up yet, we’re doing all of that now. On GitHub, create two repositories. For the sake of this article we shall call them site.com and private.site.com. Make the site.com repo public, and the private.site.com repo private (you will need a paid GitHub account).
On your machine, create the site.com directory, in which your project will live. Do your initial work in there, commit some stuff — whatever you need to do. Now we need to link this local Git repo on your machine with the public repo (remote) on GitHub. We should all be used to this:
$ git remote add origin git@github.com:[user]/site.com.git
Here we are simply telling Git to add a remote called origin which lives at git@github.com:[user]/site.com.git. Simple stuff. Now we need to push our current branch (which will be master, unless you’ve explicitly changed it) to that remote:
$ git push -u origin master
Here we are telling Git to push our master branch to a corresponding master branch on the remote called origin, which we just added. The -u sets upstream tracking, which basically tells Git to always shuttle code on this branch between the local master branch and the master branch on the origin remote. Without upstream tracking, you would have to tell Git where to push code to (and pull it from) every time you ran the push or pull commands. This sets up a permanent bond, if you like.
This is really simple stuff, stuff that you will probably have done a hundred times before as a Git user. Now to set up our private remote.
Adding your private remote
We’ve set up our public, open source repository on GitHub, and linked that to the repository on our machine. All of this code will be publicly viewable on GitHub.com. (Remember, GitHub is just a host of regular Git repositories, which also puts a nice GUI around it all.) We want to add the ability to keep certain parts of the codebase private. What we do now is add another remote repository to the same local repository. We have two repos on GitHub (site.com and private.site.com), but only one repository (and, therefore, one directory) on our machine. Two GitHub repos, and one local one.
In your local repo, check out a new branch. For the sake of this article we shall call the branch dev. This branch might contain work in progress, or draft blog posts, or anything you don’t want to be made publicly viewable on GitHub.com. The contents of this branch will, in a moment, live in our private repository.
$ git checkout -b dev
We have now made a new branch called dev off the branch we were on last (master, unless you renamed it).
Now we need to add our private remote (private.site.com) so that, in a second, we can send this branch to that remote:
$ git remote add private git@github.com:[user]/private.site.com.git
Like before, we are just telling Git to add a new remote to this repo, only this time we’ve called it private and it lives at git@github.com:[user]/private.site.com.git. We now have one local repo on our machine which has two remote repositories associated with it.
Now we need to tell our dev branch to push to our private remote:
$ git push -u private dev
Here, as before, we are pushing some code to a repo. We are saying that we want to push the dev branch to the private remote, and, once again, we’ve set up upstream tracking. This means that, by default, the dev branch will only push and pull to and from the private remote (unless you ever explicitly state otherwise).
Now you have two branches (master and dev respectively) that push to two remotes (origin and private respectively) which are public and private respectively.
Any work we do on the master branch will push and pull to and from our publicly viewable remote, and any code on the dev branch will push and pull from our private, hidden remote.
Adding more branches
So far we’ve only looked at two branches pushing to two remotes, but this workflow can grow as much or as little as you’d like. Of course, you’d never do all your work in only two branches, so you might want to push any number of them to either your public or private remotes. Let’s imagine we want to create a branch to try something out real quickly:
$ git checkout -b test
Now, when we come to push this branch, we can choose which remote we send it to:
$ git push -u private test
This pushes the new test branch to our private remote (again, setting the persistent tracking with -u).
You can have as many or as few remotes or branches as you like.
Combining the two
Let’s say you’ve been working on a new feature in private for a few days, and you’ve kept that on the private remote. You’ve now finalised the addition and want to move it into your public repo. This is just a simple merge. Check out your master branch:
$ git checkout master
Then merge in the branch that contained the feature:
$ git merge dev
Now master contains the commits that were made on dev and, once you’ve pushed master to its remote, those commits will be viewable publicly on GitHub:
$ git push
Note that we can just run $ git push on the master branch as we’d previously set up our upstream tracking (-u).
Multiple machines
So far this has covered working on just one machine; we had two GitHub remotes and one local repository. Let’s say you’ve got yourself a new Mac (yay!) and you want to clone an existing project:
$ git clone git@github.com:[user]/site.com.git
This will not clone any information about the remotes you had set up on the previous machine. Here you have a fresh clone of the public project and you will need to add the private remote to it again, as above.
Done!
If you’d like to see me blitz through all that in one go, check the showterm recording.
The beauty of this is that we can still share our code, but we don’t have to develop quite so openly all of the time. Building a framework with a killer new feature? Keep it in a private branch until it’s ready for merge. Have a blog post in a Jekyll site that you’re not ready to make live? Keep it in a private drafts branch. Working on a new feature for your personal site? Tuck it away until it’s finished. Need a staging area for a Pages-powered site? Make a staging remote with its own custom domain.
All this boils down to, really, is the fact that you can bring multiple remotes together into one local codebase on your machine. What you do with them is entirely up to you! |
2013 |
Harry Roberts |
harryroberts |
2013-12-09T00:00:00+00:00 |
https://24ways.org/2013/keeping-parts-of-your-codebase-private-on-github/ |
code |
30 |
Making Sites More Responsive, Responsibly |
With digital projects we’re used to shifting our thinking to align with our target audience. We may undertake research, create personas, identify key tasks, or observe usage patterns, with our findings helping to refine our ongoing creations. A product’s overall experience can make or break its success, and when it comes to defining these experiences our development choices play a huge role alongside more traditional user-focused activities.
The popularisation of responsive web design is a great example of how we are able to shape the web’s direction through using technology to provide better experiences. If we think back to the move from table-based layouts to CSS, initially our clients often didn’t know or care about the difference in these approaches, but we did. Responsive design was similar in this respect – momentum grew through the web industry choosing to use an approach that we felt would give a better experience, and which was more future-friendly.
We tend to think of responsive design as a means of displaying content appropriately across a range of devices, but the technology and our implementation of it can facilitate much more. A responsive layout not only helps your content work when the newest smartphone comes out, but it also ensures your layout suitably adapts if a visually impaired user drastically changes the size of the text.
The 24 ways site at 400% on a Retina MacBook Pro displays a layout more typically used for small screens.
When we think more broadly, we realise that our technical choices and approaches to implementation can have knock-on effects for the greater good, and beyond our initial target audiences. We can make our experiences more responsive to people’s needs, enhancing their usability and accessibility along the way.
Being responsibly responsive
Of course, when we think about being more responsive, there’s a fine line between creating useful functionality and becoming intrusive and overly complex. In the excellent Responsible Responsive Design, Scott Jehl states that:
A responsible responsive design equally considers the following throughout a project:
Usability: The way a website’s user interface is presented to the user, and how that UI responds to browsing conditions and user interactions.
Access: The ability for users of all devices, browsers, and assistive technologies to access and understand a site’s features and content.
Sustainability: The ability for the technology driving a site or application to work for devices that exist today and to continue to be usable and accessible to users, devices, and browsers in the future.
Performance: The speed at which a site’s features and content are perceived to be delivered to the user and the efficiency with which they operate within the user interface.
Scott’s book covers these ideas in a lot more detail than I’ll be able to here (put it on your Christmas list if it’s not there already), but for now let’s think a bit more about our roles as digital creators and the power this gives us.
Our choices around technology and the decisions we have to make can be extremely wide-ranging. Solutions will vary hugely depending on the needs of each project, though we can further explore the concept of making our creations more responsive through the use of humble web technologies.
The power of the web
We all know that under the HTML5 umbrella are some great new capabilities, including a number of JavaScript APIs such as geolocation, web audio, the file API and many more. We often use these to enhance the functionality of our sites and apps, to add in new features, or to facilitate device-specific interactions.
You’ll have seen articles with flashy titles such as “Top 5 JavaScript APIs You’ve Never Heard Of!”, which you’ll probably read, think “That’s quite cool”, yet never use in any real work.
There is great potential for technologies like these to be misused, but there are also great prospects for them to be used well to enhance experiences. Let’s have a look at a few examples you may not have considered.
Offline first
When we make websites, many of us follow a process which involves user stories – standardised snippets of context explaining who needs what, and why.
“As a student I want to pay online for my course so I don’t have to visit the college in person.”
“As a retailer I want to generate unique product codes so I can manage my stock.”
We very often focus heavily on what needs doing, but may not consider carefully how it will be done. As in Scott’s list, accessibility is extremely important, not only in terms of providing a great experience to users of assistive technologies, but also to make your creation more accessible in the general sense – including under different conditions.
Offline first is yet another ‘first’ methodology (my personal favourite being ‘tea first’), which encourages us to develop so that connectivity itself is an enhancement – letting users continue with tasks even when they’re offline. Despite the rapid growth in public Wi-Fi, if we consider data costs and connectivity in developing countries, our travel habits with planes, underground trains and roaming (or simply if you live in the UK’s signal-barren East Anglian wilderness as I do), then you’ll realise that connectivity isn’t as ubiquitous as our internet-addled brains would make us believe. Take a scenario that I’m sure we’re all familiar with – the digital conference. Your venue may be in a city served by high-speed networks, but after overloading capacity with a full house of hashtag-hungry attendees, each carrying several devices, then everyone’s likely to be offline after all. Wouldn’t it be better if we could do something like this instead?
Someone visits our conference website.
On this initial run, some assets may be cached for future use: the conference schedule, the site’s CSS, photos of the speakers.
When the attendee revisits the site on the day, the page shell loads up from the cache.
If we have cached content (our session timetable, speaker photos or anything else), we can load it directly from the cache. We might then try to update this, or get some new content from the internet, but the conference attendee already has a base experience to use.
If we don’t have something cached already, then we can try grabbing it online.
If for any reason our requests for new content fail (we’re offline), then we can display a pre-cached error message from the initial load, perhaps providing our users with alternative suggestions from what is cached.
There are a number of ways we can make something like this, including using the application cache (AppCache) if you’re that way inclined. However, you may want to look into service workers instead. There are also some great resources on Offline First! if you’d like to find out more about this.
Building in offline functionality isn’t necessarily about starting offline first, and it’s also perfectly possible to retrofit sites and apps to catch offline scenarios, but this kind of graceful degradation can end up being more complex than if we’d considered it from the start. By treating connectivity as an enhancement, we can improve the experience and provide better performance than we can when waiting to counter failures. Our websites can respond to connectivity and usage scenarios, on top of adapting how we present our content. Thinking in this way can enhance each point in Scott’s criteria.
As I mentioned, this isn’t necessarily the kind of development choice that our clients will ask us for, but it’s one we may decide is simply the right way to build based on our project, enhancing the experience we provide to people, and making it more responsive to their situation.
Even more accessible
We’ve looked at accessibility in terms of broadening when we can interact with a website, but what about how? Our user stories and personas are often of limited use. We refer in very general terms to students, retailers, and sometimes just users. What if we have a student whose needs are very different from another student? Can we make our sites even more usable and accessible through our development choices?
Again using JavaScript to illustrate this concept, we can do a lot more with the ways people interact with our websites, and with the feedback we provide, than simply accepting keyboard, mouse and touch inputs and displaying output on a screen.
Input
Ambient light detection is one of those features that looks great in simple demos, but which we struggle to put to practical use. It’s not new – many satnav systems automatically change the contrast for driving at night or in tunnels, and our laptops may alter the screen brightness or keyboard backlighting to better adapt to our surroundings. Using web technologies we can adapt our presentation to be better suited to ambient light levels.
If our device has an appropriate light sensor and runs a browser that supports the API, we can grab the ambient light in units using ambient light events, in JavaScript. We may then change our presentation based on different bandings, perhaps like this:
window.addEventListener('devicelight', function(e) {
var lux = e.value;
if (lux < 50) {
//Change things for dim light
}
if (lux >= 50 && lux <= 10000) {
//Change things for normal light
}
if (lux > 10000) {
//Change things for bright light
}
});
Live demo (requires light sensor and supported browser).
Soon we may also be able to do such detection through CSS, with light-level being cited in the Media Queries Level 4 specification. If that becomes the case, it’ll probably look something like this:
@media (light-level: dim) {
/*Change things for dim light*/
}
@media (light-level: normal) {
/*Change things for normal light*/
}
@media (light-level: washed) {
/*Change things for bright light*/
}
While we may be quick to dismiss this kind of detection as being a gimmick, it’s important to consider that apps such as Light Detector, listed on Apple’s accessibility page, provide important context around exactly this functionality.
“If you are blind, Light Detector helps you to be more independent in many daily activities. At home, point your iPhone towards the ceiling to understand where the light fixtures are and whether they are switched on. In a room, move the device along the wall to check if there is a window and where it is. You can find out whether the shades are drawn by moving the device up and down.”
everywaretechnologies.com/apps/lightdetector
Input can be about so much more than what we enter through keyboards. Both an ever increasing amount of available sensors and more APIs being supported by the major browsers will allow us to cater for more scenarios and respond to them accordingly. This can be as complex or simple as you need; for instance, while x-webkit-speech has been deprecated, the web speech API is available for a number of browsers, and research into sign language detection is also being performed by organisations such as Microsoft.
Output
Web technologies give us some great enhancements around input, allowing us to adapt our experiences accordingly. They also provide us with some nice ways to provide feedback to users.
When we play video games, many of our modern consoles come with the ability to have rumble effects on our controller pads. These are a great example of an enhancement, as they provide a level of feedback that is entirely optional, but which can give a great deal of extra information to the player in the right circumstances, and broaden the scope of our comprehension beyond what we’re seeing and hearing.
Haptic feedback is possible on the web as well. We could use this in any number of responsible applications, such as alerting a user to changes or using different patterns as a communication mechanism. If you find yourself in a pickle, here’s how to print out SOS in Morse code through the vibration API. The following code indicates the length of vibration in milliseconds, interspersed by pauses in milliseconds.
navigator.vibrate([100, 300, 100, 300, 100, 300, 600, 300, 600, 300, 600, 300, 100, 300, 100, 300, 100]);
Live demo (requires supported browser)
With great power…
What you’ve no doubt come to realise by now is that these are just more examples of progressive enhancement, whose inclusion will provide a better experience if the capabilities are available, but which we should not rely on. This idea isn’t new, but the most important thing to remember, and what I would like you to take away from this article, is that it is up to us to decide to include these kind of approaches within our projects – if we don’t root for them, they probably won’t happen. This is where our professional responsibility comes in.
We won’t necessarily be asked to implement solutions for the scenarios above, but they illustrate how we can help to push the boundaries of experiences. Maybe we’ll have to switch our thinking about how we build, but we can create more usable products for a diverse range of people and usage scenarios through the choices we make around technology. Let’s stop thinking simply in terms of features inside a narrow view of our target users, and work out how we can extend these to cater for a wider set of situations.
When you plan your next digital project, consider the power of the web and the enhancements we can use, and try to make your projects even more responsive and responsible. |
2014 |
Sally Jenkinson |
sallyjenkinson |
2014-12-10T00:00:00+00:00 |
https://24ways.org/2014/making-sites-more-responsive-responsibly/ |
code |
31 |
Dealing with Emergencies in Git |
The stockings were hung by the chimney with care,
In hopes that version control soon would be there.
This summer I moved to the UK with my partner, and the onslaught of the Christmas holiday season began around the end of October (October!). It does mean that I’ve had more than a fair amount of time to come up with horrible Git analogies for this article. Analogies, metaphors, and comparisons help the learner hook into existing mental models about how a system works. They only help, however, if the learner has enough familiarity with the topic at hand to make the connection between the old and new information.
Let’s start by painting an updated version of Clement Clarke Moore’s Christmas living room. Empty stockings are hung up next to the fireplace, waiting for Saint Nicholas to come down the chimney and fill them with small treats. Holiday treats are scattered about. A bowl of mixed nuts, the holiday nutcracker, and a few clementines. A string of coloured lights winds its way up an evergreen.
Perhaps a few of these images are familiar, or maybe they’re just settings you’ve seen in a movie. It doesn’t really matter what the living room looks like though. The important thing is to ground yourself in your own experiences before tackling a new subject. Instead of trying to brute-force your way into new information, as an adult learner constantly ask yourself: ‘What is this like? What does this remind me of? What do I already know that I can use to map out this new territory?’ It’s okay if the map isn’t perfect. As you refine your understanding of a new topic, you’ll outgrow the initial metaphors, analogies, and comparisons.
With apologies to Mr. Moore, let’s give it a try.
Getting Interrupted in Git
When on the roof there arose such a clatter!
You’re happily working on your software project when all of a sudden there are freaking reindeer on the roof! Whatever you’ve been working on is going to need to wait while you investigate the commotion.
If you’ve got even a little bit of experience working with Git, you know that you cannot simply change what you’re working on in times of emergency. If you’ve been doing work, you have a dirty working directory and you cannot change branches, or push your work to a remote repository while in this state.
Up to this point, you’ve probably dealt with emergencies by making a somewhat useless commit with a message something to the effect of ‘switching branches for a sec’. This isn’t exactly helpful to future you, as commits should really contain whole ideas of completed work. If you get interrupted, especially if there are reindeer on the roof, the chances are very high that you weren’t finished with what you were working on.
You don’t need to make useless commits though. Instead, you can use the stash command. This command allows you to temporarily set aside all of your changes so that you can come back to them later. In this sense, stash is like setting your book down on the side table (or pushing the cat off your lap) so you can go investigate the noise on the roof. You aren’t putting your book away though, you’re just putting it down for a moment so you can come back and find it exactly the way it was when you put it down.
Let’s say you’ve been working in the branch waiting-for-st-nicholas, and now you need to temporarily set aside your changes to see what the noise was on the roof:
$ git stash
After running this command, all uncommitted work will be temporarily removed from your working directory, and you will be returned to whatever state you were in the last time you committed your work.
With the book safely on the side table, and the cat safely off your lap, you are now free to investigate the noise on the roof. It turns out it’s not reindeer after all, but just your boss who thought they’d help out by writing some code on the project you’ve been working on. Bless. Rolling your eyes, you agree to take a look and see what kind of mischief your boss has gotten themselves into this time.
You fetch an updated list of branches from the remote repository, locate the branch your boss had been working on, and checkout a local copy:
$ git fetch
$ git branch -r
$ git checkout -b helpful-boss-branch origin/helpful-boss-branch
You are now in a local copy of the branch where you are free to look around, and figure out exactly what’s going on.
You sigh audibly and say, ‘Okay. Tell me what was happening when you first realised you’d gotten into a mess’ as you look through the log messages for the branch.
$ git log --oneline
$ git log
By using the log command you will be able to review the history of the branch and find out the moment right before your boss ended up stuck on your roof.
You may also want to compare the work your boss has done to the main branch for your project. For this article, we’ll assume the main branch is named master.
$ git diff master
Looking through the commits, you may be able to see that things started out okay but then took a turn for the worse.
Checking out a single commit
Using commands you’re already familiar with, you can rewind through history and take a look at the state of the code at any moment in time by checking out a single commit, just like you would a branch.
Using the log command, locate the unique identifier (commit hash) of the commit you want to investigate. For example, let’s say the unique identifier you want to checkout is 25f6d7f.
$ git checkout 25f6d7f
Note: checking out '25f6d7f'.
You are in 'detached HEAD' state. You can look around,
make experimental changes and commit them, and you can
discard any commits you make in this state without
impacting any branches by performing another checkout.
If you want to create a new branch to retain commits you create, you may do so (now or later) by using @-b@ with the checkout command again. Example:
$ git checkout -b new_branch_name
HEAD is now at 25f6d7f... Removed first paragraph.
This is usually where people start to panic. Your boss screwed something up, and now your HEAD is detached. Under normal circumstances, these words would be a very good reason to panic.
Take a deep breath. Nothing bad is going to happen. Being in a detached HEAD state just means you’ve temporarily disconnected from a known chain of events. In other words, you’re currently looking at the middle of a story (or branch) about what happened – and you’re not at the endpoint for this particular story.
Git allows you to view the history of your repository as a timeline (technically it’s a directed acyclic graph). When you make commits which are not associated with a branch, they are essentially inaccessible once you return to a known branch. If you make commits while you’re in a detached HEAD state, and then try to return to a known branch, Git will give you a warning and tell you how to save your work.
$ git checkout master
Warning: you are leaving 1 commit behind, not connected to
any of your branches:
7a85788 Your witty holiday commit message.
If you want to keep them by creating a new branch, this may be a good time to do so with:
$ git branch new_branch_name 7a85788
Switched to branch 'master'
Your branch is up-to-date with 'origin/master'.
So, if you want to save the commits you’ve made while in a detached HEAD state, you simply need to put them on a new branch.
$ git branch saved-headless-commits 7a85788
With this trick under your belt, you can jingle around in history as much as you’d like. It’s not like sliding around on a timeline though. When you checkout a specific commit, you will only have access to the history from that point backwards in time. If you want to move forward in history, you’ll need to move back to the branch tip by checking out the branch again.
$ git checkout helpful-boss-branch
You’re now back to the present. Your HEAD is now pointing to the endpoint of a known branch, and so it is no longer detached. Any changes you made while on your adventure are safely stored in a new branch, assuming you’ve followed the instructions Git gave you. That wasn’t so scary after all, now, was it?
Back to our reindeer problem.
If your boss is anything like the bosses I’ve worked with, chances are very good that at least some of their work is worth salvaging. Depending on how your repository is structured, you’ll want to capture the good work using one of several different methods.
Back in the living room, we’ll use our bowl of nuts to illustrate how you can rescue a tiny bit of work.
Saving just one commit
About that bowl of nuts. If you’re like me, you probably had some favourite kinds of nuts from an assorted collection. Walnuts were generally the most satisfying to crack open. So, instead of taking the entire bowl of nuts and dumping it into a stocking (merging the stocking and the bowl of nuts), we’re just going to pick out one nut from the bowl. In Git terms, we’re going to cherry-pick a commit and save it to another branch.
First, checkout the main branch for your development work. From this branch, create a new branch where you can copy the changes into.
$ git checkout master
$ git checkout -b rescue-the-boss
From your boss’s branch, helpful-boss-branch locate the commit you want to keep.
$ git log --oneline helpful-boss-branch
Let’s say the commit ID you want to keep is e08740b. From your rescue branch, use the command cherry-pick to copy the changes into your current branch.
$ git cherry-pick e08740b
If you review the history of your current branch again, you will see you now also have the changes made in the commit in your boss’s branch.
At this point you might need to make a few additional fixes to help your boss out. (You’re angling for a bonus out of all this. Go the extra mile.) Once you’ve made your additional changes, you’ll need to add that work to the branch as well.
$ git add [filename(s)]
$ git commit -m "Building on boss's work to improve feature X."
Go ahead and test everything, and make sure it’s perfect. You don’t want to introduce your own mistakes during the rescue mission!
Uploading the fixed branch
The next step is to upload the new branch to the remote repository so that your boss can download it and give you a huge bonus for helping you fix their branch.
$ git push -u origin rescue-the-boss
Cleaning up and getting back to work
With your boss rescued, and your bonus secured, you can now delete the local temporary branches.
$ git branch --delete rescue-the-boss
$ git branch --delete helpful-boss-branch
And settle back into your chair to wait for Saint Nicholas with your book, your branch, and possibly your cat.
$ git checkout waiting-for-st-nicholas
$ git stash pop
Your working directory has been returned to exactly the same state you were in at the beginning of the article.
Having fun with analogies
I’ve had a bit of fun with analogies in this article. But sometimes those little twists on ideas can really help someone pick up a new idea (git stash: it’s like when Christmas comes around and everyone throws their fashion sense out the window and puts on a reindeer sweater for the holiday party; or git bisect: it’s like trying to find that one broken light on the string of Christmas lights). It doesn’t matter if the analogy isn’t perfect. It’s just a way to give someone a temporary hook into a concept in a way that makes the concept accessible while the learner becomes comfortable with it. As the learner’s comfort increases, the analogies can drop away, making room for the technically correct definition of how something works.
Or, if you’re like me, you can choose to never grow old and just keep mucking about in the analogies. I’d argue it’s a lot more fun to play with a string of Christmas lights and some holiday cheer than a directed acyclic graph anyway. |
2014 |
Emma Jane Westby |
emmajanewestby |
2014-12-02T00:00:00+00:00 |
https://24ways.org/2014/dealing-with-emergencies-in-git/ |
code |
36 |
Naming Things |
There are only two hard things in computer science: cache invalidation and naming things.
Phil Karlton
Being a professional web developer means taking responsibility for the code you write and ensuring it is comprehensible to others. Having a documented code style is one means of achieving this, although the size and type of project you’re working on will dictate the conventions used and how rigorously they are enforced.
Working in-house may mean working with multiple developers, perhaps in distributed teams, who are all committing changes – possibly to a significant codebase – at the same time. Left unchecked, this codebase can become unwieldy. Coding conventions ensure everyone can contribute, and help build a product that works as a coherent whole.
Even on smaller projects, perhaps working within an agency or by yourself, at some point the resulting product will need to be handed over to a third party. It’s sensible, therefore, to ensure that your code can be understood by those who’ll eventually take ownership of it.
Put simply, code is read more often than it is written or changed. A consistent and predictable naming scheme can make code easier for other developers to understand, improve and maintain, presumably leaving them free to worry about cache invalidation.
Let’s talk about semantics
Names not only allow us to identify objects, but they can also help us describe the objects being identified.
Semantics (the meaning or interpretation of words) is the cornerstone of standards-based web development. Using appropriate HTML elements allows us to create documents and applications that have implicit structural meaning. Thanks to HTML5, the vocabulary we can choose from has grown even larger.
HTML elements provide one level of meaning: a widely accepted description of a document’s underlying structure. It’s only with the mutual agreement of browser vendors and developers that <p> indicates a paragraph.
Yet (with the exception of widely accepted microdata and microformat schemas) only HTML elements convey any meaning that can be parsed consistently by user agents. While using semantic values for class names is a noble endeavour, they provide no additional information to the visitor of a website; take them away and a document will have exactly the same semantic value.
I didn’t always think this was the case, but the real world has a habit of changing your opinion. Much of my thinking around semantics has been informed by the writing of my peers. In “About HTML semantics and front-end architecture”, Nicholas Gallagher wrote:
The important thing for class name semantics in non-trivial applications is that they be driven by pragmatism and best serve their primary purpose – providing meaningful, flexible, and reusable presentational/behavioural hooks for developers to use.
These thoughts are echoed by Harry Roberts in his CSS Guidelines:
The debate surrounding semantics has raged for years, but it is important that we adopt a more pragmatic, sensible approach to naming things in order to work more efficiently and effectively. Instead of focussing on ‘semantics’, look more closely at sensibility and longevity – choose names based on ease of maintenance, not for their perceived meaning.
Naming methodologies
Front-end development has undergone a revolution in recent years. As the projects we’ve worked on have grown larger and more important, our development practices have matured. The pros and cons of object-orientated approaches to CSS can be endlessly debated, yet their introduction has highlighted the usefulness of having documented naming schemes.
Jonathan Snook’s SMACSS (Scalable and Modular Architecture for CSS) collects style rules into five categories: base, layout, module, state and theme. This grouping makes it clear what each rule does, and is aided by a naming convention:
By separating rules into the five categories, naming convention is beneficial for immediately understanding which category a particular style belongs to and its role within the overall scope of the page. On large projects, it is more likely to have styles broken up across multiple files. In these cases, naming convention also makes it easier to find which file a style belongs to.
I like to use a prefix to differentiate between layout, state and module rules. For layout, I use l- but layout- would work just as well. Using prefixes like grid- also provide enough clarity to separate layout styles from other styles. For state rules, I like is- as in is-hidden or is-collapsed. This helps describe things in a very readable way.
SMACSS is more a set of suggestions than a rigid framework, so its ideas can be incorporated into your own practice. Nicholas Gallagher’s SUIT CSS project is far more strict in its naming conventions:
SUIT CSS relies on structured class names and meaningful hyphens (i.e., not using hyphens merely to separate words). This helps to work around the current limits of applying CSS to the DOM (i.e., the lack of style encapsulation), and to better communicate the relationships between classes.
Over the last year, I’ve favoured a BEM-inspired approach to CSS. BEM stands for block, element, modifier, which describes the three types of rule that contribute to the style of a single component. This means that, given the following markup:
<ul class=“sleigh”>
<li class=“sleigh__reindeer sleigh__reindeer––famous”>Rudolph</li>
<li class=“sleigh__reindeer”>Dasher</li>
<li class=“sleigh__reindeer”>Dancer</li>
<li class=“sleigh__reindeer”>Prancer</li>
<li class=“sleigh__reindeer”>Vixen</li>
<li class=“sleigh__reindeer”>Comet</li>
<li class=“sleigh__reindeer”>Cupid</li>
<li class=“sleigh__reindeer”>Dunder</li>
<li class=“sleigh__reindeer”>Blixem</li>
</ul>
I know that:
.sleigh is a containing block or component.
.sleigh__reindeer is used only as a descendent element of .sleigh.
.sleigh__reindeer––famous is used only as a modifier of .sleigh__reindeer.
With this naming scheme in place, I know which styles relate to a particular component, and which are shared. Beyond reducing specificity-related head-scratching, this approach has given me a framework within which I can consistently label items, and has sped up my workflow considerably.
Each of these methodologies shows that any robust CSS naming convention will have clear rules around case (lowercase, camelCase, PascalCase) and the use of special (allowed) characters like hyphens and underscores.
What makes for a good name?
Regardless of higher-level conventions, there’s no getting away from the fact that, at some point, we’re still going to have to name things. Recognising that classes should be named with other developers in mind, what makes for a good name?
Understandable
The most important aspect is for a name to be understandable. Words used in your project may come from a variety of sources: some may be widely understood, and others only be recognised by people working within a particular environment.
Culture
Most words you’ll choose will have common currency outside the world of web development, although they may have a particular interpretation among developers (think menu, list, input). However, words may have a narrower cultural significance; for example, in Germany and other German-speaking countries, impressum is the term used for legally mandated statements of ownership.
Industry
Industries often use specific terms to describe common business practices and concepts. Publishing has a number of these (headline, standfirst, masthead, colophon…) all have well understood meanings – and not all of them are relevant to online usage.
Organisation
Companies may have internal names (or nicknames) for their products and services. The Guardian is rife with such names: bisons (and buffalos), pixies (and super-pixies), bentos (and mini-bentos)… all of which mean something very different outside the organisation. Although such names can be useful inside smaller teams, in larger organisations they can become a barrier to entry, a sort of secret code used among employees who have been around long enough to know what they mean.
Product
Your team will undoubtedly have created names for specific features or interface components used in your product. For example, at Clearleft we coined the term gravigation for a navigation bar that was pinned to the bottom of the viewport. Elements of a visual design language may have names, too. Transport for London’s bar and circle logo is known internally as the roundel, while Nike’s logo is called the swoosh. Branding agencies often christen colours within a brand palette, too, either to evoke aspects of the identity or to indicate intended usage.
Once you recognise the origin of the words you use, you’ll be better able to judge their appropriateness. Using Latin words for class names may satisfy a need to use semantic-sounding terms but, unless you work in a company whose employees have a basic grasp of Latin, a degree of translation will be required. Military ranks might be a clever way of declaring sizes without implying actual values, but I’d venture most people outside the armed forces don’t know how they’re ordered.
Obvious
Quite often, the first name that comes into your head will be the best option. Names that obliquely reference the function of a class (e.g. receptacle instead of container, kevlar instead of no-bullets) only serve to add an additional layer of abstraction. Don’t overthink it!
One way of knowing if the names you use are well understood is to look at what similar concepts are called in existing vocabularies. schema.org, Dublin Core and the BBC’s ontologies are all useful sources for object names.
Functional
While we’ve learned to avoid using presentational classes, there remains a tension between naming things based on their content, and naming them for their intended presentation or behaviour (which may change at different breakpoints). Rather than think about a component’s appearance or behaviour, instead look to its function, its purpose. To clarify, ask what a component’s function is, and not how the component functions.
For example, the Guardian’s internal content system uses the following names for different types of image placement: supporting, showcase and thumbnail, with inline being the default. These options make no promise of the resulting position on a webpage (or smartphone app, or television screen…), but do suggest intended use, and therefore imply the likely presentation.
Consistent
Being consistent in your approach to names will allow for easier naming of successive components, and extending the vocabulary when necessary. For example, a predictably named hierarchy might use names like primary and secondary. Should another level need to be added, tertiary is clearly be preferred over third.
Appropriate
Your project will feature a mix of style rules. Some will perform utility functions (clearing floats, removing bullets from a list, reseting margins), while others will perform specific functions used only once or twice in a project. Names should reflect this. For commonly used classes, be generic; for unique components be more specific.
It’s also worth remembering that you can use multiple classes on an element, so combining both generic and specific can give you a powerful modular design system:
Generic: list
Specific: naughty-children
Combined: naughty-children list
If following the BEM methodology, you might use the following classes:
Generic: list
Specific: list––nice-children
Combined: list list––nice-children
Extensible
Good naming schemes can be extended. One way of achieving this is to use namespaces, which are basically a way of grouping related names under a higher-level term.
Microformats are a good example of a well-designed naming scheme, with many of its vocabularies taking property names from existing and related specifications (e.g. hCard is a 1:1 representation of vCard). Microformats 2 goes one step further by grouping properties under several namespaces:
h-* for root class names (e.g. h-card)
p-* for simple (text) properties (e.g. p-name)
u-* for URL properties (e.g. u-photo)
dt-* for date/time properties (e.g. dt-bday)
e-* for embedded markup properties (e.g. e-note)
The inclusion of namespaces is a massive improvement over the earlier specification, but the downside is that microformats now occupy five separate namespaces. This might be problematic if you are using u-* for your utility classes. While nothing will break, your naming system won’t be as robust, so plan accordingly.
(Note: Microformats perform a very specific function, separate from any presentational concerns. It’s therefore considered best practice to not use microformat classes as styling hooks, but instead use additional classes that relate to the function of the component and adhere to your own naming conventions.)
Short
Names should be as long as required, but no longer. When looking for words to describe a particular function, I try to look for single words where possible. Avoid abbreviations unless they are understood within the contexts described above. rrp is fine if labelling a recommended retail price in an online shop, but not very helpful if used to mean ragged-right paragraph, for example.
Fun!
Finally, names can be an opportunity to have some fun! Names can give character to a project, be it by providing an outlet for in-jokes or adding little easter eggs for those inclined to look.
The copyright statement on Apple’s website has long been named sosumi, a word that has a nice little history inside Apple. Until recently, the hamburger menu icon on the Guardian website was labelled honest-burger, after the developer’s favourite burger restaurant.
A few thoughts on preprocessors
CSS preprocessors have solved a lot of problems, but they have an unfortunate downside: they require you to name yet more things! Whereas we needed to worry only about style rules, now we need names for variables, mixins, functions… oh my!
A second article could be written about naming these, so for now I’ll offer just a few thoughts. The first is to note that preprocessors make it easier to change things, as they allow for DRYer code. So while the names of variables are important (and the advice in this article still very much applies), you can afford to relax a little.
Looking to name colour variables? If possible, find out if colours have been assigned names in a brand palette. If not, use obvious names (based on appearance or function, depending on your preference) and adapt as the palette grows. If it becomes difficult to name colours that are too similar, I’d venture that the problem lies with the design rather than the naming scheme.
The same is true for responsive breakpoints. Preprocessors allow you to move awkward naming conventions out of the markup and into the CSS. Although terms like mobile, tablet and desktop are not desirable given the need to think about device-agnostic design, if these terms are widely understood within a product team and among stakeholders, using them will ensure everyone is using the same language (they can always be changed later).
It still feels like we’re at the very beginning of understanding how preprocessors fit into a development workflow, if at all! I suspect over the next few years, best practices will emerge for all of these considerations. In the meantime, use your brain!
Even with sensible rules and conventions in place, naming things can remain difficult, but hopefully I’ve made this exercise a little less painful. Christmas is a time of giving, so to the developer reading your code in a year’s time, why not make your gift one of clearer class names. |
2014 |
Paul Lloyd |
paulrobertlloyd |
2014-12-21T00:00:00+00:00 |
https://24ways.org/2014/naming-things/ |
code |
37 |
JavaScript Modules the ES6 Way |
JavaScript admittedly has plenty of flaws, but one of the largest and most prominent is the lack of a module system: a way to split up your application into a series of smaller files that can depend on each other to function correctly.
This is something nearly all other languages come with out of the box, whether it be Ruby’s require, Python’s import, or any other language you’re familiar with. Even CSS has @import! JavaScript has nothing of that sort, and this has caused problems for application developers as they go from working with small websites to full client-side applications. Let’s be clear: it doesn’t mean the new module system in the upcoming version of JavaScript won’t be useful to you if you’re building smaller websites rather than the next Instagram.
Thankfully, the lack of a module system will soon be a problem of the past. The next version of JavaScript, ECMAScript 6, will bring with it a full-featured module and dependency management solution for JavaScript. The bad news is that it won’t be landing in browsers for a while yet – but the good news is that the specification for the module system and how it will look has been finalised. The even better news is that there are tools available to get it all working in browsers today without too much hassle. In this post I’d like to give you the gift of JS modules and show you the syntax, and how to use them in browsers today. It’s much simpler than you might think.
What is ES6?
ECMAScript is a scripting language that is standardised by a company called Ecma International. JavaScript is an implementation of ECMAScript. ECMAScript 6 is simply the next version of the ECMAScript standard and, hence, the next version of JavaScript. The spec aims to be fully comfirmed and complete by the end of 2014, with a target initial release date of June 2015. It’s impossible to know when we will have full feature support across the most popular browsers, but already some ES6 features are landing in the latest builds of Chrome and Firefox. You shouldn’t expect to be able to use the new features across browsers without some form of additional tooling or library for a while yet.
The ES6 module spec
The ES6 module spec was fully confirmed in July 2014, so all the syntax I will show you in this article is not expected to change. I’ll first show you the syntax and the new APIs being added to the language, and then look at how to use them today. There are two parts to the new module system. The first is the syntax for declaring modules and dependencies in your JS files, and the second is a programmatic API for loading in modules manually. The first is what most people are expected to use most of the time, so it’s what I’ll focus on more.
Module syntax
The key thing to understand here is that modules have two key components. First, they have dependencies. These are things that the module you are writing depends on to function correctly. For example, if you were building a carousel module that used jQuery, you would say that jQuery is a dependency of your carousel. You import these dependencies into your module, and we’ll see how to do that in a minute. Second, modules have exports. These are the functions or variables that your module exposes publicly to anything that imports it. Using jQuery as the example again, you could say that jQuery exports the $ function. Modules that depend on and hence import jQuery get access to the $ function, because jQuery exports it.
Another important thing to note is that when I discuss a module, all I really mean is a JavaScript file. There’s no extra syntax to use other than the new ES6 syntax. Once ES6 lands, modules and files will be analogous.
Named exports
Modules can export multiple objects, which can be either plain old variables or JavaScript functions. You denote something to be exported with the export keyword:
export function double(x) {
return x + x;
};
You can also store something in a variable then export it. If you do that, you have to wrap the variable in a set of curly braces.
var double = function(x) {
return x + x;
}
export { double };
A module can then import the double function like so:
import { double } from 'mymodule';
double(2); // 4
Again, curly braces are required around the variable you would like to import. It’s also important to note that from 'mymodule' will look for a file called mymodule.js in the same directory as the file you are requesting the import from. There is no need to add the .js extension.
The reason for those extra braces is that this syntax lets you export multiple variables:
var double = function(x) {
return x + x;
}
var square = function(x) {
return x * x;
}
export { double, square }
I personally prefer this syntax over the export function …, but only because it makes it much clearer to me what the module exports. Typically I will have my export {…} line at the bottom of the file, which means I can quickly look in one place to determine what the module is exporting.
A file importing both double and square can do so in just the way you’d expect:
import { double, square } from 'mymodule';
double(2); // 4
square(3); // 9
With this approach you can’t easily import an entire module and all its methods. This is by design – it’s much better and you’re encouraged to import just the functions you need to use.
Default exports
Along with named exports, the system also lets a module have a default export. This is useful when you are working with a large library such as jQuery, Underscore, Backbone and others, and just want to import the entire library. A module can define its default export (it can only ever have one default export) like so:
export default function(x) {
return x + x;
}
And that can be imported:
import double from 'mymodule';
double(2); // 4
This time you do not use the curly braces around the name of the object you are importing. Also notice how you can name the import whatever you’d like. Default exports are not named, so you can import them as anything you like:
import christmas from 'mymodule';
christmas(2); // 4
The above is entirely valid.
Although it’s not something that is used too often, a module can have both named exports and a default export, if you wish.
One of the design goals of the ES6 modules spec was to favour default exports. There are many reasons behind this, and there is a very detailed discussion on the ES Discuss site about it. That said, if you find yourself preferring named exports, that’s fine, and you shouldn’t change that to meet the preferences of those designing the spec.
Programmatic API
Along with the syntax above, there is also a new API being added to the language so you can programmatically import modules. It’s pretty rare you would use this, but one obvious example is loading a module conditionally based on some variable or property. You could easily import a polyfill, for example, if the user’s browser didn’t support a feature your app relied on. An example of doing this is:
if(someFeatureNotSupported) {
System.import('my-polyfill').then(function(myPolyFill) {
// use the module from here
});
}
System.import will return a promise, which, if you’re not familiar, you can read about in this excellent article on HTMl5 Rocks by Jake Archibald. A promise basically lets you attach callback functions that are run when the asynchronous operation (in this case, System.import), is complete.
This programmatic API opens up a lot of possibilities and will also provide hooks to allow you to register callbacks that will run at certain points in the lifetime of a module. Those hooks and that syntax are slightly less set in stone, but when they are confirmed they will provide really useful functionality. For example, you could write code that would run every module that you import through something like JSHint before importing it. In development that would provide you with an easy way to keep your code quality high without having to run a command line watch task.
How to use it today
It’s all well and good having this new syntax, but right now it won’t work in any browser – and it’s not likely to for a long time. Maybe in next year’s 24 ways there will be an article on how you can use ES6 modules with no extra work in the browser, but for now we’re stuck with a bit of extra work.
ES6 module transpiler
One solution is to use the ES6 module transpiler, a compiler that lets you write your JavaScript using the ES6 module syntax (actually a subset of it – not quite everything is supported, but the main features are) and have it compiled into either CommonJS-style code (CommonJS is the module specification that NodeJS and Browserify use), or into AMD-style code (the spec RequireJS uses). There are also plugins for all the popular build tools, including Grunt and Gulp.
The advantage of using this transpiler is that if you are already using a tool like RequireJS or Browserify, you can drop the transpiler in, start writing in ES6 and not worry about any additional work to make the code work in the browser, because you should already have that set up already. If you don’t have any system in place for handling modules in the browser, using the transpiler doesn’t really make sense. Remember, all this does is convert ES6 module code into CommonJS- or AMD-compliant JavaScript. It doesn’t do anything to help you get that code running in the browser, but if you have that part sorted it’s a really nice addition to your workflow. If you would like a tutorial on how to do this, I wrote a post back in June 2014 on using ES6 with the ES6 module transpiler.
SystemJS
Another solution is SystemJS. It’s the best solution in my opinion, particularly if you are starting a new project from scratch, or want to use ES6 modules on a project where you have no current module system in place. SystemJS is a spec-compliant universal module loader: it loads ES6 modules, AMD modules, CommonJS modules, as well as modules that just add a variable to the global scope (window, in the browser).
To load in ES6 files, SystemJS also depends on two other libraries: the ES6 module loader polyfill; and Traceur. Traceur is best accessed through the bower-traceur package, as the main repository doesn’t have an easy to find downloadable version. The ES6 module load polyfill implements System.import, and lets you load in files using it. Traceur is an ES6-to-ES5 module loader. It takes code written in ES6, the newest version of JavaScript, and transpiles it into ES5, the version of JavaScript widely implemented in browsers. The advantage of this is that you can play with the new features of the language today, even though they are not supported in browsers. The drawback is that you have to run all your files through Traceur every time you save them, but this is easily automated. Additionally, if you use SystemJS, the Traceur compilation is done automatically for you.
All you need to do to get SystemJS running is to add a <script> element to load SystemJS into your webpage. It will then automatically load the ES6 module loader and Traceur files when it needs them. In your HTML you then need to use System.import to load in your module:
<script>
System.import('./app');
</script>
When you load the page, app.js will be asynchronously loaded. Within app.js, you can now use ES6 modules. SystemJS will detect that the file is an ES6 file, automatically load Traceur, and compile the file into ES5 so that it works in the browser. It does all this dynamically in the browser, but there are tools to bundle your application in production, so it doesn’t make a lot of requests on the live site. In development though, it makes for a really nice workflow.
When working with SystemJS and modules in general, the best approach is to have a main module (in our case app.js) that is the main entry point for your application. app.js should then be responsible for loading all your application’s modules. This forces you to keep your application organised by only loading one file initially, and having the rest dealt with by that file.
SystemJS also provides a workflow for bundling your application together into one file.
Conclusion
ES6 modules may be at least six months to a year away (if not more) but that doesn’t mean they can’t be used today. Although there is an overhead to using them now – with the work required to set up SystemJS, the module transpiler, or another solution – that doesn’t mean it’s not worthwhile. Using any module system in the browser, whether that be RequireJS, Browserify or another alternative, requires extra tooling and libraries to support it, and I would argue that the effort to set up SystemJS is no greater than that required to configure any other tool. It also comes with the extra benefit that when the syntax is supported in browsers, you get a free upgrade. You’ll be able to remove SystemJS and have everything continue to work, backed by the native browser solution.
If you are starting a new project, I would strongly advocate using ES6 modules. It is a syntax and specification that is not going away at all, and will soon be supported in browsers. Investing time in learning it now will pay off hugely further down the road.
Further reading
If you’d like to delve further into ES6 modules (or ES6 generally) and using them today, I recommend the following resources:
ECMAScript 6 modules: the final syntax by Axel Rauschmayer
Practical Workflows for ES6 Modules by Guy Bedford
ECMAScript 6 resources for the curious JavaScripter by Addy Osmani
Tracking ES6 support by Addy Osmani
ES6 Tools List by Addy Osmani
Using Grunt and the ES6 Module Transpiler by Thomas Boyt
JavaScript Modules and Dependencies with jspm by myself
Using ES6 Modules Today by Guy Bedford |
2014 |
Jack Franklin |
jackfranklin |
2014-12-03T00:00:00+00:00 |
https://24ways.org/2014/javascript-modules-the-es6-way/ |
code |
38 |
Websites of Christmas Past, Present and Future |
The websites of Christmas past
The first website was created at CERN. It was launched on 20 December 1990 (just in time for Christmas!), and it still works today, after twenty-four years. Isn’t that incredible?!
Why does this website still work after all this time? I can think of a few reasons.
First, the authors of this document chose HTML. Of course they couldn’t have known back then the extent to which we would be creating documents in HTML, but HTML always had a lot going for it. It’s built on top of plain text, which means it can be opened in any text editor, and it’s pretty readable, even without any parsing.
Despite the fact that HTML has changed quite a lot over the past twenty-four years, extensions to the specification have always been implemented in a backwards-compatible manner. Reading through the 1992 W3C document HTML Tags, you’ll see just how it has evolved. We still have h1 – h6 elements, but I’d not heard of the <plaintext> element before. Despite being deprecated since HTML2, it still works in several browsers. You can see it in action on my website.
As well as being written in HTML, there is no run-time compilation of code; the first website simply consists of HTML files transmitted over the web. Due to its lack of complexity, it stood a good chance of surviving in the turbulent World Wide Web.
That’s all well and good for a simple, static website. But websites created today are increasingly interactive. Many require a login and provide experiences that are tailored to the individual user. This type of dynamic website requires code to be executed somewhere.
Traditionally, dynamic websites would execute such code on the server, and transmit a simple HTML file to the user. As far as the browser was concerned, this wasn’t much different from the first website, as the additional complexity all happened before the document was sent to the browser.
Doing it all in the browser
In 2003, the first single page interface was created at slashdotslash.com. A single page interface or single page app is a website where the page is created in the browser via JavaScript. The benefit of this technique is that, after the initial page load, subsequent interactions can happen instantly, or very quickly, as they all happen in the browser.
When software runs on the client rather than the server, it is often referred to as a fat client. This means that the bulk of the processing happens on the client rather than the server (which can now be thin).
A fat client is preferred over a thin client because:
It takes some processing requirements away from the server, thereby reducing the cost of servers (a thin server requires cheaper, or fewer servers).
They can often continue working offline, provided no server communication is required to complete tasks after initial load.
The latency of internet communications is bypassed after initial load, as interactions can appear near instantaneous when compared to waiting for a response from the server.
But there are also some big downsides, and these are often overlooked:
They can’t work without JavaScript. Obviously JavaScript is a requirement for any client-side code execution. And as the UK Government Digital Service discovered, 1.1% of their visitors did not receive JavaScript enhancements. Of that 1.1%, 81% had JavaScript enabled, but their browsers failed to execute it (possibly due to dropping the internet connection). If you care about 1.1% of your visitors, you should care about the non-JavaScript experience for your website.
The browser needs to do all the processing. This means that the hardware it runs on needs to be fast. It also means that we require all clients to have largely the same capabilities and browser APIs.
The initial payload is often much larger, and nothing will be rendered for the user until this payload has been fully downloaded and executed. If the connection drops at any point, or the code fails to execute owing to a bug, we’re left with the non-JavaScript experience.
They are not easily indexed as every crawler now needs to run JavaScript just to receive the content of the website.
These are not merely edge case issues to shirk off. The first three issues will affect some of your visitors; the fourth affects everyone, including you.
What problem are we trying to solve?
So what can be done to address these issues? Whereas fat clients solve some inherent issues with the web, they seem to create as many problems. When attempting to resolve any issue, it’s always good to try to uncover the original problem and work forwards from there. One of the best ways to frame a problem is as a user story. A user story considers the who, what and why of a need. Here’s a template:
As a {who} I want {what} so that {why}
I haven’t got a specific project in mind, so let’s refer to the who as user. Here’s one that could explain the use of thick clients.
As a user I want the site to respond to my actions quickly so that I get immediate feedback when I do something.
This user story could probably apply to a great number of websites, but so could this:
As a user I want to get to the content quickly, so that I don’t have to wait too long to find out what the site is all about or get the content I need.
A better solution
How can we balance both these user needs? How can we have a website that loads fast, and also reacts fast? The solution is to have a thick server, that serves the complete document, and then a thick client, that manages subsequent actions and replaces parts of the page. What we’re talking about here is simply progressive enhancement, but from the user’s perspective.
The initial payload contains the entire document. At this point, all interactions would happen in a traditional way using links or form elements. Then, once we’ve downloaded the JavaScript (asynchronously, after load) we can enhance the experience with JavaScript interactions. If for whatever reason our JavaScript fails to download or execute, it’s no biggie – we’ve already got a fully functioning website. If an API that we need isn’t available in this browser, it’s not a problem. We just fall back to the basic experience.
This second point, of having some minimum requirement for an enhanced experience, is often referred to as cutting the mustard, first used in this sense by the BBC News team. Essentially it’s an if statement like this:
if('querySelector' in document
&& 'localStorage' in window
&& 'addEventListener' in window) {
// bootstrap the JavaScript application
}
This code states that the browser must support the following methods before downloading and executing the JavaScript:
document.querySelector (can it find elements by CSS selectors)
window.localStorage (can it store strings)
window.addEventListener (can it bind to events in a standards-compliant way)
These three properties are what the BBC News team decided to test for, as they are present in their website’s JavaScript. Each website will have its own requirements. The last method, window.addEventListener is in interesting one. Although it’s simple to bind to events on IE8 and earlier, these browsers have very inconsistent support for standards. Making any JavaScript-heavy website work on IE8 and earlier is a painful exercise, and comes at a cost to all users on other browsers, as they’ll download unnecessary code to patch support for IE.
JavaScript API support by browser.
I discovered that IE8 supports 12% of the current JavaScript APIs, while IE9 supports 16%, and IE10 51%. It seems, then, that IE10 could be the earliest version of IE that I’d like to develop JavaScript for. That doesn’t mean that users on browsers earlier than 10 can’t use the website. On the contrary, they get the core experience, and because it’s just HTML and CSS, it’s much more likely to be bug-free, and could even provide a better experience than trying to run JavaScript in their browser. They receive the thin client experience.
By reducing the number of platforms that our enhanced JavaScript version supports, we can better focus our efforts on those platforms and offer an even greater experience to those users. But we can only do that if we use progressive enhancement. Otherwise our website would be completely broken for all other users.
So what we have is a thick server, capable of serving the entire website to our users, complete with all core functionality needed for our users to complete their tasks; and we have a thick client on supported browsers, which can bring an even greater experience to those users.
This is all transparent to users. They may notice that the website seems snappier on the new iPhone they received for Christmas than on the Windows 7 machine they got five years ago, but then they probably expected it to be faster on their iPhone anyway.
Isn’t this just more work?
It’s true that making a thick server and a thick client is more work than just making one or the other. But there are some big advantages:
The website works for everyone.
You can decide when users get the enhanced experience.
You can enhance features in an iterative (or agile) manner.
When the website breaks, it doesn’t break down.
The more you practise this approach, the quicker you will become.
The websites of Christmas present
The best way to discover websites using this technique of progressive enhancement is to disable JavaScript and see if the website breaks. I use the Web Developer extension, which is available for Chrome and Firefox. It lets me quickly disable JavaScript.
Web Developer extension.
24 ways works with and without JavaScript. Try using the menu icon to view the navigation. Without JavaScript, it’s a jump link to the bottom of the page, but with JavaScript, the menu slides in from the right.
24 ways navigation with JavaScript disabled.
24 ways navigation with working JavaScript.
Google search will also work without JavaScript. You won’t get instant search results or any prerendering, because those are enhancements.
For a more app-like example, try using Twitter. Without JavaScript, it still works, and looks nearly identical. But when you load JavaScript, links open in modal windows and all pages are navigated much quicker, as only the content that has changed is loaded. You can read about how they achieved this in Twitter’s blog posts Improving performance on twitter.com and Implementing pushState for twitter.com.
Unfortunately Facebook doesn’t use progressive enhancement, which not only means that the website doesn’t work without JavaScript, but it takes longer to load. I tested it on WebPagetest and if you compare the load times of Twitter and Facebook, you’ll notice that, despite putting similar content on the page, Facebook takes two and a half times longer to render the core content on the page.
Facebook takes two and a half times longer to load than Twitter.
Websites of Christmas yet to come
Every project is different, and making a website that enjoys a long life, or serves a larger number of users may or may not be a high priority. But I hope I’ve convinced you that it certainly is possible to look to the past and future simultaneously, and that there can be significant advantages to doing so. |
2014 |
Josh Emerson |
joshemerson |
2014-12-08T00:00:00+00:00 |
https://24ways.org/2014/websites-of-christmas-past-present-and-future/ |
code |
42 |
An Overview of SVG Sprite Creation Techniques |
SVG can be used as an icon system to replace icon fonts. The reasons why SVG makes for a superior icon system are numerous, but we won’t be going over them in this article. If you don’t use SVG icons and are interested in knowing why you may want to use them, I recommend you check out “Inline SVG vs Icon Fonts” by Chris Coyier – it covers the most important aspects of both systems and compares them with each other to help you make a better decision about which system to choose.
Once you’ve made the decision to use SVG instead of icon fonts, you’ll need to think of the best way to optimise the delivery of your icons, and ways to make the creation and use of icons faster.
Just like bitmaps, we can create image sprites with SVG – they don’t look or work exactly alike, but the basic concept is pretty much the same.
There are several ways to create SVG sprites, and this article will give you an overview of three of them. While we’re at it, we’re going to take a look at some of the available tools used to automate sprite creation and fallback for us.
Prerequisites
The content of this article assumes you are familiar with SVG. If you’ve never worked with SVG before, you may want to look at some of the introductory tutorials covering SVG syntax, structure and embedding techniques. I recommend the following:
SVG basics: Using SVG.
Structure: Structuring, Grouping, and Referencing in SVG — The <g>, <use>, <defs> and <symbol> Elements. We’ll mention <use> and <symbol> quite a bit in this article.
Embedding techniques: Styling and Animating SVGs with CSS. The article covers several topics, but the section linked focuses on embedding techniques.
A compendium of SVG resources compiled by Chris Coyier — contains resources to almost every aspect of SVG you might be interested in.
And if you’re completely new to the concept of spriting, Chris Coyier’s CSS Sprites explains all about them.
Another important SVG feature is the viewBox attribute. For some of the techniques, knowing your way around this attribute is not required, but it’s definitely more useful if you understand – even if just vaguely – how it works. The last technique mentioned in the article requires that you do know the attribute’s syntax and how to use it. To learn all about viewBox, you can refer to my blog post about SVG coordinate systems.
With the prerequisites in place, let’s move on to spriting SVGs!
Before you sprite…
In order to create an SVG sprite with your icons, you’ll of course need to have these icons ready for use.
Some spriting tools require that you place your icons in a folder to which a certain spriting process is to be applied. As such, for all of the upcoming sections we’ll work on the assumption that our SVG icons are placed in a folder named SVG.
Each icon is an individual .svg file.
You’ll need to make sure each icon is well-prepared and optimised for use – make sure you’ve cleaned up the code by running it through one of the optimisation tools or processes available (or doing it manually if it’s not tedious).
After prepping the icon files and placing them in a folder, we’re ready to create our SVG sprite.
HTML inline SVG sprites
Since SVG is XML code, it can be embedded inline in an HTML document as a code island using the <svg> element. Chris Coyier wrote about this technique first on CSS-Tricks.
The embedded SVG will serve as a container for our icons and is going to be the actual sprite we’re going to use. So we’ll start by including the SVG in our document.
<!DOCTYPE html>
<!-- HTML document stuff -->
<svg style="display:none;">
<!-- icons here -->
</svg>
<!-- other document stuff -->
</html>
Next, we’re going to place the icons inside the <svg>. Each icon will be wrapped in a <symbol> element we can then reference and use elsewhere in the page using the SVG <use> element. The <symbol> element has many benefits, and we’re using it because it allows us to define a symbol (which is a convenient markup for an icon) without rendering that symbol on the screen. The elements defined inside <symbol> will only be rendered when they are referenced – or called – by the <use> element.
Moreover, <symbol> can have its own viewBox attribute, which makes it possible to control the positioning of its content inside its container at any time.
Before we move on, I’d like to shed some light on the style="display:none;" part of the snippet above. Without setting the display of the SVG to none, and even though its contents are not rendered on the page, the SVG will still take up space in the page, resulting in a big empty area. In order to avoid that, we’re hiding the SVG entirely with CSS.
Now, suppose we have a Twitter icon in the icons folder. twitter.svg might look something like this:
<!-- twitter.svg -->
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="32" height="32" viewBox="0 0 32 32">
<path d="M32 6.076c-1.177 0.522-2.443 0.875-3.771 1.034 1.355-0.813 2.396-2.099 2.887-3.632-1.269 0.752-2.674 1.299-4.169 1.593-1.198-1.276-2.904-2.073-4.792-2.073-3.626 0-6.565 2.939-6.565 6.565 0 0.515 0.058 1.016 0.17 1.496-5.456-0.274-10.294-2.888-13.532-6.86-0.565 0.97-0.889 2.097-0.889 3.301 0 2.278 1.159 4.287 2.921 5.465-1.076-0.034-2.088-0.329-2.974-0.821-0.001 0.027-0.001 0.055-0.001 0.083 0 3.181 2.263 5.834 5.266 6.437-0.551 0.15-1.131 0.23-1.73 0.23-0.423 0-0.834-0.041-1.235-0.118 0.835 2.608 3.26 4.506 6.133 4.559-2.247 1.761-5.078 2.81-8.154 2.81-0.53 0-1.052-0.031-1.566-0.092 2.905 1.863 6.356 2.95 10.064 2.95 12.076 0 18.679-10.004 18.679-18.68 0-0.285-0.006-0.568-0.019-0.849 1.283-0.926 2.396-2.082 3.276-3.398z" fill="#000000"></path>
</svg>
We don’t need the root svg element, so we’ll strip the code and only keep the parts that make up the Twitter icon’s shape, which in this example is just the <path> element.Let’s drop that into the sprite container like so:
<svg style="display:none;">
<symbol id="twitter-icon" viewBox="0 0 32 32">
<path d="M32 6.076c-1.177 …" fill="#000000"></path>
</symbol>
<!-- remaining icons here -->
<symbol id="instagram-icon" viewBox="0 0 32 32">
<!-- icon contents -->
</symbol>
<!-- etc. -->
</svg>
Repeat for the other icons.
The value of the <symbol> element’s viewBox attribute depends on the size of the SVG. You don’t need to know how the viewBox works to use it in this case. Its value is made up of four parts: the first two will almost always be “0 0”; the second two will be equal to the size of the icon. For example, our Twitter icon is 32px by 32px (see twitter.svg above), so the viewBox value is “0 0 32 32”.
That said, it is certainly useful to understand how the viewBox works – it can help you troubleshoot SVG sometimes and gives you better control over it, allowing you to scale, position and even crop SVGs manually without having to resort to an editor. My blog post explains all about the viewBox attribute and its related attributes.
Once you have your SVG sprite ready, you can display the icons anywhere on the page by referencing them using the SVG <use> element:
<svg class="twitter-icon">
<use xlink:href="#twitter-icon"></use>
<svg>
And that’s all there is to it!
HTML-inline SVG sprites are simple to create and use, but when you have a lot of icons (and the more icon sets you create) it can easily become daunting if you have to manually transfer the icons into the <svg>. Fortunately, you don’t have to do that. Fabrice Weinberg created a Grunt plugin called grunt-svgstore which takes the icons in your SVG folder and generates the SVG sprites for you; all you have to do is just drop the sprites into your page and use the icons like we did earlier.
This technique works in all browsers supporting SVG. There seems to be a bug in Safari on iOS which causes the icons not to show up when the SVG sprite is defined at the bottom of the document after the <use> references to the icons, so it’s safest to include the sprite before you use the icons until this bug is fixed.
This technique has one disadvantage: the SVG sprite cannot be cached. We’re saving an extra HTTP request here but the browser cannot cache the image, so we aren’t speeding up any subsequent page loads by inlining the SVG. There must be a better way – and there is.
Styling the icons is possible, but getting deep into the styles becomes a bit harder owing to the nature of the contents of the <use> element – these contents are cloned into a shadow DOM, and hence selecting elements in CSS the traditional way is not possible. However, some techniques to work around that do exist, and give us slightly more styling flexibility. Animations work as expected.
Referencing an external SVG sprite in HTML
Instead of including the SVG inline in the document, you can reference the sprite and the icons inside it externally, taking advantage of fragment identifiers to select individual icons in the sprite.
For example, the above reference to the Twitter icon would look something like this instead:
<svg class="twitter-icon">
<use xlink:href="path/to/icons.svg#twitter-icon"></use>
<svg>
icons.svg is the name of the SVG file that contains all of our icons as symbols, and the fragment identifier #twitter-icon is the reference to the <symbol> wrapping the Twitter icon’s contents. Very convenient, isn’t it? The browser will request the sprite and then cache it, speeding up subsequent page loads. Win!
This technique also works in all browsers supporting SVG except Internet Explorer – not even IE9+ with SVG support permits this technique. No version of IE supports referencing an external SVG in <use>.
Fortunately (again), Jonathan Neil has created a plugin called svg4everybody which fills this gap in IE; you can reference an external sprite in <use> and also provide fallback for browsers that do not support SVG. However, it requires you to have the fallback images (PNG or JPEG, for example) available to do so. For details, refer to the plugin’s Github repository’s readme file.
CSS inline SVG sprites
Another way to create an SVG sprite is by inlining the SVG icons in a style sheet using data URIs, and providing fallback for non-supporting browsers – also within the CSS.
Using this approach, we’re turning the style sheet into the sprite that includes our icons. The style sheet is normally cached by the browser, so we have that concern out of the way.
This technique is put into practice in Filament Group’s icon system approach, which uses their Grunticon plugin – or its sister Grumpicon web app – for generating the necessary CSS for the sprite. As such, we’re going to cover this technique by following a workflow that uses one of these tools.
Again, we start with our icon SVG files. To focus on the actual spriting method and not on the tooling, I’ll go over the process of sprite creation using the Grumpicon web app, instead of the Grunticon plugin. Both tools generate the same resources that we’re going to use for the icon system. Whether you choose the web app or the Grunt set-up, after processing your SVG folder you’re going to end up with the same set of resources that we’ll be using throughout this section.
The first step is to drop your icons into the Grumpicon web app.
Grumpicon homepage screenshot.
The application will then show you a preview of your icons, and a download button will allow you to download the generated files. These files will contain everything you need for your icon system – all that’s left is for you to drop the generated files and code into your project as recommended and you’ll have your sprite and icons ready to use anywhere you want in your page.
Grumpicon generates five files and one folder in the downloaded package: a png folder containing PNG versions of your icons; three style sheets (that we’ll go over briefly); a loader script file; and preview.html which is a live example showing you the other files in action.
The script in the loader goes into the <head> of your page. This script handles browser and feature detection, and requests the necessary style sheet depending on browser support for SVG and base64 data URIs. If you view the source code of the preview page, you can see exactly how the script is added.
icons.data.svg.css is the style sheet that contains your icons – the sprite. The icons are embedded inline inside the style sheet using data URIs, and applied to elements of your choice as background images, using class names. For example:
.twitter-icon{
background-image: url('data:image/svg+xml;…'); /* the ellipsis is where the icon’s data would go */
background-repeat: no-repeat;
background-position: 50% 50%;
height: 2em;
width: 2em;
/* etc. */
}
Then, you only have to apply the twitter-icon class name to an element in your HTML to apply the icon as a background to it:
<span class="twitter-icon"></span>
And that’s all you need to do to get an icon on the page.
icons.data.svg.css, along with the other two style sheets and the png folder should be added to your CSS folder.
icons.data.png.css is the style sheet the script will load in browsers that don’t support SVG, such as IE8. Fallback for the inline SVG is provided as a base64-encoded PNG. For instance, the fallback for the Twitter icon from our example would look like so:
.twitter-icon{
background-image: url('data:image/png;base64;…’);
/* etc. */
}
icons.fallback.css is the style sheet required for browsers that don’t support base64-encoded PNGs – the PNG images are loaded as usual using the image’s URL. The script will load this style sheet for IE6 and IE7, for example.
.twitter-icon{
background-image: url(png/twitter-icon.png);
/* etc. */
}
This technique is very different from the previous one. The sprite in this case is literally the style sheet, not an SVG container, and the icon usage is very similar to that of a CSS sprite – the icons are provided as background images.
This technique has advantages and disadvantages. For the sake of brevity, I won’t go into further details, but the main limitations worth mentioning are that SVGs embedded as background images cannot be styled with CSS; and animations are restricted to those defined inside the <svg> for each icon. CSS interactions (such as hover effects) don’t work either. Thus, to apply an effect for an icon that changes its color on hover, for example, you’ll need to export a set of SVGs for each colour in order for Grumpicon to create matching fallback PNG images that can then be used for the animation.
For more details about the Grumpicon workflow, I recommend you check out “A Designer’s Guide to Grumpicon” on Filament Group’s website.
Using SVG fragment identifiers and views
This spriting technique is, again, different from the previous ones, and it is my personal favourite.
SVG comes with a standard way of cropping to a specific area in a particular SVG image. If you’ve ever worked with CSS sprites before then this definitely sounds familiar: it’s almost exactly what we do with CSS sprites – the image containing all of the icons is cropped, so to speak, to show only the one icon that we want in the background positioning area of the element, using background size and positioning properties.
Instead of using background properties, we’ll be using SVG’s viewBox attribute to crop our SVG to the specific icon we want.
What I like about this technique is that it is more visual than the previous ones. Using this technique, the SVG sprite is treated like an actual image containing other images (the icons), instead of treating it as a piece of code containing other code.
Again, our SVG icons are placed inside a main SVG container that is going to be our SVG sprite. If you’re working in a graphics editor, position or arrange your icons inside the canvas any way you want them to be, and then export the graphic as is. Of course, the less empty space there is in your SVG, the better.
In our example, the sprite contains three icons as shown in the following image. The sprite is open in Sketch. Notice how the SVG is just big enough to fit the icons inside it. It doesn’t have to be like this, but it’s cleaner this way.
Screenshot showing the SVG sprite containing our icons.
Now, suppose you want to display only the Instagram icon. Using the SVG viewBox attribute, we can crop the SVG to the icon. The Instagram icon is positioned at 64px along the positive x-axis, and zero pixels along the y-axis. It is also 32px by 32px in size.
Screenshot showing the position (offset) of the Instagram icon inside the SVG sprite, and its size.
Using this information, we can specify the value of the viewBox as: 64 0 32 32. This area of the view box contains only the Instagram icon. 64 0 specifies the top-left corner of the view box area, and 32 32 specify its dimensions.
Now, if we were to change the viewBox value on the SVG sprite to this value, only the Instagram icon will be visible inside the SVG viewport. Great. But how do we use this information to display the icon in our page using our sprite?
SVG comes with a native way to link to portions or areas of an image using fragment identifiers. Fragment identifiers are used to link into a particular view area of an SVG document. Thus, using a fragment identifier and the boundaries of the area that we want (from the viewBox), we can link to that area and display it.
For example, if you want to display the icon from the sprite using an <img> tag, you can reference the icon in the sprite like so:
<img src='uiIcons.svg#svgView(viewBox(64, 0, 32, 32))' alt="Settings icon"/>
The fragment identifier in the snippet above (#svgView(viewBox(64, 0, 32, 32))) is the important part. This will result in only the Instagram icon’s area of the sprite being displayed.
There is also another way to do this, using the SVG <view> element. The <view> element can be used to define a view area and then reference that area somewhere else. For example, to define the view box containing the Instagram icon, we can do the following:
<view id='instagram-icon' viewBox='64 0 32 32' />
Then, we can reference this view in our <img> element like this:
<img src='sprite.svg#instagram-icon' alt="Instagram icon" />
The best part about this technique – besides the ability to reference an external SVG and hence make use of browser caching – is that it allows us to use practically any SVG embedding technique and does not restrict us to specific tags.
It goes without saying that this feature can be used for more than just icon systems, owing to viewBox’s power in controlling an SVG’s viewable area.
SVG fragment identifiers have decent browser support, but the technique is buggy in Safari: there is a bug that causes problems when loading a server SVG file and then using fragment identifiers with it. Bear Travis has documented the issue and a workaround.
Where to go from here
Pick the technique that works best for your project. Each technique has its own pros and cons, relating to convenience and maintainability, performance, and styling and scripting. Each technique also requires its own fallback mechanism.
The spriting techniques mentioned here are not the only techniques available. Other methods exist, such as SVG stacks, and others may surface in future, but these are the three main ones today.
The third technique using SVG’s built-in viewBox features is my favourite, and with better browser support and fewer (ideally, no) bugs, I believe it is more likely to become the standard way to create and use SVG sprites. Fallback techniques can be created, of course, in one of many possible ways.
Do you use SVG for your icon system? If so, which is your favourite technique? Do you know or have worked with other ways for creating SVG sprites? |
2014 |
Sara Soueidan |
sarasoueidan |
2014-12-16T00:00:00+00:00 |
https://24ways.org/2014/an-overview-of-svg-sprite-creation-techniques/ |
code |
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 |
49 |
Universal React |
One of the libraries to receive a huge amount of focus in 2015 has been ReactJS, a library created by Facebook for building user interfaces and web applications.
More generally we’ve seen an even greater rise in the number of applications built primarily on the client side with most of the logic implemented in JavaScript. One of the main issues with building an app in this way is that you immediately forgo any customers who might browse with JavaScript turned off, and you can also miss out on any robots that might visit your site to crawl it (such as Google’s search bots). Additionally, we gain a performance improvement by being able to render from the server rather than having to wait for all the JavaScript to be loaded and executed.
The good news is that this problem has been recognised and it is possible to build a fully featured client-side application that can be rendered on the server. The way in which these apps work is as follows:
The user visits www.yoursite.com and the server executes your JavaScript to generate the HTML it needs to render the page.
In the background, the client-side JavaScript is executed and takes over the duty of rendering the page.
The next time a user clicks, rather than being sent to the server, the client-side app is in control.
If the user doesn’t have JavaScript enabled, each click on a link goes to the server and they get the server-rendered content again.
This means you can still provide a very quick and snappy experience for JavaScript users without having to abandon your non-JS users. We achieve this by writing JavaScript that can be executed on the server or on the client (you might have heard this referred to as isomorphic) and using a JavaScript framework that’s clever enough handle server- or client-side execution. Currently, ReactJS is leading the way here, although Ember and Angular are both working on solutions to this problem.
It’s worth noting that this tutorial assumes some familiarity with React in general, its syntax and concepts. If you’d like a refresher, the ReactJS docs are a good place to start.
Getting started
We’re going to create a tiny ReactJS application that will work on the server and the client. First we’ll need to create a new project and install some dependencies. In a new, blank directory, run:
npm init -y
npm install --save ejs express react react-router react-dom
That will create a new project and install our dependencies:
ejs is a templating engine that we’ll use to render our HTML on the server.
express is a small web framework we’ll run our server on.
react-router is a popular routing solution for React so our app can fully support and respect URLs.
react-dom is a small React library used for rendering React components.
We’re also going to write all our code in ECMAScript 6, and therefore need to install BabelJS and configure that too.
npm install --save-dev babel-cli babel-preset-es2015 babel-preset-react
Then, create a .babelrc file that contains the following:
{
"presets": ["es2015", "react"]
}
What we’ve done here is install Babel’s command line interface (CLI) tool and configured it to transform our code from ECMAScript 6 (or ES2015) to ECMAScript 5, which is more widely supported. We’ll need the React transforms when we start writing JSX when working with React.
Creating a server
For now, our ExpressJS server is pretty straightforward. All we’ll do is render a view that says ‘Hello World’. Here’s our server code:
import express from 'express';
import http from 'http';
const app = express();
app.use(express.static('public'));
app.set('view engine', 'ejs');
app.get('*', (req, res) => {
res.render('index');
});
const server = http.createServer(app);
server.listen(3003);
server.on('listening', () => {
console.log('Listening on 3003');
});
Here we’re using ES6 modules, which I wrote about on 24 ways last year, if you’d like a reminder. We tell the app to render the index view on any GET request (that’s what app.get('*') means, the wildcard matches any route).
We now need to create the index view file, which Express expects to be defined in views/index.ejs:
<!DOCTYPE html>
<html>
<head>
<title>My App</title>
</head>
<body>
Hello World
</body>
</html>
Finally, we’re ready to run the server. Because we installed babel-cli earlier we have access to the babel-node executable, which will transform all your code before running it through node. Run this command:
./node_modules/.bin/babel-node server.js
And you should now be able to visit http://localhost:3003 and see ‘Hello World’ right there:
Building the React app
Now we’ll build the React application entirely on the server, before adding the client-side JavaScript right at the end. Our app will have two routes, / and /about which will both show a small amount of content. This will demonstrate how to use React Router on the server side to make sure our React app plays nicely with URLs.
Firstly, let’s update views/index.ejs. Our server will figure out what HTML it needs to render, and pass that into the view. We can pass a value into our view when we render it, and then use EJS syntax to tell it to output that data. Update the template file so the body looks like so:
<body>
<%- markup %>
</body>
Next, we’ll define the routes we want our app to have using React Router. For now we’ll just define the index route, and not worry about the /about route quite yet. We could define our routes in JSX, but I think for server-side rendering it’s clearer to define them as an object. Here’s what we’re starting with:
const routes = {
path: '',
component: AppComponent,
childRoutes: [
{
path: '/',
component: IndexComponent
}
]
}
These are just placed at the top of server.js, after the import statements. Later we’ll move these into a separate file, but for now they are fine where they are.
Notice how I define first that the AppComponent should be used at the '' path, which effectively means it matches every single route and becomes a container for all our other components. Then I give it a child route of /, which will match the IndexComponent. Before we hook these routes up with our server, let’s quickly define components/app.js and components/index.js. app.js looks like so:
import React from 'react';
export default class AppComponent extends React.Component {
render() {
return (
<div>
<h2>Welcome to my App</h2>
{ this.props.children }
</div>
);
}
}
When a React Router route has child components, they are given to us in the props under the children key, so we need to include them in the code we want to render for this component. The index.js component is pretty bland:
import React from 'react';
export default class IndexComponent extends React.Component {
render() {
return (
<div>
<p>This is the index page</p>
</div>
);
}
}
Server-side routing with React Router
Head back into server.js, and firstly we’ll need to add some new imports:
import React from 'react';
import { renderToString } from 'react-dom/server';
import { match, RoutingContext } from 'react-router';
import AppComponent from './components/app';
import IndexComponent from './components/index';
The ReactDOM package provides react-dom/server which includes a renderToString method that takes a React component and produces the HTML string output of the component. It’s this method that we’ll use to render the HTML from the server, generated by React. From the React Router package we use match, a function used to find a matching route for a URL; and RoutingContext, a React component provided by React Router that we’ll need to render. This wraps up our components and provides some functionality that ties React Router together with our app. Generally you don’t need to concern yourself about how this component works, so don’t worry too much.
Now for the good bit: we can update our app.get('*') route with the code that matches the URL against the React routes:
app.get('*', (req, res) => {
// routes is our object of React routes defined above
match({ routes, location: req.url }, (err, redirectLocation, props) => {
if (err) {
// something went badly wrong, so 500 with a message
res.status(500).send(err.message);
} else if (redirectLocation) {
// we matched a ReactRouter redirect, so redirect from the server
res.redirect(302, redirectLocation.pathname + redirectLocation.search);
} else if (props) {
// if we got props, that means we found a valid component to render
// for the given route
const markup = renderToString(<RoutingContext {...props} />);
// render `index.ejs`, but pass in the markup we want it to display
res.render('index', { markup })
} else {
// no route match, so 404. In a real app you might render a custom
// 404 view here
res.sendStatus(404);
}
});
});
We call match, giving it the routes object we defined earlier and req.url, which contains the URL of the request. It calls a callback function we give it, with err, redirectLocation and props as the arguments. The first two conditionals in the callback function just deal with an error occuring or a redirect (React Router has built in redirect support). The most interesting bit is the third conditional, else if (props). If we got given props and we’ve made it this far it means we found a matching component to render and we can use this code to render it:
...
} else if (props) {
// if we got props, that means we found a valid component to render
// for the given route
const markup = renderToString(<RoutingContext {...props} />);
// render `index.ejs`, but pass in the markup we want it to display
res.render('index', { markup })
} else {
...
}
The renderToString method from ReactDOM takes that RoutingContext component we mentioned earlier and renders it with the properties required. Again, you need not concern yourself with what this specific component does or what the props are. Most of this is data that React Router provides for us on top of our components.
Note the {...props}, which is a neat bit of JSX syntax that spreads out our object into key value properties. To see this better, note the two pieces of JSX code below, both of which are equivalent:
<MyComponent a="foo" b="bar" />
// OR:
const props = { a: "foo", b: "bar" };
<MyComponent {...props} />
Running the server again
I know that felt like a lot of work, but the good news is that once you’ve set this up you are free to focus on building your React components, safe in the knowledge that your server-side rendering is working. To check, restart the server and head to http://localhost:3003 once more. You should see it all working!
Refactoring and one more route
Before we move on to getting this code running on the client, let’s add one more route and do some tidying up. First, move our routes object out into routes.js:
import AppComponent from './components/app';
import IndexComponent from './components/index';
const routes = {
path: '',
component: AppComponent,
childRoutes: [
{
path: '/',
component: IndexComponent
}
]
}
export { routes };
And then update server.js. You can remove the two component imports and replace them with:
import { routes } from './routes';
Finally, let’s add one more route for ./about and links between them. Create components/about.js:
import React from 'react';
export default class AboutComponent extends React.Component {
render() {
return (
<div>
<p>A little bit about me.</p>
</div>
);
}
}
And then you can add it to routes.js too:
import AppComponent from './components/app';
import IndexComponent from './components/index';
import AboutComponent from './components/about';
const routes = {
path: '',
component: AppComponent,
childRoutes: [
{
path: '/',
component: IndexComponent
},
{
path: '/about',
component: AboutComponent
}
]
}
export { routes };
If you now restart the server and head to http://localhost:3003/about` you’ll see the about page!
For the finishing touch we’ll use the React Router link component to add some links between the pages. Edit components/app.js to look like so:
import React from 'react';
import { Link } from 'react-router';
export default class AppComponent extends React.Component {
render() {
return (
<div>
<h2>Welcome to my App</h2>
<ul>
<li><Link to='/'>Home</Link></li>
<li><Link to='/about'>About</Link></li>
</ul>
{ this.props.children }
</div>
);
}
}
You can now click between the pages to navigate. However, everytime we do so the requests hit the server. Now we’re going to make our final change, such that after the app has been rendered on the server once, it gets rendered and managed in the client, providing that snappy client-side app experience.
Client-side rendering
First, we’re going to make a small change to views/index.ejs. React doesn’t like rendering directly into the body and will give a warning when you do so. To prevent this we’ll wrap our app in a div:
<body>
<div id="app"><%- markup %></div>
<script src="build.js"></script>
</body>
I’ve also added in a script tag to build.js, which is the file we’ll generate containing all our client-side code.
Next, create client-render.js. This is going to be the only bit of JavaScript that’s exclusive to the client side. In it we need to pull in our routes and render them to the DOM.
import React from 'react';
import ReactDOM from 'react-dom';
import { Router } from 'react-router';
import { routes } from './routes';
import createBrowserHistory from 'history/lib/createBrowserHistory';
ReactDOM.render(
<Router routes={routes} history={createBrowserHistory()} />,
document.getElementById('app')
)
The first thing you might notice is the mention of createBrowserHistory. React Router is built on top of the history module, a module that listens to the browser’s address bar and parses the new location. It has many modes of operation: it can keep track using a hashbang, such as http://localhost/#!/about (this is the default), or you can tell it to use the HTML5 history API by calling createBrowserHistory, which is what we’ve done. This will keep the URLs nice and neat and make sure the client and the server are using the same URL structure. You can read more about React Router and histories in the React Router documentation.
Finally we use ReactDOM.render and give it the Router component, telling it about all our routes, and also tell ReactDOM where to render, the #app element.
Generating build.js
We’re actually almost there! The final thing we need to do is generate our client side bundle. For this we’re going to use webpack, a module bundler that can take our application, follow all the imports and generate one large bundle from them. We’ll install it and babel-loader, a webpack plugin for transforming code through Babel.
npm install --save-dev webpack babel-loader
To run webpack we just need to create a configuration file, called webpack.config.js. Create the file in the root of our application and add the following code:
var path = require('path');
module.exports = {
entry: path.join(process.cwd(), 'client-render.js'),
output: {
path: './public/',
filename: 'build.js'
},
module: {
loaders: [
{
test: /.js$/,
loader: 'babel'
}
]
}
}
Note first that this file can’t be written in ES6 as it doesn’t get transformed. The first thing we do is tell webpack the main entry point for our application, which is client-render.js. We use process.cwd() because webpack expects an exact location – if we just gave it the string ‘client-render.js’, webpack wouldn’t be able to find it.
Next, we tell webpack where to output our file, and here I’m telling it to place the file in public/build.js. Finally we tell webpack that every time it hits a file that ends in .js, it should use the babel-loader plugin to transform the code first.
Now we’re ready to generate the bundle!
./node_modules/.bin/webpack
This will take a fair few seconds to run (on my machine it’s about seven or eight), but once it has it will have created public/build.js, a client-side bundle of our application. If you restart your server once more you’ll see that we can now navigate around our application without hitting the server, because React on the client takes over. Perfect!
The first bundle that webpack generates is pretty slow, but if you run webpack -w it will go into watch mode, where it watches files for changes and regenerates the bundle. The key thing is that it only regenerates the small pieces of the bundle it needs, so while the first bundle is very slow, the rest are lightning fast. I recommend leaving webpack constantly running in watch mode when you’re developing.
Conclusions
First, if you’d like to look through this code yourself you can find it all on GitHub. Feel free to raise an issue there or tweet me if you have any problems or would like to ask further questions.
Next, I want to stress that you shouldn’t use this as an excuse to build all your apps in this way. Some of you might be wondering whether a static site like the one we built today is worth its complexity, and you’d be right. I used it as it’s an easy example to work with but in the future you should carefully consider your reasons for wanting to build a universal React application and make sure it’s a suitable infrastructure for you.
With that, all that’s left for me to do is wish you a very merry Christmas and best of luck with your React applications! |
2015 |
Jack Franklin |
jackfranklin |
2015-12-05T00:00:00+00:00 |
https://24ways.org/2015/universal-react/ |
code |
52 |
Git Rebasing: An Elfin Workshop Workflow |
This year Santa’s helpers have been tasked with making a garland. It’s a pretty simple task: string beads onto yarn in a specific order. When the garland reaches a specific length, add it to the main workshop garland. Each elf has a specific sequence they’re supposed to chain, which is given to them via a work order. (This is starting to sound like one of those horrible calculus problems. I promise it isn’t. It’s worse; it’s about Git.)
For the most part, the system works really well. The elves are able to quickly build up a shared chain because each elf specialises on their own bit of garland, and then links the garland together. Because of this they’re able to work independently, but towards the common goal of making a beautiful garland.
At first the elves are really careful with each bead they put onto the garland. They check with one another before merging their work, and review each new link carefully. As time crunches on, the elves pour a little more cheer into the eggnog cooler, and the quality of work starts to degrade. Tensions rise as mistakes are made and unkind words are said. The elves quickly realise they’re going to need a system to change the beads out when mistakes are made in the chain.
The first common mistake is not looking to see what the latest chain is that’s been added to the main garland. The garland is huge, and it sits on a roll in one of the corners of the workshop. It’s a big workshop, so it is incredibly impractical to walk all the way to the roll to check what the last link is on the chain. The elves, being magical, have set up a monitoring system that allows them to keep a local copy of the main garland at their workstation. It’s an imperfect system though, so the elves have to request a manual refresh to see the latest copy. They can request a new copy by running the command
git pull --rebase=preserve
(They found that if they ran git pull on its own, they ended up with weird loops of extra beads off the main garland, so they’ve opted to use this method.) This keeps the shared garland up to date, which makes things a lot easier. A visualisation of the rebase process is available.
The next thing the elves noticed is that if they worked on the main workshop garland, they were always running into problems when they tried to share their work back with the rest of the workshop. It was fine if they were working late at night by themselves, but in the middle of the day, it was horrible. (I’ve been asked not to talk about that time the fight broke out.) Instead of trying to share everything on their local copy of the main garland, the elves have realised it’s a lot easier to work on a new string and then knot this onto the main garland when their pattern repeat is finished. They generate a new string by issuing the following commands:
git checkout master
git checkout -b 1234_pattern-name
1234 represents the work order number and pattern-name describes the pattern they’re adding. Each bead is then added to the new link (git add bead.txt) and locked into place (git commit). Each elf repeats this process until the sequence of beads described in the work order has been added to their mini garland.
To combine their work with the main garland, the elves need to make a few decisions. If they’re making a single strand, they issue the following commands:
git checkout master
git merge --ff-only 1234_pattern-name
To share their work they publish the new version of the main garland to the workshop spool with the command git push origin master.
Sometimes this fails. Sharing work fails because the workshop spool has gotten new links added since the elf last updated their copy of the main workshop spool. This makes the elves both happy and sad. It makes them happy because it means the other elves have been working too, but it makes them sad because they now need to do a bit of extra work to close their work order.
To update the local copy of the workshop spool, the elf first unlinks the chain they just linked by running the command:
git reset --merge ORIG_HEAD
This works because the garland magic notices when the elves are doing a particularly dangerous thing and places a temporary, invisible bookmark to the last safe bead in the chain before the dangerous thing happened. The garland no longer has the elf’s work, and can be updated safely. The elf runs the command git pull --rebase=preserve and the changes all the other elves have made are applied locally.
With these new beads in place, the elf now has to restring their own chain so that it starts at the right place. To do this, the elf turns back to their own chain (git checkout 1234_pattern-name) and runs the command git rebase master. Assuming their bead pattern is completely unique, the process will run and the elf’s beads will be restrung on the tip of the main workshop garland.
Sometimes the magic fails and the elf has to deal with merge conflicts. These are kind of annoying, so the elf uses a special inspector tool to figure things out. The elf opens the inspector by running the command git mergetool to work through places where their beads have been added at the same points as another elf’s beads. Once all the conflicts are resolved, the elf saves their work, and quits the inspector. They might need to do this a few times if there are a lot of new beads, so the elf has learned to follow this update process regularly instead of just waiting until they’re ready to close out their work order.
Once their link is up to date, the elf can now reapply their chain as before, publish their work to the main workshop garland, and close their work order:
git checkout master
git merge --ff-only 1234_pattern-name
git push origin master
Generally this process works well for the elves. Sometimes, though, when they’re tired or bored or a little drunk on festive cheer, they realise there’s a mistake in their chain of beads. Fortunately they can fix the beads without anyone else knowing. These tools can be applied to the whole workshop chain as well, but it causes problems because the magic assumes that elves are only ever adding to the main chain, not removing or reordering beads on the fly. Depending on where the mistake is, the elf has a few different options.
Let’s pretend the elf has a sequence of five beads she’s been working on. The work order says the pattern should be red-blue-red-blue-red.
If the sequence of beads is wrong (for example, blue-blue-red-red-red), the elf can remove the beads from the chain, but keep the beads in her workstation using the command git reset --soft HEAD~5.
If she’s been using the wrong colours and the wrong pattern (for example, green-green-yellow-yellow-green), she can remove the beads from her chain and discard them from her workstation using the command git reset --hard HEAD~5.
If one of the beads is missing (for example, red-blue-blue-red), she can restring the beads using the first method, or she can use a bit of magic to add the missing bead into the sequence.
Using a tool that’s a bit like orthoscopic surgery, she first selects a sequence of beads which contains the problem. A visualisation of this process is available.
Start the garland surgery process with the command:
git rebase --interactive HEAD~4
A new screen comes up with the following information (the oldest bead is on top):
pick c2e4877 Red bead
pick 9b5555e Blue bead
pick 7afd66b Blue bead
pick e1f2537 Red bead
The elf adjusts the list, changing “pick” to “edit” next to the first blue bead:
pick c2e4877 Red bead
edit 9b5555e Blue bead
pick 7afd66b Blue bead
pick e1f2537 Red bead
She then saves her work and quits the editor. The garland magic has placed her back in time at the moment just after she added the first blue bead.
She needs to manually fix up her garland to add the new red bead. If the beads were files, she might run commands like vim beads.txt and edit the file to make the necessary changes.
Once she’s finished her changes, she needs to add her new bead to the garland (git add --all) and lock it into place (git commit). This time she assigns the commit message “Red bead – added” so she can easily find it.
The garland magic has replaced the bead, but she still needs to verify the remaining beads on the garland. This is a mostly automatic process which is started by running the command git rebase --continue.
The new red bead has been assigned a position formerly held by the blue bead, and so the elf must deal with a merge conflict. She opens up a new program to help resolve the conflict by running git mergetool.
She knows she wants both of these beads in place, so the elf edits the file to include both the red and blue beads.
With the conflict resolved, the elf saves her changes and quits the mergetool.
Back at the command line, the elf checks the status of her work using the command git status.
rebase in progress; onto 4a9cb9d
You are currently rebasing branch '2_RBRBR' on '4a9cb9d'.
(all conflicts fixed: run "git rebase --continue")
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
modified: beads.txt
Untracked files:
(use "git add <file>..." to include in what will be committed)
beads.txt.orig
She removes the file added by the mergetool with the command rm beads.txt.orig and commits the edits she just made to the bead file using the commands:
git add beads.txt
git commit --message "Blue bead -- resolved conflict"
With the conflict resolved, the elf is able to continue with the rebasing process using the command git rebase --continue. There is one final conflict the elf needs to resolve. Once again, she opens up the visualisation tool and takes a look at the two conflicting files.
She incorporates the changes from the left and right column to ensure her bead sequence is correct.
Once the merge conflict is resolved, the elf saves the file and quits the mergetool. Once again, she cleans out the backup file added by the mergetool (rm beads.txt.orig) and commits her changes to the garland:
git add beads.txt
git commit --message "Red bead -- resolved conflict"
and then runs the final verification steps in the rebase process (git rebase --continue).
The verification process runs through to the end, and the elf checks her work using the command git log --oneline.
9269914 Red bead -- resolved conflict
4916353 Blue bead -- resolved conflict
aef0d5c Red bead -- added
9b5555e Blue bead
c2e4877 Red bead
She knows she needs to read the sequence from bottom to top (the oldest bead is on the bottom). Reviewing the list she sees that the sequence is now correct.
Sometimes, late at night, the elf makes new copies of the workshop garland so she can play around with the bead sequencer just to see what happens. It’s made her more confident at restringing beads when she’s found real mistakes. And she doesn’t mind helping her fellow elves when they run into trouble with their beads. The sugar cookies they leave her as thanks don’t hurt either. If you would also like to play with the bead sequencer, you can get a copy of the branches the elf worked.
Our lessons from the workshop:
By using rebase to update your branches, you avoid merge commits and keep a clean commit history.
If you make a mistake on one of your local branches, you can use reset to take commits off your branch. If you want to save the work, but uncommit it, add the parameter --soft. If you want to completely discard the work, use the parameter, --hard.
If you have merged working branch changes to the local copy of your master branch and it is preventing you from pushing your work to a remote repository, remove these changes using the command reset with the parameter --merge ORIG_HEAD before updating your local copy of the remote master branch.
If you want to make a change to work that was committed a little while ago, you can use the command rebase with the parameter --interactive. You will need to include how many commits back in time you want to review. |
2015 |
Emma Jane Westby |
emmajanewestby |
2015-12-07T00:00:00+00:00 |
https://24ways.org/2015/git-rebasing/ |
code |
54 |
Putting My Patterns through Their Paces |
Over the last few years, the conversation around responsive design has shifted subtly, focusing not on designing pages, but on patterns: understanding the small, reusable elements that comprise a larger design system. And given that many of those patterns are themselves responsive, learning to manage these small layout systems has become a big part of my work.
The thing is, the more pattern-driven work I do, the more I realize my design process has changed in a number of subtle, important ways. I suppose you might even say that pattern-driven design has, in a few ways, redesigned me.
Meet the Teaser
Here’s a recent example. A few months ago, some friends and I redesigned The Toast. (It was a really, really fun project, and we learned a lot.) Each page of the site is, as you might guess, stitched together from a host of tiny, reusable patterns. Some of them, like the search form and footer, are fairly unique, and used once per page; others are used more liberally, and built for reuse. The most prevalent example of these more generic patterns is the teaser, which is classed as, uh, .teaser. (Look, I never said I was especially clever.)
In its simplest form, a teaser contains a headline, which links to an article:
Fairly straightforward, sure. But it’s just the foundation: from there, teasers can have a byline, a description, a thumbnail, and a comment count. In other words, we have a basic building block (.teaser) that contains a few discrete content types – some required, some not. In fact, very few of those pieces need to be present; to qualify as a teaser, all we really need is a link and a headline. But by adding more elements, we can build slight variations of our teaser, and make it much, much more versatile.
Nearly every element visible on this page is built out of our generic “teaser” pattern.
But the teaser variation I’d like to call out is the one that appears on The Toast’s homepage, on search results or on section fronts. In the main content area, each teaser in the list features larger images, as well as an interesting visual treatment: the byline and comment count were the most prominent elements within each teaser, appearing above the headline.
The approved visual design of our teaser, as it appears on lists on the homepage and the section fronts.
And this is, as it happens, the teaser variation that gave me pause. Back in the old days – you know, like six months ago – I probably would’ve marked this module up to match the design. In other words, I would’ve looked at the module’s visual hierarchy (metadata up top, headline and content below) and written the following HTML:
<div class="teaser">
<p class="article-byline">By <a href="#">Author Name</a></p>
<a class="comment-count" href="#">126 <i>comments</i></a>
<h1 class="article-title"><a href="#">Article Title</a></h1>
<p class="teaser-excerpt">Lorem ipsum dolor sit amet, consectetur…</p>
</div>
But then I caught myself, and realized this wasn’t the best approach.
Moving Beyond Layout
Since I’ve started working responsively, there’s a question I work into every step of my design process. Whether I’m working in Sketch, CSSing a thing, or researching a project, I try to constantly ask myself:
What if someone doesn’t browse the web like I do?
…Okay, that doesn’t seem especially fancy. (And maybe you came here for fancy.) But as straightforward as that question might seem, it’s been invaluable to so many aspects of my practice. If I’m working on a widescreen layout, that question helps me remember the constraints of the small screen; if I’m working on an interface that has some enhancements for touch, it helps me consider other input modes as I work. It’s also helpful as a reminder that many might not see the screen the same way I do, and that accessibility (in all its forms) should be a throughline for our work on the web.
And that last point, thankfully, was what caught me here. While having the byline and comment count at the top was a lovely visual treatment, it made for a terrible content hierarchy. For example, it’d be a little weird if the page was being read aloud in a speaking browser: the name of the author and the number of comments would be read aloud before the title of the article with which they’re associated.
That’s why I find it’s helpful to begin designing a pattern’s hierarchy before its layout: to move past the visual presentation in front of me, and focus on the underlying content I’m trying to support. In other words, if someone’s encountering my design without the CSS I’ve written, what should their experience be?
So I took a step back, and came up with a different approach:
<div class="teaser">
<h1 class="article-title"><a href="#">Article Title</a></h1>
<h2 class="article-byline">By <a href="#">Author Name</a></h2>
<p class="teaser-excerpt">
Lorem ipsum dolor sit amet, consectetur…
<a class="comment-count" href="#">126 <i>comments</i></a>
</p>
</div>
Much, much better. This felt like a better match for the content I was designing: the headline – easily most important element – was at the top, followed by the author’s name and an excerpt. And while the comment count is visually the most prominent element in the teaser, I decided it was hierarchically the least critical: that’s why it’s at the very end of the excerpt, the last element within our teaser. And with some light styling, we’ve got a respectable-looking hierarchy in place:
Yeah, you’re right – it’s not our final design. But from this basic-looking foundation, we can layer on a bit more complexity. First, we’ll bolster the markup with an extra element around our title and byline:
<div class="teaser">
<div class="teaser-hed">
<h1 class="article-title"><a href="#">Article Title</a></h1>
<h2 class="article-byline">By <a href="#">Author Name</a></h2>
</div>
…
</div>
With that in place, we can use flexbox to tweak our layout, like so:
.teaser-hed {
display: flex;
flex-direction: column-reverse;
}
flex-direction: column-reverse acts a bit like a change in gravity within our teaser-hed element, vertically swapping its two children.
Getting closer! But as great as flexbox is, it doesn’t do anything for elements outside our container, like our little comment count, which is, as you’ve probably noticed, still stranded at the very bottom of our teaser.
Flexbox is, as you might already know, wonderful! And while it enjoys incredibly broad support, there are enough implementations of old versions of Flexbox (in addition to plenty of bugs) that I tend to use a feature test to check if the browser’s using a sufficiently modern version of flexbox. Here’s the one we used:
var doc = document.body || document.documentElement;
var style = doc.style;
if ( style.webkitFlexWrap == '' ||
style.msFlexWrap == '' ||
style.flexWrap == '' ) {
doc.className += " supports-flex";
}
Eagle-eyed readers will note we could have used @supports feature queries to ask browsers if they support certain CSS properties, removing the JavaScript dependency. But since we wanted to serve the layout to IE we opted to write a little question in JavaScript, asking the browser if it supports flex-wrap, a property used elsewhere in the design. If the browser passes the test, then a class of supports-flex gets applied to our html element. And with that class in place, we can safely quarantine our flexbox-enabled layout from less-capable browsers, and finish our teaser’s design:
.supports-flex .teaser-hed {
display: flex;
flex-direction: column-reverse;
}
.supports-flex .teaser .comment-count {
position: absolute;
right: 0;
top: 1.1em;
}
If the supports-flex class is present, we can apply our flexbox layout to the title area, sure – but we can also safely use absolute positioning to pull our comment count out of its default position, and anchor it to the top right of our teaser. In other words, the browsers that don’t meet our threshold for our advanced styles are left with an attractive design that matches our HTML’s content hierarchy; but the ones that pass our test receive the finished, final design.
And with that, our teaser’s complete.
Diving Into Device-Agnostic Design
This is, admittedly, a pretty modest application of flexbox. (For some truly next-level work, I’d recommend Heydon Pickering’s “Flexbox Grid Finesse”, or anything Zoe Mickley Gillenwater publishes.) And for such a simple module, you might feel like this is, well, quite a bit of work. And you’d be right! In fact, it’s not one layout, but two: a lightly styled content hierarchy served to everyone, with the finished design served conditionally to the browsers that can successfully implement it. But I’ve found that thinking about my design as existing in broad experience tiers – in layers – is one of the best ways of designing for the modern web. And what’s more, it works not just for simple modules like our teaser, but for more complex or interactive patterns as well.
Open video
Even a simple search form can be conditionally enhanced, given a little layered thinking.
This more layered approach to interface design isn’t a new one, mind you: it’s been championed by everyone from Filament Group to the BBC. And with all the challenges we keep uncovering, a more device-agnostic approach is one of the best ways I’ve found to practice responsive design. As Trent Walton once wrote,
Like cars designed to perform in extreme heat or on icy roads, websites should be built to face the reality of the web’s inherent variability.
We have a weird job, working on the web. We’re designing for the latest mobile devices, sure, but we’re increasingly aware that our definition of “smartphone” is much too narrow. Browsers have started appearing on our wrists and in our cars’ dashboards, but much of the world’s mobile data flows over sub-3G networks. After all, the web’s evolution has never been charted along a straight line: it’s simultaneously getting slower and faster, with devices new and old coming online every day. With all the challenges in front of us, including many we don’t yet know about, a more device-agnostic, more layered design process can better prepare our patterns – and ourselves – for the future.
(It won’t help you get enough to eat at holiday parties, though.) |
2015 |
Ethan Marcotte |
ethanmarcotte |
2015-12-10T00:00:00+00:00 |
https://24ways.org/2015/putting-my-patterns-through-their-paces/ |
code |
55 |
How Tabs Should Work |
Tabs in browsers (not browser tabs) are one of the oldest custom UI elements in a browser that I can think of. They’ve been done to death. But, sadly, most of the time I come across them, the tabs have been badly, or rather partially, implemented.
So this post is my definition of how a tabbing system should work, and one approach of implementing that.
But… tabs are easy, right?
I’ve been writing code for tabbing systems in JavaScript for coming up on a decade, and at one point I was pretty proud of how small I could make the JavaScript for the tabbing system:
var tabs = $('.tab').click(function () {
tabs.hide().filter(this.hash).show();
}).map(function () {
return $(this.hash)[0];
});
$('.tab:first').click();
Simple, right? Nearly fits in a tweet (ignoring the whole jQuery library…). Still, it’s riddled with problems that make it a far from perfect solution.
Requirements: what makes the perfect tab?
All content is navigable and available without JavaScript (crawler-compatible and low JS-compatible).
ARIA roles.
The tabs are anchor links that:
are clickable
have block layout
have their href pointing to the id of the panel element
use the correct cursor (i.e. cursor: pointer).
Since tabs are clickable, the user can open in a new tab/window and the page correctly loads with the correct tab open.
Right-clicking (and Shift-clicking) doesn’t cause the tab to be selected.
Native browser Back/Forward button correctly changes the state of the selected tab (think about it working exactly as if there were no JavaScript in place).
The first three points are all to do with the semantics of the markup and how the markup has been styled. I think it’s easy to do a good job by thinking of tabs as links, and not as some part of an application. Links are navigable, and they should work the same way other links on the page work.
The last three points are JavaScript problems. Let’s investigate that.
The shitmus test
Like a litmus test, here’s a couple of quick ways you can tell if a tabbing system is poorly implemented:
Change tab, then use the Back button (or keyboard shortcut) and it breaks
The tab isn’t a link, so you can’t open it in a new tab
These two basic things are, to me, the bare minimum that a tabbing system should have.
Why is this important?
The people who push their so-called native apps on users can’t have more reasons why the web sucks. If something as basic as a tab doesn’t work, obviously there’s more ammo to push a closed native app or platform on your users.
If you’re going to be a web developer, one of your responsibilities is to maintain established interactivity paradigms. This doesn’t mean don’t innovate. But it does mean: stop fucking up my scrolling experience with your poorly executed scroll effects. </rant> :breath:
URI fragment, absolute URL or query string?
A URI fragment (AKA the # hash bit) would be using mysite.com/config#content to show the content panel. A fully addressable URL would be mysite.com/config/content. Using a query string (by way of filtering the page): mysite.com/config?tab=content.
This decision really depends on the context of your tabbing system. For something like GitHub’s tabs to view a pull request, it makes sense that the full URL changes.
For our problem though, I want to solve the issue when the page doesn’t do a full URL update; that is, your regular run-of-the-mill tabbing system.
I used to be from the school of using the hash to show the correct tab, but I’ve recently been exploring whether the query string can be used. The biggest reason is that multiple hashes don’t work, and comma-separated hash fragments don’t make any sense to control multiple tabs (since it doesn’t actually link to anything).
For this article, I’ll keep focused on using a single tabbing system and a hash on the URL to control the tabs.
Markup
I’m going to assume subcontent, so my markup would look like this (yes, this is a cat demo…):
<ul class="tabs">
<li><a class="tab" href="#dizzy">Dizzy</a></li>
<li><a class="tab" href="#ninja">Ninja</a></li>
<li><a class="tab" href="#missy">Missy</a></li>
</ul>
<div id="dizzy">
<!-- panel content -->
</div>
<div id="ninja">
<!-- panel content -->
</div>
<div id="missy">
<!-- panel content -->
</div>
It’s important to note that in the markup the link used for an individual tab references its panel content using the hash, pointing to the id on the panel. This will allow our content to connect up without JavaScript and give us a bunch of features for free, which we’ll see once we’re on to writing the code.
URL-driven tabbing systems
Instead of making the code responsive to the user’s input, we’re going to exclusively use the browser URL and the hashchange event on the window to drive this tabbing system. This way we get Back button support for free.
With that in mind, let’s start building up our code. I’ll assume we have the jQuery library, but I’ve also provided the full code working without a library (vanilla, if you will), but it depends on relatively new (polyfillable) tech like classList and dataset (which generally have IE10 and all other browser support).
Note that I’ll start with the simplest solution, and I’ll refactor the code as I go along, like in places where I keep calling jQuery selectors.
function show(id) {
// remove the selected class from the tabs,
// and add it back to the one the user selected
$('.tab').removeClass('selected').filter(function () {
return (this.hash === id);
}).addClass('selected');
// now hide all the panels, then filter to
// the one we're interested in, and show it
$('.panel').hide().filter(id).show();
}
$(window).on('hashchange', function () {
show(location.hash);
});
// initialise by showing the first panel
show('#dizzy');
This works pretty well for such little code. Notice that we don’t have any click handlers for the user and the Back button works right out of the box.
However, there’s a number of problems we need to fix:
The initialised tab is hard-coded to the first panel, rather than what’s on the URL.
If there’s no hash on the URL, all the panels are hidden (and thus broken).
If you scroll to the bottom of the example, you’ll find a “top” link; clicking that will break our tabbing system.
I’ve purposely made the page long, so that when you click on a tab, you’ll see the page scrolls to the top of the tab. Not a huge deal, but a bit annoying.
From our criteria at the start of this post, we’ve already solved items 4 and 5. Not a terrible start. Let’s solve items 1 through 3 next.
Using the URL to initialise correctly and protect from breakage
Instead of arbitrarily picking the first panel from our collection, the code should read the current location.hash and use that if it’s available.
The problem is: what if the hash on the URL isn’t actually for a tab?
The solution here is that we need to cache a list of known panel IDs. In fact, well-written DOM scripting won’t continuously search the DOM for nodes. That is, when the show function kept calling $('.tab').each(...) it was wasteful. The result of $('.tab') should be cached.
So now the code will collect all the tabs, then find the related panels from those tabs, and we’ll use that list to double the values we give the show function (during initialisation, for instance).
// collect all the tabs
var tabs = $('.tab');
// get an array of the panel ids (from the anchor hash)
var targets = tabs.map(function () {
return this.hash;
}).get();
// use those ids to get a jQuery collection of panels
var panels = $(targets.join(','));
function show(id) {
// if no value was given, let's take the first panel
if (!id) {
id = targets[0];
}
// remove the selected class from the tabs,
// and add it back to the one the user selected
tabs.removeClass('selected').filter(function () {
return (this.hash === id);
}).addClass('selected');
// now hide all the panels, then filter to
// the one we're interested in, and show it
panels.hide().filter(id).show();
}
$(window).on('hashchange', function () {
var hash = location.hash;
if (targets.indexOf(hash) !== -1) {
show(hash);
}
});
// initialise
show(targets.indexOf(location.hash) !== -1 ? location.hash : '');
The core of working out which tab to initialise with is solved in that last line: is there a location.hash? Is it in our list of valid targets (panels)? If so, select that tab.
The second breakage we saw in the original demo was that clicking the “top” link would break our tabs. This was due to the hashchange event firing and the code didn’t validate the hash that was passed. Now this happens, the panels don’t break.
So far we’ve got a tabbing system that:
Works without JavaScript.
Supports right-click and Shift-click (and doesn’t select in these cases).
Loads the correct panel if you start with a hash.
Supports native browser navigation.
Supports the keyboard.
The only annoying problem we have now is that the page jumps when a tab is selected. That’s due to the browser following the default behaviour of an internal link on the page. To solve this, things are going to get a little hairy, but it’s all for a good cause.
Removing the jump to tab
You’d be forgiven for thinking you just need to hook a click handler and return false. It’s what I started with. Only that’s not the solution. If we add the click handler, it breaks all the right-click and Shift-click support.
There may be another way to solve this, but what follows is the way I found – and it works. It’s just a bit… hairy, as I said.
We’re going to strip the id attribute off the target panel when the user tries to navigate to it, and then put it back on once the show code starts to run. This change will mean the browser has nowhere to navigate to for that moment, and won’t jump the page.
The change involves the following:
Add a click handle that removes the id from the target panel, and cache this in a target variable that we’ll use later in hashchange (see point 4).
In the same click handler, set the location.hash to the current link’s hash. This is important because it forces a hashchange event regardless of whether the URL actually changed, which prevents the tabs breaking (try it yourself by removing this line).
For each panel, put a backup copy of the id attribute in a data property (I’ve called it old-id).
When the hashchange event fires, if we have a target value, let’s put the id back on the panel.
These changes result in this final code:
/*global $*/
// a temp value to cache *what* we're about to show
var target = null;
// collect all the tabs
var tabs = $('.tab').on('click', function () {
target = $(this.hash).removeAttr('id');
// if the URL isn't going to change, then hashchange
// event doesn't fire, so we trigger the update manually
if (location.hash === this.hash) {
// but this has to happen after the DOM update has
// completed, so we wrap it in a setTimeout 0
setTimeout(update, 0);
}
});
// get an array of the panel ids (from the anchor hash)
var targets = tabs.map(function () {
return this.hash;
}).get();
// use those ids to get a jQuery collection of panels
var panels = $(targets.join(',')).each(function () {
// keep a copy of what the original el.id was
$(this).data('old-id', this.id);
});
function update() {
if (target) {
target.attr('id', target.data('old-id'));
target = null;
}
var hash = window.location.hash;
if (targets.indexOf(hash) !== -1) {
show(hash);
}
}
function show(id) {
// if no value was given, let's take the first panel
if (!id) {
id = targets[0];
}
// remove the selected class from the tabs,
// and add it back to the one the user selected
tabs.removeClass('selected').filter(function () {
return (this.hash === id);
}).addClass('selected');
// now hide all the panels, then filter to
// the one we're interested in, and show it
panels.hide().filter(id).show();
}
$(window).on('hashchange', update);
// initialise
if (targets.indexOf(window.location.hash) !== -1) {
update();
} else {
show();
}
This version now meets all the criteria I mentioned in my original list, except for the ARIA roles and accessibility. Getting this support is actually very cheap to add.
ARIA roles
This article on ARIA tabs made it very easy to get the tabbing system working as I wanted.
The tasks were simple:
Add aria-role set to tab for the tabs, and tabpanel for the panels.
Set aria-controls on the tabs to point to their related panel (by id).
I use JavaScript to add tabindex=0 to all the tab elements.
When I add the selected class to the tab, I also set aria-selected to true and, inversely, when I remove the selected class I set aria-selected to false.
When I hide the panels I add aria-hidden=true, and when I show the specific panel I set aria-hidden=false.
And that’s it. Very small changes to get full sign-off that the tabbing system is bulletproof and accessible.
Check out the final version (and the non-jQuery version as promised).
In conclusion
There’s a lot of tab implementations out there, but there’s an equal amount that break the browsing paradigm and the simple linkability of content. Clearly there’s a special hell for those tab systems that don’t even use links, but I think it’s clear that even in something that’s relatively simple, it’s the small details that make or break the user experience.
Obviously there are corners I’ve not explored, like when there’s more than one set of tabs on a page, and equally whether you should deliver the initial markup with the correct tab selected. I think the answer lies in using query strings in combination with hashes on the URL, but maybe that’s for another year! |
2015 |
Remy Sharp |
remysharp |
2015-12-22T00:00:00+00:00 |
https://24ways.org/2015/how-tabs-should-work/ |
code |
63 |
Be Fluid with Your Design Skills: Build Your Own Sites |
Just five years ago in 2010, when we were all busy trying to surprise and delight, learning CSS3 and trying to get whole websites onto one page, we had a poster on our studio wall. It was entitled ‘Designers Vs Developers’, an infographic that showed us the differences between the men(!) who created websites.
Designers wore skinny jeans and used Macs and developers wore cargo pants and brought their own keyboards to work. We began to learn that designers and developers were not only doing completely different jobs but were completely different people in every way. This opinion was backed up by hundreds of memes, millions of tweets and pages of articles which used words like void and battle and versus.
Thankfully, things move quickly in this industry; the wide world of web design has moved on in the last five years. There are new devices, technologies, tools – and even a few women. Designers have been helped along by great apps, software, open source projects, conferences, and a community of people who, to my unending pride, love to share their knowledge and their work.
So the world has moved on, and if Miley Cyrus, Ruby Rose and Eliot Sumner are identifying as gender fluid (an identity which refers to a gender which varies over time or is a combination of identities), then I would like to come out as discipline fluid!
OK, I will probably never identify as a developer, but I will identify as fluid! How can we be anything else in an industry that moves so quickly? That’s how we should think of our skills, our interests and even our job titles. After all, Steve Jobs told us that “Design is not just what it looks like and feels like. Design is how it works.” Sorry skinny-jean-wearing designers – this means we’re all designing something together. And it’s not just about knowing the right words to use: you have to know how it feels. How it feels when you make something work, when you fix that bug, when you make it work on IE.
Like anything in life, things run smoothly when you make the effort to share experiences, empathise and deeply understand the needs of others. How can designers do that if they’ve never built their own site? I’m not talking the big stuff, I’m talking about your portfolio site, your mate’s business website, a website for that great idea you’ve had. I’m talking about doing it yourself to get an unique insight into how it feels.
We all know that designers and developers alike love an <ol>, so here it is.
Ten reasons designers should be fluid with their skills and build their own sites
1. It’s never been easier
Now here’s where the definition of ‘build’ is going to get a bit loose and people are going to get angry, but when I say it’s never been easier I mean because of the existence of apps and software like WordPress, Squarespace, Tumblr, et al. It’s easy to make something and get it out there into the world, and these are all gateway drugs to hard coding!
2. You’ll understand how it feels
How it feels to be so proud that something actually works that you momentarily don’t notice if the kerning is off or the padding is inconsistent. How it feels to see your site appear when you’ve redirected a URL. How it feels when you just can’t work out where that one extra space is in a line of PHP that has killed your whole site.
3. It makes you a designer
Not a better designer, it makes you a designer when you are designing how things look and how they work.
4. You learn about movement
Photoshop and Sketch just don’t cut it yet. Until you see your site in a browser or your app on a phone, it’s hard to imagine how it moves. Building your own sites shows you that it’s not just about how the content looks on the screen, but how it moves, interacts and feels.
5. You make techie friends
All the tutorials and forums in the world can’t beat your network of techie friends. Since I started working in web design I have worked with, sat next to, and co-created with some of the greatest developers. Developers who’ve shared their knowledge, encouraged me to build things, patiently explained HTML, CSS, servers, divs, web fonts, iOS development. There has been no void, no versus, very few battles; just people who share an interest and love of making things.
6. You will own domain names
When something is paid for, online and searchable then it’s real and you’ve got to put the work in. Buying domains has taught me how to stop procrastinating, but also about DNS, FTP, email, and how servers work.
7. People will ask you to do things
Learning about code and development opens a whole new world of design. When you put your own personal websites and projects out there people ask you to do more things. OK, so sometimes those things are “Make me a website for free”, but more often it’s cool things like “Come and speak at my conference”, “Write an article for my magazine” and “Collaborate with me.”
8. The young people are coming!
They love typography, they love print, they love layout, but they’ve known how to put a website together since they started their first blog aged five and they show me clever apps they’ve knocked together over the weekend! They’re new, they’re fluid, and they’re better than us!
9. Your portfolio is your portfolio
OK, it’s an obvious one, but as designers our work is our CV, our legacy! We need to show our skill, our attention to detail and our creativity in the way we showcase our work. Building your portfolio is the best way to start building your own websites. (And please be that designer who’s bothered to work out how to change the Squarespace favicon!)
10. It keeps you fluid!
Building your own websites is tough. You’ll never be happy with it, you’ll constantly be updating it to keep up with technology and fashion, and by the time you’ve finished it you’ll want to start all over again. Perfect for forcing you to stay up-to-date with what’s going on in the industry.
</ol> |
2015 |
Ros Horner |
roshorner |
2015-12-12T00:00:00+00:00 |
https://24ways.org/2015/be-fluid-with-your-design-skills-build-your-own-sites/ |
code |
64 |
Being Responsive to the Small Things |
It’s that time of the year again to trim the tree with decorations. Or maybe a DOM tree?
Any web page is made of HTML elements that lay themselves out in a tree structure. We start at the top and then have multiple branches with branches that branch out from there.
To decorate our tree, we use CSS to specify which branches should receive the tinsel we wish to adorn upon it. It’s all so lovely.
In years past, this was rather straightforward. But these days, our trees need to be versatile. They need to be responsive!
Responsive web design is pretty wonderful, isn’t it? Based on our viewport, we can decide how elements on the page should change their appearance to accommodate various constraints using media queries.
Clearleft have a delightfully clean and responsive site
Alas, it’s not all sunshine, lollipops, and rainbows.
With complex layouts, we may have design chunks — let’s call them components — that appear in different contexts. Each context may end up providing its own constraints on the design, both in its default state and in its possibly various responsive states.
Media queries, however, limit us to the context of the entire viewport, not individual containers on the page. For every container our component lives in, we need to specify how to rearrange things in that context. The more complex the system, the more contexts we need to write code for.
@media (min-width: 800px) {
.features > .component { }
.sidebar > .component {}
.grid > .component {}
}
Each new component and each new breakpoint just makes the entire system that much more difficult to maintain.
@media (min-width: 600px) {
.features > .component { }
.grid > .component {}
}
@media (min-width: 800px) {
.features > .component { }
.sidebar > .component {}
.grid > .component {}
}
@media (min-width: 1024px) {
.features > .component { }
}
Enter container queries
Container queries, also known as element queries, allow you to specify conditional CSS based on the width (or maybe height) of the container that an element lives in. In doing so, you no longer have to consider the entire page and the interplay of all the elements within.
With container queries, you’ll be able to consider the breakpoints of just the component you’re designing. As a result, you end up specifying less code and the components you develop have fewer dependencies on the things around them. (I guess that makes your components more independent.)
Awesome, right?
There’s only one catch.
Browsers can’t do container queries. There’s not even an official specification for them yet. The Responsive Issues (née Images) Community Group is looking into solving how such a thing would actually work.
See, container queries are tricky from an implementation perspective. The contents of a container can affect the size of the container. Because of this, you end up with troublesome circular references.
For example, if the width of the container is under 500px then the width of the child element should be 600px, and if the width of the container is over 500px then the width of the child element should be 400px.
Can you see the dilemma? When the container is under 500px, the child element resizes to 600px and suddenly the container is 600px. If the container is 600px, then the child element is 400px! And so on, forever. This is bad.
I guess we should all just go home and sulk about how we just got a pile of socks when we really wanted the Millennium Falcon.
Our saviour this Christmas: JavaScript
The three wise men — Tim Berners-Lee, Håkon Wium Lie, and Brendan Eich — brought us the gifts of HTML, CSS, and JavaScript.
To date, there are a handful of open source solutions to fill the gap until a browser implementation sees the light of day.
Elementary by Scott Jehl
ElementQuery by Tyson Matanich
EQ.js by Sam Richards
CSS Element Queries from Marcj
Using any of these can sometimes feel like your toy broke within ten minutes of unwrapping it.
Each take their own approach on how to specify the query conditions. For example, Elementary, the smallest of the group, only supports min-width declarations made in a :before selector.
.mod-foo:before {
content: “300 410 500”;
}
The script loops through all the elements that you specify, reading the content property and then setting an attribute value on the HTML element, allowing you to use CSS to style that condition.
.mod-foo[data-minwidth~="300"] {
background: blue;
}
To get the script to run, you’ll need to set up event handlers for when the page loads and for when it resizes.
window.addEventListener( "load", window.elementary, false );
window.addEventListener( "resize", window.elementary, false );
This works okay for static sites but breaks down on pages where elements can expand or contract, or where new content is dynamically inserted.
In the case of EQ.js, the implementation requires the creation of the breakpoints in the HTML. That means that you have implementation details in HTML, JavaScript, and CSS. (Although, with the JavaScript, once it’s in the build system, it shouldn’t ever be much of a concern unless you’re tracking down a bug.)
Another problem you may run into is the use of content delivery networks (CDNs) or cross-origin security issues. The ElementQuery and CSS Element Queries libraries need to be able to read the CSS file. If you are unable to set up proper cross-origin resource sharing (CORS) headers, these libraries won’t help.
At Shopify, for example, we had all of these problems. The admin that store owners use is very dynamic and the CSS and JavaScript were being loaded from a CDN that prevented the JavaScript from reading the CSS.
To go responsive, the team built their own solution — one similar to the other scripts above, in that it loops through elements and adds or removes classes (instead of data attributes) based on minimum or maximum width.
The caveat to this particular approach is that the declaration of breakpoints had to be done in JavaScript.
elements = [
{ ‘module’: “.carousel”, “className”:’alpha’, minWidth: 768, maxWidth: 1024 },
{ ‘module’: “.button”, “className”:’beta’, minWidth: 768, maxWidth: 1024 } ,
{ ‘module’: “.grid”, “className”:’cappa’, minWidth: 768, maxWidth: 1024 }
]
With that done, the script then had to be set to run during various events such as inserting new content via Ajax calls. This sometimes reveals itself in flashes of unstyled breakpoints (FOUB). An unfortunate side effect but one largely imperceptible.
Using this approach, however, allowed the Shopify team to make the admin responsive really quickly. Each member of the team was able to tackle the responsive story for a particular component without much concern for how all the other components would react.
Each element responds to its own breakpoint that would amount to dozens of breakpoints using traditional breakpoints. This approach allows for a truly fluid and adaptive interface for all screens.
Christmas is over
I wish I were the bearer of greater tidings and cheer. It’s not all bad, though. We may one day see browsers implement container queries natively. At which point, we shall all rejoice! |
2015 |
Jonathan Snook |
jonathansnook |
2015-12-19T00:00:00+00:00 |
https://24ways.org/2015/being-responsive-to-the-small-things/ |
code |
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 |
68 |
Grid, Flexbox, Box Alignment: Our New System for Layout |
Three years ago for 24 ways 2012, I wrote an article about a new CSS layout method I was excited about. A specification had emerged, developed by people from the Internet Explorer team, bringing us a proper grid system for the web. In 2015, that Internet Explorer implementation is still the only public implementation of CSS grid layout. However, in 2016 we should be seeing it in a new improved form ready for our use in browsers.
Grid layout has developed hidden behind a flag in Blink, and in nightly builds of WebKit and, latterly, Firefox. By being developed in this way, breaking changes could be safely made to the specification as no one was relying on the experimental implementations in production work.
Another new layout method has emerged over the past few years in a more public and perhaps more painful way. Shipped prefixed in browsers, The flexible box layout module (flexbox) was far too tempting for developers not to use on production sites. Therefore, as changes were made to the specification, we found ourselves with three different flexboxes, and browser implementations that did not match one another in completeness or in the version of specified features they supported.
Owing to the different ways these modules have come into being, when I present on grid layout it is often the very first time someone has heard of the specification. A question I keep being asked is whether CSS grid layout and flexbox are competing layout systems, as though it might be possible to back the loser in a CSS layout competition. The reality, however, is that these two methods will sit together as one system for doing layout on the web, each method playing to certain strengths and serving particular layout tasks.
If there is to be a loser in the battle of the layouts, my hope is that it will be the layout frameworks that tie our design to our markup. They have been a necessary placeholder while we waited for a true web layout system, but I believe that in a few years time we’ll be easily able to date a website to circa 2015 by seeing <div class="row"> or <div class="col-md-3"> in the markup.
In this article, I’m going to take a look at the common features of our new layout systems, along with a couple of examples which serve to highlight the differences between them.
To see the grid layout examples you will need to enable grid in your browser. The easiest thing to do is to enable the experimental web platform features flag in Chrome. Details of current browser support can be found here.
Relationship
Items only become flex or grid items if they are a direct child of the element that has display:flex, display:grid or display:inline-grid applied. Those direct children then understand themselves in the context of the complete layout. This makes many things possible. It’s the lack of relationship between elements that makes our existing layout methods difficult to use. If we float two columns, left and right, we have no way to tell the shorter column to extend to the height of the taller one. We have expended a lot of effort trying to figure out the best way to make full-height columns work, using techniques that were never really designed for page layout.
At a very simple level, the relationship between elements means that we can easily achieve full-height columns. In flexbox:
See the Pen Flexbox equal height columns by rachelandrew (@rachelandrew) on CodePen.
And in grid layout (requires a CSS grid-supporting browser):
See the Pen Grid equal height columns by rachelandrew (@rachelandrew) on CodePen.
Alignment
Full-height columns rely on our flex and grid items understanding themselves as part of an overall layout. They also draw on a third new specification: the box alignment module. If vertical centring is a gift you’d like to have under your tree this Christmas, then this is the box you’ll want to unwrap first.
The box alignment module takes the alignment and space distribution properties from flexbox and applies them to other layout methods. That includes grid layout, but also other layout methods. Once implemented in browsers, this specification will give us true vertical centring of all the things.
Our examples above achieved full-height columns because the default value of align-items is stretch. The value ensured our columns stretched to the height of the tallest. If we want to use our new vertical centring abilities on all items, we would set align-items:center on the container. To align one flex or grid item, apply the align-self property.
The examples below demonstrate these alignment properties in both grid layout and flexbox. The portrait image of Widget the cat is aligned with the default stretch. The other three images are aligned using different values of align-self.
Take a look at an example in flexbox:
See the Pen Flexbox alignment by rachelandrew (@rachelandrew) on CodePen.
And also in grid layout (requires a CSS grid-supporting browser):
See the Pen Grid alignment by rachelandrew (@rachelandrew) on CodePen.
The alignment properties used with CSS grid layout.
Fluid grids
A cornerstone of responsive design is the concept of fluid grids.
“[…]every aspect of the grid—and the elements laid upon it—can be expressed as a proportion relative to its container.”
—Ethan Marcotte, “Fluid Grids”
The method outlined by Marcotte is to divide the target width by the context, then use that value as a percentage value for the width property on our element.
h1 {
margin-left: 14.575%; /* 144px / 988px = 0.14575 */
width: 70.85%; /* 700px / 988px = 0.7085 */
}
In more recent years, we’ve been able to use calc() to simplify this (at least, for those of us able to drop support for Internet Explorer 8). However, flexbox and grid layout make fluid grids simple.
The most basic of flexbox demos shows this fluidity in action. The justify-content property – another property defined in the box alignment module – can be used to create an equal amount of space between or around items. As the available width increases, more space is assigned in proportion.
In this demo, the list items are flex items due to display:flex being added to the ul. I have given them a maximum width of 250 pixels. Any remaining space is distributed equally between the items as the justify-content property has a value of space-between.
See the Pen Flexbox: justify-content by rachelandrew (@rachelandrew) on CodePen.
For true fluid grid-like behaviour, your new flexible friends are flex-grow and flex-shrink. These properties give us the ability to assign space in proportion.
The flexbox flex property is a shorthand for:
flex-grow
flex-shrink
flex-basis
The flex-basis property sets the default width for an item. If flex-grow is set to 0, then the item will not grow larger than the flex-basis value; if flex-shrink is 0, the item will not shrink smaller than the flex-basis value.
flex: 1 1 200px: a flexible box that can grow and shrink from a 200px basis.
flex: 0 0 200px: a box that will be 200px and cannot grow or shrink.
flex: 1 0 200px: a box that can grow bigger than 200px, but not shrink smaller.
In this example, I have a set of boxes that can all grow and shrink equally from a 100 pixel basis.
See the Pen Flexbox: flex-grow by rachelandrew (@rachelandrew) on CodePen.
What I would like to happen is for the first element, containing a portrait image, to take up less width than the landscape images, thus keeping it more in proportion. I can do this by changing the flex-grow value. By giving all the items a value of 1, they all gain an equal amount of the available space after the 100 pixel basis has been worked out.
If I give them all a value of 3 and the first box a value of 1, the other boxes will be assigned three parts of the available space while box 1 is assigned only one part. You can see what happens in this demo:
See the Pen Flexbox: flex-grow by rachelandrew (@rachelandrew) on CodePen.
Once you understand flex-grow, you should easily be able to grasp how the new fraction unit (fr, defined in the CSS grid layout specification) works. Like flex-grow, this unit allows us to assign available space in proportion. In this case, we assign the space when defining our track sizes.
In this demo (which requires a CSS grid-supporting browser), I create a four-column grid using the fraction unit to define my track sizes. The first track is 1fr in width, and the others 2fr.
grid-template-columns: 1fr 2fr 2fr 2fr;
See the Pen Grid fraction units by rachelandrew (@rachelandrew) on CodePen.
The four-track grid.
Separation of concerns
My younger self petitioned my peers to stop using tables for layout and to move to CSS. One of the rallying cries of that movement was the concept of separating our source and content from how they were displayed. It was something of a failed promise given the tools we had available: the display leaked into the markup with the need for redundant elements to cope with browser bugs, or visual techniques that just could not be achieved without supporting markup.
Browsers have improved, but even now we can find ourselves compromising the ideal document structure so we can get the layout we want at various breakpoints. In some ways, the situation has returned to tables-for-layout days. Many of the current grid frameworks rely on describing our layout directly in the markup. We add divs for rows, and classes to describe the number of desired columns. We nest these constructions of divs inside one another.
Here is a snippet from the Bootstrap grid examples – two columns with two nested columns:
<div class="row">
<div class="col-md-8">
.col-md-8
<div class="row">
<div class="col-md-6">
.col-md-6
</div>
<div class="col-md-6">
.col-md-6
</div>
</div>
</div>
<div class="col-md-4">
.col-md-4
</div>
</div>
Not a million miles away from something I might have written in 1999.
<table>
<tr>
<td class="col-md-8">
.col-md-8
<table>
<tr>
<td class="col-md-6">
.col-md-6
</td>
<td class="col-md-6">
.col-md-6
</td>
</tr>
</table>
</td>
<td class="col-md-4">
.col-md-4
</td>
</tr>
</table>
Grid and flexbox layouts do not need to be described in markup. The layout description happens entirely in the CSS, meaning that elements can be moved around from within the presentation layer.
Flexbox gives us the ability to reverse the flow of elements, but also to set the order of elements with the order property. This is demonstrated here, where Widget the cat is in position 1 in the source, but I have used the order property to display him after the things that are currently unimpressive to him.
See the Pen Flexbox: order by rachelandrew (@rachelandrew) on CodePen.
Grid layout takes this a step further. Where flexbox lets us set the order of items in a single dimension, grid layout gives us the ability to position things in two dimensions: both rows and columns. Defined in the CSS, this positioning can be changed at any breakpoint without needing additional markup. Compare the source order with the display order in this example (requires a CSS grid-supporting browser):
See the Pen Grid positioning in two dimensions by rachelandrew (@rachelandrew) on CodePen.
Laying out our items in two dimensions using grid layout.
As these demos show, a straightforward way to decide if you should use grid layout or flexbox is whether you want to position items in one dimension or two. If two, you want grid layout.
A note on accessibility and reordering
The issues arising from this powerful ability to change the way items are ordered visually from how they appear in the source have been the subject of much discussion. The current flexbox editor’s draft states
“Authors must use order only for visual, not logical, reordering of content. Style sheets that use order to perform logical reordering are non-conforming.”
—CSS Flexible Box Layout Module Level 1, Editor’s Draft (3 December 2015)
This is to ensure that non-visual user agents (a screen reader, for example) can rely on the document source order as being correct. Take care when reordering that you do so from the basis of a sound document that makes sense in terms of source order. Avoid using visual order to convey meaning.
Automatic content placement with rules
Having control over the order of items, or placing items on a predefined grid, is nice. However, we can often do that already with one method or another and we have frameworks and tools to help us. Tools such as Susy mean we can even get away from stuffing our markup full of grid classes. However, our new layout methods give us some interesting new possibilities.
Something that is useful to be able to do when dealing with content coming out of a CMS or being pulled from some other source, is to define a bunch of rules and then say, “Display this content, using these rules.”
As an example of this, I will leave you with a Christmas poem displayed in a document alongside Widget the cat and some of the decorations that are bringing him no Christmas cheer whatsoever.
The poem is displayed first in the source as a set of paragraphs. I’ve added a class identifying each of the four paragraphs but they are displayed in the source as one text. Below that are all my images, some landscape and some portrait; I’ve added a class of landscape to the landscape ones.
The mobile-first grid is a single column and I use line-based placement to explicitly position my poem paragraphs. The grid layout auto-placement rules then take over and place the images into the empty cells left in the grid.
At wider screen widths, I declare a four-track grid, and position my poem around the grid, keeping it in a readable order.
I also add rules to my landscape class, stating that these items should span two tracks. Once again the grid layout auto-placement rules position the rest of my images without my needing to position them. You will see that grid layout takes items out of source order to fill gaps in the grid. It does this because I have set the property grid-auto-flow to dense. The default is sparse meaning that grid will not attempt this backfilling behaviour.
Take a look and play around with the full demo (requires a CSS grid layout-supporting browser):
See the Pen Grid auto-flow with rules by rachelandrew (@rachelandrew) on CodePen.
The final automatic placement example.
My wish for 2016
I really hope that in 2016, we will see CSS grid layout finally emerge from behind browser flags, so that we can start to use these features in production — that we can start to move away from using the wrong tools for the job.
However, I also hope that we’ll see developers fully embracing these tools as the new system that they are. I want to see people exploring the possibilities they give us, rather than trying to get them to behave like the grid systems of 2015. As you discover these new modules, treat them as the new paradigm that they are, get creative with them. And, as you find the edges of possibility with them, take that feedback to the CSS Working Group. Help improve the layout systems that will shape the look of the future web.
Some further reading
I maintain a site of grid layout examples and resources at Grid by Example.
The three CSS specifications I’ve discussed can be found as editor’s drafts: CSS grid, flexbox, box alignment.
I wrote about the last three years of my interest in CSS grid layout, which gives something of a history of the specification.
More examples of box alignment and grid layout.
My presentation at Fronteers earlier this year, in which I explain more about these concepts. |
2015 |
Rachel Andrew |
rachelandrew |
2015-12-15T00:00:00+00:00 |
https://24ways.org/2015/grid-flexbox-box-alignment-our-new-system-for-layout/ |
code |
70 |
Bringing Your Code to the Streets |
— or How to Be a Street VJ
Our amazing world of web code is escaping out of the browser at an alarming rate and appearing in every aspect of the environment around us. Over the past few years we’ve already seen JavaScript used server-side, hardware coded with JavaScript, a rise of native style and desktop apps created with HTML, CSS and JavaScript, and even virtual reality (VR) is getting its fair share of front-end goodness.
You can go ahead and play with JavaScript-powered hardware such as the Tessel or the Espruino to name a couple. Just check out the Tessel project page to see JavaScript in the world of coffee roasting or sleep tracking your pet. With the rise of the internet of things, JavaScript can be seen collecting information on flooding among other things. And if that’s not enough ‘outside the browser’ implementations, Node.js servers can even be found in aircraft!
I previously mentioned VR and with three.js’s extra StereoEffect.js module it’s relatively simple to get browser 3D goodness to be Google Cardboard-ready, and thus set the stage for all things JavaScript and VR. It’s been pretty popular in the art world too, with interactive works such as Seb Lee-Delisle’s Lunar Trails installation, featuring the old arcade game Lunar Lander, which you can now play in your browser while others watch (it is the web after all). The Science Museum in London held Chrome Web Lab, an interactive exhibition featuring five experiments, showcasing the magic of the web. And it’s not even the connectivity of the web that’s being showcased; we can even take things offline and use web code for amazing things, such as fighting Ebola.
One thing is for sure, JavaScript is awesome. Hell, if you believe those telly programs (as we all do), JavaScript can even take down the stock market, purely through the witchcraft of canvas! Go JavaScript!
Now it’s our turn
So I wanted to create a little project influenced by this theme, and as it’s Christmas, take it to the streets for a little bit of party fun! Something that could take code anywhere. Here’s how I made a portable visual projection pack, a piece of video mixing software and created some web-coded street art.
Step one: The equipment
You will need:
One laptop: with HDMI output and a modern browser installed, such as Google Chrome.
One battery-powered mini projector: I’ve used a Texas Instruments DLP; for its 120 lumens it was the best cost-to-lumens ratio I could find.
One MIDI controller (optional): mine is an ICON iDJ as it suits mixing visuals. However, there is more affordable hardware on the market such as an Akai LPD8 or a Korg nanoPAD2. As you’ll see in the article, this is optional as it can be emulated within the software.
A case to carry it all around in.
Step two: The software
The projected visuals, I imagined, could be anything you can create within a browser, whether that be simple HTML and CSS, images, videos, SVG or canvas. The only requirement I have is that they move or change with sound and that I can mix any one visual into another.
You may remember a couple of years ago I created a demo on this very site, allowing audio-triggered visuals from the ambient sounds your device mic was picking up. That was a great starting point – I used that exact method to pick up the audio and thus the first requirement was complete. If you want to see some more examples of visuals I’ve put together for this, there’s a showcase on CodePen.
The second requirement took a little more thought. I needed two screens, which could at any point show any of the visuals I had coded, but could be mixed from one into the other and back again. So let’s start with two divs, both absolutely positioned so they’re on top of each other, but at the start the second screen’s opacity is set to zero.
Now all we need is a slider, which when moved from one side to the other slowly sets the second screen’s opacity to 1, thereby fading it in.
See the Pen Mixing Screens (Software Version) by Rumyra (@Rumyra) on CodePen.
Mixing Screens (CodePen)
As you saw above, I have a MIDI controller and although the software method works great, I’d quite like to make use of this nifty piece of kit. That’s easily done with the Web MIDI API. All I need to do is call it, and when I move one of the sliders on the controller (I’ve allocated the big cross fader in the middle for this), pick up on the change of value and use that to control the opacity instead.
var midi, data;
// start talking to MIDI controller
if (navigator.requestMIDIAccess) {
navigator.requestMIDIAccess({
sysex: false
}).then(onMIDISuccess, onMIDIFailure);
} else {
alert(“No MIDI support in your browser.”);
}
// on success
function onMIDISuccess(midiData) {
// this is all our MIDI data
midi = midiData;
var allInputs = midi.allInputs.values();
// loop over all available inputs and listen for any MIDI input
for (var input = allInputs.next(); input && !input.done; input = allInputs.next()) {
// when a MIDI value is received call the onMIDIMessage function
input.value.onmidimessage = onMIDIMessage;
}
}
function onMIDIMessage(message) {
// data comes in the form [command/channel, note, velocity]
data = message.data;
// Opacity change for screen. The cross fader values are [176, 8, {0-127}]
if ( (data[0] === 176) && (data[1] === 8) ) {
// this value will change as the fader is moved
var opacity = data[2]/127;
screenTwo.style.opacity = opacity;
}
}
The final code was slightly more complicated than this, as I decided to switch the two screens based on the frequencies of the sound that was playing, and use the cross fader to depict the frequency threshold value. This meant they flickered in and out of each other, rather than just faded. There’s a very rough-and-ready first version of the software on GitHub.
Phew, Great! Now we need to get all this to the streets!
Step three: Portable kit
Did you notice how I mentioned a case to carry it all around in? I wanted the case to be morphable, so I could use the equipment from it too, a sort of bag-to-usherette-tray-type affair. Well, I had an unused laptop bag…
I strengthened it with some MDF, so when I opened the bag it would hold like a tray where the laptop and MIDI controller would sit. The projector was Velcroed to the external pocket of the bag, so when it was a tray it would project from underneath. I added two durable straps, one for my shoulders and one round my waist, both attached to the bag itself. There was a lot of cutting and trimming. As it was a laptop bag it was pretty thick to start and sewing was tricky. However, I only broke one sewing machine needle; I’ve been known to break more working with leather, so I figured I was doing well. By the way, you can actually buy usherette trays, but I just couldn’t resist hacking my own :)
Step four: Take to the streets
First, make sure everything is charged – everything – a lot! The laptop has to power both the MIDI controller and the projector, and although I have a mobile phone battery booster pack, that’ll only charge the projector should it run out. I estimated I could get a good hour of visual artistry before I needed to worry, though.
I had a couple of ideas about time of day and location. Here in the UK at this time of year, it gets dark around half past four, so I could easily head out in a city around 5pm and it would be dark enough for the projections to be seen pretty well. I chose Bristol, around the waterfront, as there were some interesting locations to try it out in. The best was Millennium Square: busy but not crowded and plenty of surfaces to try projecting on to.
My first time out with the portable audio/visual pack (PAVP as it will now be named) was brilliant. I played music and projected visuals, like a one-woman band of A/V!
You might be thinking what the point of this was, besides, of course, it being a bit of fun. Well, this project got me to look at canvas and SVG more closely. The Web MIDI API was really interesting; MIDI as a data format has some great practical uses. I think without our side projects we may not have all these wonderful uses for our everyday code. Not only do they remind us coding can, and should, be fun, they also help us learn and grow as makers.
My favourite part? When I was projecting into a water feature in Millennium Square. For those who are familiar, you’ll know it’s like a wall of water so it produced a superb effect. I drew quite a crowd and a kid came to stand next to me and all I could hear him say with enthusiasm was, ‘Oh wow! That’s so cool!’
Yes… yes, kid, it was cool. Making things with code is cool.
Massive thanks to the lovely Drew McLellan for his incredibly well-directed photography, and also Simon Johnson who took a great hand in perfecting the kit while it was attached. |
2015 |
Ruth John |
ruthjohn |
2015-12-06T00:00:00+00:00 |
https://24ways.org/2015/bringing-your-code-to-the-streets/ |
code |
71 |
Upping Your Web Security Game |
When I started working in web security fifteen years ago, web development looked very different. The few non-static web applications were built using a waterfall process and shipped quarterly at best, making it possible to add security audits before every release; applications were deployed exclusively on in-house servers, allowing Info Sec to inspect their configuration and setup; and the few third-party components used came from a small set of well-known and trusted providers. And yet, even with these favourable conditions, security teams were quickly overwhelmed and called for developers to build security in.
If the web security game was hard to win before, it’s doomed to fail now. In today’s web development, every other page is an application, accepting inputs and private data from users; software is built continuously, designed to eliminate manual gates, including security gates; infrastructure is code, with servers spawned with little effort and even less security scrutiny; and most of the code in a typical application is third-party code, pulled in through open source repositories with rarely a glance at who provided them.
Security teams, when they exist at all, cannot solve this problem. They are vastly outnumbered by developers, and cannot keep up with the application’s pace of change. For us to have a shot at making the web secure, we must bring security into the core. We need to give it no less attention than that we give browser compatibility, mobile design or web page load times. More broadly, we should see security as an aspect of quality, expecting both ourselves and our peers to address it, and taking pride when we do it well.
Where To Start?
Embracing security isn’t something you do overnight.
A good place to start is by reviewing things you’re already doing – and trying to make them more secure. Here are three concrete steps you can take to get going.
HTTPS
Threats begin when your system interacts with the outside world, which often means HTTP. As is, HTTP is painfully insecure, allowing attackers to easily steal and manipulate data going to or from the server. HTTPS adds a layer of crypto that ensures the parties know who they’re talking to, and that the information exchanged can be neither modified nor sniffed.
HTTPS is relevant to any site. If your non-HTTPS site holds opinions, reading it may get your users in trouble with employers or governments. If your users believe what you say, attackers can modify your non-HTTPS to take advantage of and abuse that trust. If you want to use new browser technologies like HTTP2 and service workers, your site will need to be HTTPS. And if you want to be discovered on the web, using HTTPS can help your Google ranking. For more details on why I think you should make the switch to HTTPS, check out this post, these slides and this video.
Using HTTPS is becoming easier and cheaper. Here are a few free tools that can help:
Get free and easy HTTPS delivery from Cloudflare (be sure to use “Full SSL”!)
Get a free and automation-friendly certificate from Let’s Encrypt (now in open beta).
Test how well your HTTPS is set up using SSLTest.
Other vendors and platforms are rapidly simplifying and reducing the cost of their HTTPS offering, as demand and importance grows.
Two-Factor Authentication
The most sensitive data is usually stored behind a login, and the authentication process is the primary gate in front of this data. Making this process secure has many aspects, including using HTTPS when accepting credentials, having a strong password policy, never storing the password, and more.
All of these are important, but the best single step to boost your authentication security is to introduce two-factor authentication (2FA). Adding 2FA usually means prompting users for an additional one-time code when logging in, which they get via SMS or a mobile app (e.g. Google Authenticator). This code is short-lived and is extremely hard for a remote attacker to guess, thus vastly reducing the risk a leaked or easily guessed password presents.
The typical algorithm for 2FA is based on an IETF standard called the time-based one-time password (TOTP) algorithm, and it isn’t that hard to implement. Joel Franusic wrote a great post on implementing 2FA; modules like speakeasy make it even easier; and you can swap SMS with Google Authenticator or your own app if you prefer. If you don’t want to build 2FA support yourself, you can purchase two/multi-factor authentication services from vendors such as DuoSecurity, Auth0, Clef, Hypr and others.
If implementing 2FA still feels like too much work, you can also choose to offload your entire authentication process to an OAuth-based federated login. Many companies offer this today, including Facebook, Google, Twitter, GitHub and others. These bigger players tend to do authentication well and support 2FA, but you should consider what data you’re sharing with them in the process.
Tracking Known Vulnerabilities
Most of the code in a modern application was actually written by third parties, and pulled into your app as frameworks, modules and libraries. While using these components makes us much more productive, along with their functionality we also adopt their security flaws. To make things worse, some of these flaws are well-known vulnerabilities, making it easy for hackers to take advantage of them in an attack.
This is a real problem and happens on pretty much every platform. Do you develop in Java? In 2014, over 6% of Java modules downloaded from Maven had a known severe security issue, the typical Java applications containing 24 flaws. Are you coding in Node.js? Roughly 14% of npm packages carry a known vulnerability, and over 60% of dev shops find vulnerabilities in their code. 30% of Docker Hub containers include a high priority known security hole, and 60% of the top 100,000 websites use client-side libraries with known security gaps.
To find known security issues, take stock of your dependencies and match them against language-specific lists such as Snyk’s vulnerability DB for Node.js, rubysec for Ruby, victims-db for Python and OWASP’s Dependency Check for Java. Once found, you can fix most issues by upgrading the component in question, though that may be tricky for indirect dependencies.
This process is still way too painful, which means most teams don’t do it. The Snyk team and I are hoping to change that by making it as easy as possible to find, fix and monitor known vulnerabilities in your dependencies. Snyk’s wizard will help you find and fix these issues through guided upgrades and patches, and adding Snyk’s test to your continuous integration and deployment (CI/CD) will help you stay secure as your code evolves.
Note that newly disclosed vulnerabilities usually impact old code – the one you’re running in production. This means you have to stay alert when new vulnerabilities are disclosed, so you can fix them before attackers can exploit them. You can do so by subscribing to vulnerability lists like US-CERT, OSVDB and NVD. Snyk’s monitor will proactively let you know about new disclosures relevant to your code, but only for Node.js for now – you can register to get updated when we expand.
Securing Yourself
In addition to making your application secure, you should make the contributors to that application secure – including you. Earlier this year we’ve seen attackers target mobile app developers with a malicious Xcode. The real target, however, wasn’t these developers, but rather the users of the apps they create. That you create. Securing your own work environment is a key part of keeping your apps secure, and your users from being compromised.
There’s no single step that will make you fully secure, but here are a few steps that can make a big impact:
Use 2FA on all the services related to the application, notably source control (e.g. GitHub), cloud platform (e.g. AWS), CI/CD, CDN, DNS provider and domain registrar. If an attacker compromises any one of those, they could modify or replace your entire application. I’d recommend using 2FA on all your personal services too.
Use a password manager (e.g. 1Password, LastPass) to ensure you have a separate and complex password for each service. Some of these services will get hacked, and passwords will leak. When that happens, don’t let the attackers access your other systems too.
Secure your workstation. Be careful what you download, lock your screen when you walk away, change default passwords on services you install, run antivirus software, etc. Malware on your machine can translate to malware in your applications.
Be very wary of phishing. Smart attackers use ‘spear phishing’ techniques to gain access to specific systems, and can trick even security savvy users. There are even phishing scams targeting users with 2FA. Be alert to phishy emails.
Don’t install things through curl <somewhere-on-the-web> | sudo bash, especially if the URL is on GitHub, meaning someone else controls it. Don’t do it on your machines, and definitely don’t do it in your CI/CD systems. Seriously.
Staying secure should be important to you personally, but it’s doubly important when you have privileged access to an application. Such access makes you a way to reach many more users, and therefore a more compelling target for bad actors.
A Culture of Security
Using HTTPS, enabling two-factor authentication and fixing known vulnerabilities are significant steps in building security at your core. As you implement them, remember that these are just a few steps in a longer journey.
The end goal is to embrace security as an aspect of quality, and accept we all share the responsibility of keeping ourselves – and our users – safe. |
2015 |
Guy Podjarny |
guypodjarny |
2015-12-11T00:00:00+00:00 |
https://24ways.org/2015/upping-your-web-security-game/ |
code |
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 |
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 |
79 |
Responsive Images: What We Thought We Needed |
If you were to read a web designer’s Christmas wish list, it would likely include a solution for displaying images responsively. For those concerned about users downloading unnecessary image data, or serving images that look blurry on high resolution displays, finding a solution has become a frustrating quest.
Having experimented with complex and sometimes devilish hacks, consensus is forming around defining new standards that could solve this problem. Two approaches have emerged.
The <picture> element markup pattern was proposed by Mat Marquis and is now being developed by the Responsive Images Community Group. By providing a means of declaring multiple sources, authors could use media queries to control which version of an image is displayed and under what conditions:
<picture width="500" height="500">
<source media="(min-width: 45em)" src="large.jpg">
<source media="(min-width: 18em)" src="med.jpg">
<source src="small.jpg">
<img src="small.jpg" alt="">
<p>Accessible text</p>
</picture>
A second proposal put forward by Apple, the srcset attribute, uses a more concise syntax intended for use with the <img> element, although it could be compatible with the <picture> element too. This would allow authors to provide a set of images, but with the decision on which to use left to the browser:
<img src="fallback.jpg" alt="" srcset="small.jpg 640w 1x, small-hd.jpg 640w 2x, med.jpg 1x, med-hd.jpg 2x ">
Enter Scrooge
Men’s courses will foreshadow certain ends, to which, if persevered in, they must lead.
Ebenezer Scrooge
Given the complexity of this issue, there’s a heated debate about which is the best option. Yet code belies a certain truth. That both feature verbose and opaque syntax, I’m not sure either should find its way into the browser – especially as alternative approaches have yet to be fully explored.
So, as if to dampen the festive cheer, here are five reasons why I believe both proposals are largely redundant.
1. We need better formats, not more markup
As we move away from designs defined with fixed pixel values, bitmap images look increasingly unsuitable. While simple images and iconography can use scalable vector formats like SVG, for detailed photographic imagery, raster formats like GIF, PNG and JPEG remain the only suitable option.
There is scope within current formats to account for varying bandwidth but this requires cooperation from browser vendors. Newer formats like JPEG2000 and WebP generate higher quality images with smaller file sizes, but aren’t widely supported.
While it’s tempting to try to solve this issue by inventing new markup, the crux of it remains at the file level.
Daan Jobsis’s experimentation with image compression strengthens this argument. He discovered that by increasing the dimensions of a JPEG image while simultaneously reducing its quality, a smaller files could be produced, with the resulting image looking just as good on both standard and high-resolution displays.
This may be a hack in lieu of a more permanent solution, but it’s applied in the right place. Easy to accomplish with existing tools and without compatibility issues, it has few downsides. Further experimentation in this area should be encouraged, with standardisation efforts more helpful if focused on developing new image formats or, preferably, extending existing ones.
2. Art direction doesn’t belong in markup
A desired benefit of the <picture> markup pattern is to allow for greater art direction. For example, rather than scaling down images on smaller displays to the point that their content is hard to discern, we could present closer crops instead:
This can be achieved with CSS of course, although with a download penalty for those parts of an image not shown. This point may be negligible, however, since in the context of adaptable layouts, these hidden areas may end up being revealed anyway.
Art direction concerns design, not content. If we wish to maintain a separation of concerns, including presentation within our markup seems misguided.
3. The size of a display has little relation to the size of an image
By using media queries, the <picture> element allows authors to choose which characteristics of the screen or viewport to query for different images to be displayed.
In developing sites at Clearleft, we have noticed that the viewport is essentially arbitrary, with the size of an image’s containing element more important. For example, look at how this grid of images may adapt at different viewport widths:
As we build more modular systems, components need to be adaptable in and of themselves. There is a case to be made for developing more contextual methods of querying, rather than those based on attributes of the display.
4. We haven’t lived with the problem long enough
A key strength of the web is that the underlying platform can be continually iterated. This can also be problematic if snap judgements are made about what constitutes an improvement.
The early history of the web is littered with such examples, be it the perceived need for blinking text or inline typographic styling. To build a platform for the future, additions to it should be carefully considered. And if we want more consistent support across browsers, burdening vendors with an ever increasing list of features seems counterproductive.
Only once the need for a new feature is sufficiently proven, should we look to standardise it. Before we could declare hover effects, rounded corners and typographic styling in CSS, we used JavaScript as a polyfill. Sure, doing so was painful, but use cases were fully explored, and the CSS specification better reflected the needs of authors.
5. Images and the web aesthetic
The srcset proposal has emerged from a company that markets its phones as being able to browse the real – yet squashed down, tapped and zoomable – web. Perhaps Apple should make its own website responsive before suggesting how the rest of us should do so.
Converserly, while the <picture> proposal has the backing of a few respected developers and designers, it was born out of the work Mat Marquis and Filament Group did for the Boston Globe. As the first large-scale responsive design, this was a landmark project that ignited the responsive web design movement and proved its worth. But it was the first.
Its design shares a vernacular to that of contemporary newspaper websites, with a columnar, image-laden and densely packed layout. Compared to more recent examples – Quartz, The Next Web and the New York Times Skimmer – it feels out of step with the future direction of news sites. In seeking out a truer aesthetic for the web in which software interfaces have greater influence, we might discover that the need for responsive images isn’t as great as originally thought.
Building for the future
With responsive design, we’ve accepted the idea that a fully fluid layout, rather than a set of fixed layouts, is best suited to the web’s unpredictable nature. Current responsive image proposals are antithetical to this approach.
We need solutions that lack complexity, are device-agnostic and work within existing workflows. Any proposal that requires different versions of the same image to be created, is likely to have to acquiesce under the pressure of reality.
While it’s easy to get distracted about the size and quality of an image, and how we might choose to serve it, often the simplest solution is not to include it at all. After years of gluttonous design practice, in which fast connections and expansive display sizes were an accepted norm, we have got use to filling pages with needless images and countless items of page furniture.
To design more adaptable experiences, the presence of every element needs to be questioned, for its existence requires additional data to be downloaded or futher complexity within a design system. Conditional loading techniques mean that the inclusion of images is no longer a binary choice, but can instead appear in a progressively enhanced manner.
So here is my proposal. Instead of spending the next year worrying about responsive images, let’s embrace the constraints of the medium, and seek out new solutions that can work within them. |
2012 |
Paul Lloyd |
paulrobertlloyd |
2012-12-11T00:00:00+00:00 |
https://24ways.org/2012/responsive-images-what-we-thought-we-needed/ |
code |
80 |
HTML5 Video Bumpers |
Video is a bigger part of the web experience than ever before. With native browser support for HTML5 video elements freeing us from the tyranny of plugins, and the availability of faster internet connections to the workplace, home and mobile networks, it’s now pretty straightforward to publish video in a way that can be consumed in all sorts of ways on all sorts of different web devices.
I recently worked on a project where the client had shot some dedicated video shorts to publish on their site. They also had some five-second motion graphics produced to top and tail the videos with context and branding. This pretty common requirement is a great idea on the web, where a user might land at your video having followed a link and be viewing a page without much context.
Known as bumpers, these short introduction clips help brand a video and make it look a lot more professional.
Adding bumpers to a video
The simplest way to add bumpers to a video would be to edit them on to the start and end of the video file itself. Cooking the bumpers into the video file is easy, but should you ever want to update them it can become a real headache. If the branding needs updating, for example, you’d need to re-edit and re-encode all your videos. Not a fun task.
What if the bumpers could be added dynamically? That would enable you to use the same bumper for multiple videos (decreasing download time for users who might watch more than one) and to update the bumpers whenever you wanted. You could change them seasonally, update them for special promotions, run different advertising slots, perform multivariate testing, or even target different bumpers to different users.
The trade-off, of course, is that if you dynamically add your bumpers, there’s a chance that a user in a given circumstance might not see the bumper. For example, if the main video feature was uploaded to YouTube, you’d have no way to control the playback. As always, you need to weigh up the pros and cons and make your choice.
HTML5 bumpers
If you wanted to dynamically add bumpers to your HTML5 video, how would you go about it? That was the question I found myself needing to answer for this particular client project.
My initial thought was to treat it just like an image slideshow. If I were building a slideshow that moved between images, I’d use CSS absolute positioning with z-index to stack the images up on top of each other in a pile, with the first image on top. To transition to the second image, I’d use JavaScript to fade the top image out, revealing the second image beneath it.
Now that video is just a native object in the DOM, just like an image, why not do the same? Stack the videos up with the opening bumper on top, listen for the video’s onended event, and fade it out to reveal the main feature behind. Good idea, right?
Wrong
Remember that this is the web. It’s never going to be that easy. The problem here is that many non-desktop devices use native, dedicated video players. Think about watching a video on a mobile phone – when you play the video, the phone often goes full-screen in its native player, leaving the web page behind. There’s no opportunity to fade or switch z-index, as the video isn’t being viewed in the page. Your page is left powerless. Powerless!
So what can we do? What can we control?
Those of us with particularly long memories might recall a time before CSS, when we’d have to use JavaScript to perform image rollovers. As CSS background images weren’t a practical reality, we would use lots of <img> elements, and perform a rollover by modifying the src attribute of the image.
Turns out, this old trick of modifying the source can help us out with video, too. In most cases, modifying the src attribute of a <video> element, or perhaps more likely the src attribute of a source element, will swap from one video to another.
Swappin’ it
Let’s take a deliberately simple example of a super-basic video tag:
<video src="mycat.webm" controls>no fallback coz i is lame, innit.</video>
We could very simply write a script to find all video tags and give them a new src to show our bumper.
<script>
var videos, i, l;
videos = document.getElementsByTagName('video');
for(i=0, l=videos.length; i<l; i++) {
videos[i].setAttribute('src', 'bumper-in.webm');
}
</script>
View the example in a browser with WebM support. You’ll see that the video is swapped out for the opening bumper. Great!
Beefing it up
Of course, we can’t just publish video in one format. In practical use, you need a <video> element with multiple <source> elements containing your different source formats.
<video controls>
<source src="mycat.mp4" type="video/mp4" />
<source src="mycat.webm" type="video/webm" />
<source src="mycat.ogv" type="video/ogg" />
</video>
This time, our script needs to loop through the sources, not the videos. We’ll use a regular expression replacement to swap out the file name while maintaining the correct file extension.
<script>
var sources, i, l, orig;
sources = document.getElementsByTagName('source');
for(i=0, l=sources.length; i<l; i++) {
orig = sources[i].getAttribute('src');
sources[i].setAttribute('src', orig.replace(/(w+).(w+)/, 'bumper-in.$2'));
// reload the video
sources[i].parentNode.load();
}
</script>
The difference this time is that when changing the src of a <source> we need to call the .load() method on the video to get it to acknowledge the change.
See the code in action, this time in a wider range of browsers.
But, my video!
I guess we should get the original video playing again. Keeping the same markup, we need to modify the script to do two things:
Store the original src in a data- attribute so we can access it later
Add an event listener so we can detect the end of the bumper playing, and load the original video back in
As we need to loop through the videos this time to add the event listener, I’ve moved the .load() call into that loop. It’s a bit more efficient to call it only once after modifying all the video’s sources.
<script>
var videos, sources, i, l, orig;
sources = document.getElementsByTagName('source');
for(i=0, l=sources.length; i<l; i++) {
orig = sources[i].getAttribute('src');
sources[i].setAttribute('data-orig', orig);
sources[i].setAttribute('src', orig.replace(/(w+).(w+)/, 'bumper-in.$2'));
}
videos = document.getElementsByTagName('video');
for(i=0, l=videos.length; i<l; i++) {
videos[i].load();
videos[i].addEventListener('ended', function(){
sources = this.getElementsByTagName('source');
for(i=0, l=sources.length; i<l; i++) {
orig = sources[i].getAttribute('data-orig');
if (orig) {
sources[i].setAttribute('src', orig);
}
sources[i].setAttribute('data-orig','');
}
this.load();
this.play();
});
}
</script>
Again, view the example to see the bumper play, followed by our spectacular main feature. (That’s my cat, Widget. His interests include sleeping and internet marketing.)
Tidying things up
The final thing to do is add our closing bumper after the main video has played. This involves the following changes:
We need to keep track of whether the src has been changed, so we only play the video if it’s changed. I’ve added the modified variable to track this, and it stops us getting into a situation where the video just loops forever.
Add an else to the event listener, for when the orig is false (so the main feature has been playing) to load in the end bumper. We also check that we’re not already playing the end bumper. Because looping.
<script>
var videos, sources, i, l, orig, current, modified;
sources = document.getElementsByTagName('source');
for(i=0, l=sources.length; i<l; i++) {
orig = sources[i].getAttribute('src');
sources[i].setAttribute('data-orig', orig);
sources[i].setAttribute('src', orig.replace(/(w+).(w+)/, 'bumper-in.$2'));
}
videos = document.getElementsByTagName('video');
for(i=0, l=videos.length; i<l; i++) {
videos[i].load();
modified = false;
videos[i].addEventListener('ended', function(){
sources = this.getElementsByTagName('source');
for(i=0, l=sources.length; i<l; i++) {
orig = sources[i].getAttribute('data-orig');
if (orig) {
sources[i].setAttribute('src', orig);
modified = true;
}else{
current = sources[i].getAttribute('src');
if (current.indexOf('bumper-out')==-1) {
sources[i].setAttribute('src', current.replace(/([w]+).(w+)/, 'bumper-out.$2'));
modified = true;
}else{
this.pause();
modified = false;
}
}
sources[i].setAttribute('data-orig','');
}
if (modified) {
this.load();
this.play();
}
});
}
</script>
Yo ho ho, that’s a lot of JavaScript. See it in action – you should get a bumper, the cat video, and an end bumper.
Of course, this code works fine for demonstrating the principle, but it’s very procedural. Nothing wrong with that, but to do something similar in production, you’d probably want to make the code more modular to ease maintainability. Besides, you may want to use a framework, rather than basic JavaScript.
The end credits
One really important principle here is that of progressive enhancement. If the browser doesn’t support JavaScript, the user won’t see your bumper, but they will get the main video. If the browser supports JavaScript but doesn’t allow you to modify the src (as was the case with older versions of iOS), the user won’t see your bumper, but they will get the main video.
If a search engine or social media bot grabs your page and looks for content, they won’t see your bumper, but they will get the main video – which is absolutely what you want.
This means that if the bumper is absolutely crucial, you may still need to cook it into the video. However, for many applications, running it dynamically can work quite well.
As always, it comes down to three things:
Measure your audience: know how people access your site
Test the solution: make sure it works for your audience
Plan for failure: it’s the web and that’s how things work ‘round these parts
But most of all play around with it, have fun and build something awesome. |
2012 |
Drew McLellan |
drewmclellan |
2012-12-01T00:00:00+00:00 |
https://24ways.org/2012/html5-video-bumpers/ |
code |
83 |
Cut Copy Paste |
Long before I got into this design thing, I was heavily into making my own music inspired by the likes of Coldcut and Steinski. I would scour local second-hand record shops in search of obscure beats, loops and bits of dialogue in the hope of finding that killer sample I could then splice together with other things to make a huge hit that everyone would love. While it did eventually lead to a record contract and getting to release a few 12″ singles, ultimately I knew I’d have to look for something else to pay the bills.
I may not make my own records any more, but the approach I took back then – finding (even stealing) things, cutting and pasting them into interesting combinations – is still at the centre of how I work, only these days it’s pretty much bits of code rather than bits of vinyl. Over the years I’ve stored these little bits of code (some I’ve found, some I’ve created myself) in Evernote, ready to be dialled up whenever I need them.
So when Drew got in touch and asked if I’d like to do something for this year’s 24 ways I thought it might be kind of cool to share with you a few of these snippets that I find really useful. Think of these as a kind of coding mix tape; but remember – don’t just copy as is: play around, combine and remix them into other wonderful things.
Some of this stuff is dirty; some of it will make hardcore programmers feel ill. For those people, remember this – while you were complaining about the syntax, I made something.
Create unique colours
Let’s start right away with something I stole. Well, actually it was given away at the time by Matt Biddulph who was then at Dopplr before Nokia destroyed it. Imagine you have thousands of words and you want to assign each one a unique colour. Well, Matt came up with a crazily simple but effective way to do that using an MD5 hash. Just encode said word using an MD5 hash, then take the first six characters of the string you get back to create a hexadecimal colour representation.
I can’t guarantee that it will be a harmonious colour palette, but it’s still really useful. The thing I love the most about this technique is the left-field thinking of using an encryption system to create colours! Here’s an example using JavaScript:
// requires the MD5 library available at http://pajhome.org.uk/crypt/md5
function MD5Hex(str){
result = MD5.hex(str).substring(0, 6);
return result;
}
Make something breathe using a sine wave
I never paid attention in school, especially during double maths. As a matter of fact, the only time I received corporal punishment – several strokes of the ruler – was in maths class. Anyway, if they had shown me then how beautiful mathematics actually is, I might have paid more attention. Here’s a little example of how a sine wave can be used to make something appear to breathe.
I recently used this on an Arduino project where an LED ring surrounding a button would gently breathe. Because of that it felt much more inviting. I love mathematics.
for(int i = 0; i<360; i++){
float rad = DEG_TO_RAD * i;
int sinOut = constrain((sin(rad) * 128) + 128, 0, 255);
analogWrite(LED, sinOut);
delay(10);
}
Snap position to grid
This is so elegant I love it, and it was shown to me by Gary Burgess, or Boom Boom as myself and others like to call him. It snaps a position, in this case the X-position, to a grid. Just define your grid size (say, twenty pixels) and you’re good.
snappedXpos = floor( xPos / gridSize) * gridSize;
Calculate the distance between two objects
For me, interaction design is about the relationship between two objects: you and another object; you and another person; or simply one object to another. How close these two things are to each other can be a handy thing to know, allowing you to react to that information within your design. Here’s how to calculate the distance between two objects in a 2-D plane:
deltaX = round(p2.x-p1.x);
deltaY = round(p2.y-p1.y);
diff = round(sqrt((deltaX*deltaX)+(deltaY*deltaY)));
Find the X- and Y-position between two objects
What if you have two objects and you want to place something in-between them? A little bit of interruption and disruption can be a good thing. This small piece of code will allow you to place an object in-between two other objects:
// set the position: 0.5 = half-way
float position = 0.5;
float x = x1 + (x2 - x1) *position;
float y = y1 + (y2 - y1) *position;
Distribute objects equally around a circle
More fun with maths, this time adding cosine to our friend sine. Let’s say you want to create a circular navigation of arbitrary elements (yeah, Jakob, you heard), or you want to place images around a circle. Well, this piece of code will do just that. You can adjust the size of the circle by changing the distance variable and alter the number of objects with the numberOfObjects variable. Example below is for use in Processing.
// Example for Processing available for free download at processing.org
void setup() {
size(800,800);
int numberOfObjects = 12;
int distance = 100;
float inc = (TWO_PI)/numberOfObjects;
float x,y;
float a = 0;
for (int i=0; i < numberOfObjects; i++) {
x = (width/2) + sin(a)*distance;
y = (height/2) + cos(a)*distance;
ellipse(x,y,10,10);
a += inc;
}
}
Use modulus to make a grid
The modulus operator, represented by %, returns the remainder of a division. Fallen into a coma yet? Hold on a minute – this seemingly simple function is very powerful in lots of ways. At a simple level, you can use it to determine if a number is odd or even, great for creating alternate row colours in a table for instance:
boolean checkForEven(numberToCheck) {
if (numberToCheck % 2 == 0)
return true;
} else {
return false;
}
}
That’s all well and good, but here’s a use of modulus that might very well blow your mind. Construct a grid with only a few lines of code. Again the example is in Processing but can easily be ported to any other language.
void setup() {
size(600,600);
int numItems = 120;
int numOfColumns = 12;
int xSpacing = 40;
int ySpacing = 40;
int totalWidth = xSpacing*numOfColumns;
for (int i=0; i < numItems; i++) {
ellipse(floor((i*xSpacing)%totalWidth),floor((i*xSpacing)/totalWidth)*ySpacing,10,10);
}
}
Not all the bits of code I keep around are for actual graphical output. I also have things that are very utilitarian, but which I still consider part of the design process. Here’s a couple of things that I’ve found really handy lately in my design workflow. They may be a little specific, but I hope they demonstrate that it’s not about working harder, it’s about working smarter.
Merge CSV files into one file
Recently, I’ve had to work with huge – about 1GB – CSV text files that I then needed to combine into one master CSV file so I could then process the data. Opening up each text file and then copying and pasting just seemed really dumb, not to mention slow, so I thought there must be a better way. After some Googling I found this command line script that would combine .txt files into one file and add a new line after each:
awk 1 *.txt > finalfile.txt
But that wasn’t what I was ideally after. I wanted to merge the CSV files, keeping the first row of the first file (the column headings) and then ignore the first row of subsequent files. Sure enough I found the answer after some Googling and it worked like a charm. Apologies to the original author but I can’t remember where I found it, but you, sir or madam, are awesome. Save this as a shell script:
FIRST=
for FILE in *.csv
do
exec 5<"$FILE" # Open file
read LINE <&5 # Read first line
[ -z "$FIRST" ] && echo "$LINE" # Print it only from first file
FIRST="no"
cat <&5 # Print the rest directly to standard output
exec 5<&- # Close file
# Redirect stdout for this section into file.out
done > file.out
Create a symbolic link to another file or folder
Oftentimes, I’ll find myself hunting through a load of directories to load a file to be processed, like a CSV file. Use a symbolic link (in the Terminal) to place a link on your desktop or wherever is most convenient and it’ll save you loads of time. Especially great if you’re going through a Java file dialogue box in Processing or something that doesn’t allow the normal Mac dialog box or aliases.
cd /DirectoryYouWantShortcutToLiveIn
ln -s /Directory/You/Want/ShortcutTo/ TheShortcut
You can do it, in the mix
I hope you’ve found some of the above useful and that they’ve inspired a few ideas here and there. Feel free to tell me better ways of doing things or offer up any other handy pieces of code. Most of all though, collect, remix and combine the things you discover to make lovely new things. |
2012 |
Brendan Dawes |
brendandawes |
2012-12-17T00:00:00+00:00 |
https://24ways.org/2012/cut-copy-paste/ |
code |
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 |
89 |
Direction, Distance and Destinations |
With all these new smartphones in the hands of lost and confused owners, we need a better way to represent distances and directions to destinations. The immediate examples that jump to mind are augmented reality apps which let you see another world through your phone’s camera. While this is interesting, there is a simpler way: letting people know how far away they are and if they are getting warmer or colder.
In the app world, you can easily tap into the phone’s array of sensors such as the GPS and compass, but what people rarely know is that you can do the same with HTML. The native versus web app debate will never subside, but at least we can show you how to replicate some of the functionality progressively in HTML and JavaScript.
In this tutorial, we’ll walk through how to create a simple webpage listing distances and directions of a few popular locations around the world. We’ll use JavaScript to access the device’s geolocation API and also attempt to access the compass to get a heading. Both of these APIs are documented, to be included in the W3C geolocation API specification, and can be used on both desktop and mobile devices today.
To get started, we need a list of a few locations around the world. I have chosen the highest mountain peak on each continent so you can see a diverse set of distances and directions.
Mountain
°Latitude
°Longitude
Kilimanjaro
-3.075833
37.353333
Vinson Massif
-78.525483
-85.617147
Puncak Jaya
-4.078889
137.158333
Everest
27.988056
86.925278
Elbrus
43.355
42.439167
Mount McKinley
63.0695
-151.0074
Aconcagua
-32.653431
-70.011083
Source: Wikipedia
We can put those into an HTML list to be styled and accessed by JavaScript to create some distance and directions calculations.
The next thing we need to do is check to see if the browser and operating system have geolocation support. To do this we test to see if the function is available or not using a single JavaScript if statement.
<script>
// If this is true, then the method is supported and we can try to access the location
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(geo_success, geo_error);
}
</script>
The if statement will be false if geolocation support is not present, and then it is up to you to do something else instead as a fallback. For this example, we’ll do nothing since our page should work as is and only get progressively better if more functionality is available.
The if statement will be true if there is support and therefore will continue inside the curly brackets to try to get the location. This should prompt the reader to accept or deny the request to get their location. If they say no, the second function callback is processed, in this case a function called geo_error; whereas if the location is available, it fires the geo_success function callback.
The function geo_error(){ } isn’t that exciting. You can handle this in any way you see fit. The success function is more interesting. We get a position object passed into the function which contains a series of exciting attributes, namely the latitude and longitude of the device’s current location.
function geo_success(position){
gLat = position.coords.latitude;
gLon = position.coords.longitude;
}
Now, in the variables gLat and gLon we have the user’s approximate geographical position. We can use this information to start to calculate some distances between where they are and all the destinations.
At the time of writing, you can also get position.coords.heading, but on Windows and iOS devices this returned NULL. In the future, if and when this is supported, this is also where you can easily grab the compass information.
Inside the geo_success function, we want to loop through the HTML to get all of the mountain peaks’ latitudes and longitudes and compute the distance.
...
$('.geo').each(function(){
// Get the lat/lon from the HTML
tLat = $(this).find('.lat').html()
tLon = $(this).find('.lon').html()
// compute the distances between the current location and this points location
dist = distance(tLat,tLon,gLat,gLon);
// set the return values into something useful
d = parseInt(dist[0]*10)/10;
a = parseFloat(dist[1]);
// display the value in the HTML and style the arrow
$(this).find('.distance').html(d+' km away');
$(this).find('.direction').css('-webkit-transform','rotate(-' + a + 'deg)');
// store the arc for later use if compass is available
$(this).attr('data-arc',a);
}
In the variable d we have the distance between the current location and the location of the mountain peak based on the Haversine Formula. The variable a is the arc, which has a value from 0 to 359.99. This will be useful later if we have compass support. Given these two values we have a distance and a heading to style the HTML.
The next thing we want to do is check to see if the device has a compass and then get access to the the current heading. As we’ll see, there are several ways to do this, some of which work on certain devices but not others. The W3C geolocation spec says that, along with the coordinates, there are several other attributes: accuracy; altitude; and heading. Heading is the direction to true north, which is different than magnetic north! WebKit and Windows return NULL for the heading value, but WebKit has an experimental method to fetch the heading. If you get into accessing these sensors, you’ll have to try to catch a few of these methods to finally get a value. Assuming you do, we can move on to the more interesting display opportunities.
In an ideal world, this would succeed and set a variable we’ll call compassHeading to get a value between 0 and 359.99 degrees. Now we know which direction north is, we also know the direction relative to north of the path to our destination, so we can can subtract the two values to get an arrow to display on the screen. But we’re not finished yet: we also need to get the device’s orientation (landscape or portrait) and subtract the correct amount from the angle for the arrow. Once we have a value, we can use CSS to rotate the arrow the correct number of degrees.
-webkit-transform: rotate(-180deg)
Not all devices support a standard way to access compass information, so in the meantime we need to use a work around. On iOS, you can use the experimental event method e.webkitCompassHeading. We want the compass to update in real time as the device is moved around, so we’ll put this inside an event listener.
window.addEventListener('deviceorientation', function(e) {
// Loop through all the locations on the page
$('.geo').each(function(){
// get the arc value from north we computed and stored earlier
destination_arc = parseInt($(this).attr('data-arc'))
compassHeading = e.webkitCompassHeading + window.orientation + destination_arc;
// find the arrow element and rotate it accordingly
$(this).find('.direction').css('-webkit-transform','rotate(-' + compassHeading + 'deg)');
}
}
As the device is rotated, the compass arrow will constantly be updated. If you want to see an example, you can have a look at this page which shows the distances to all the peaks on each continent.
With progressive enhancement, we slowly layer on additional functionality as we go. The reader will first see the list of locations with a latitude and longitude. If the device is capable and permissions allow, it will then compute the distance. If a compass is available, with the correct permissions it will then add the final layer which is direction.
You should consider this code a stub for your projects. If you are making a hyperlocal webpage with restaurant locations, for example, then consider adding these features. Knowing not only how far away a place is, but also the direction can be hugely important, and since the compass is always active, it acts as a guide to the location.
Future developments
Improvements to this could include setting a timer and recalling the navigator.geolocation.getCurrentPosition() function and updating the distances. I chose very distant mountains so kilometres made sense, but you can divide again by 1,000 to convert to metres if you are dealing with much nearer places. Walking or driving would change the distances so the ability to refresh would be important.
It is outside the scope of this article, but if you manage to get this HTML to work offline, then you can make a nice web app which sits on your devices’ homescreens and works even without an internet connection. This could be ideal for travellers in an unknown city looking for your destination. Just with offline storage, base64 encoding and data URIs, it is possible to embed plenty of design and functionality into a small offline webpage.
Now you know how to use JavaScript to look up a destination’s location and figure out the distance and direction – never get lost again. |
2012 |
Brian Suda |
briansuda |
2012-12-19T00:00:00+00:00 |
https://24ways.org/2012/direction-distance-and-destinations/ |
code |
91 |
Infinite Canvas: Moving Beyond the Page |
Remember Web 2.0? I do. In fact, that phrase neatly bifurcates my life on the internet. Pre-2.0, I was occupied by chatting on AOL and eventually by learning HTML so I could build sites on Geocities. Around 2002, however, I saw a WYSIWYG demo in Dreamweaver. The instructor was dragging boxes and images around a canvas. With a few clicks he was able to build a dynamic, single-page interface. Coming from the world of tables and inline HTML styles, I was stunned.
As I entered college the next year, the web was blossoming: broadband, Wi-Fi, mobile (proud PDA owner, right here), CSS, Ajax, Bloglines, Gmail and, soon, Google Maps. I was a technology fanatic and a hobbyist web developer. For me, the web had long been informational. It was now rapidly becoming something else, something more: sophisticated, presentational, actionable.
In 2003 we watched as the internet changed. The predominant theme of those early Web 2.0 years was the withering of Internet Explorer 6 and the triumph of web standards. Upon cresting that mountain, we looked around and collectively breathed the rarefied air of pristine HMTL and CSS, uncontaminated by toxic hacks and forks – only to immediately begin hurtling down the other side at what is, frankly, terrifying speed.
Ten years later, we are still riding that rocket. Our days (and nights) are spent cramming for exams on CSS3 and RWD and Sass and RESS. We are the proud, frazzled owners of tiny pocket computers that annihilate the best laptops we could have imagined, and the architects of websites that are no longer restricted to big screens nor even segregated by device. We dragoon our sites into working any time, anywhere. At this point, we can hardly ask the spec developers to slow down to allow us to catch our breath, nor should we. It is, without a doubt, a most wonderful time to be a web developer.
But despite the newfound luxury of rounded corners, gradients, embeddable fonts, low-level graphics APIs, and, glory be, shadows, the canyon between HTML and native appears to be as wide as ever. The improvements in HTML and CSS have, for the most part, been conveniences rather than fundamental shifts. What I’d like to do now, if you’ll allow me, is outline just a few of the remaining gaps that continue to separate web sites and applications from their native companions.
What I’d like for Christmas
There is one irritant which is the grandfather of them all, the one from which all others flow and have their being, and it is, simply, the page refresh. That’s right, the foundational principle of the web is our single greatest foe. To paraphrase a patron saint of designers everywhere, if you see a page refresh, we blew it.
The page refresh brings with it, of course, many noble and lovely benefits: addressability, for one; and pagination, for another. (See also caching, resource loading, and probably half a dozen others.) Still, those concerns can be answered (and arguably answered more compellingly) by replacing the weary page with the young and hearty document. Flash may be dead, but it has many lessons yet to bequeath.
Preparing a single document when the site loads allows us to engage the visitor in a smooth and engrossing experience. We have long known this, of course. Twitter was not the first to attempt, via JavaScript, to envelop the user in a single-page application, nor the first to abandon it. Our shared task is to move those technologies down the stack, to make them more primitive, so that the next Twitter can be built with the most basic combination of HTML and CSS rather than relying on complicated, slow, and unreliable scripted solutions.
So, let’s take a look at what we can do, right now, that we might have a better idea of where our current tools fall short.
A print magazine in HTML clothing
Like many others, I suspect, one of my earliest experiences with publishing was laying out newsletters and newspapers on a computer for print. If you’ve ever used InDesign or Quark or even Microsoft Publisher, you’ll remember reflowing content from page to page. The advent of the internet signaled, in many ways, the abandonment of that model. Articles were no longer constrained by the physical limitations of paper. In shedding our chains, however, it is arguable that we’ve lost something useful. We had a self-contained and complete package, a closed loop. It was a thing that could be handled and finished, and doing so provided a sense of accomplishment that our modern, infinitely scrolling, ever-fractal web of content has stolen.
For our purposes today, we will treat 24 ways as the online equivalent of that newspaper or magazine. A single year’s worth of articles could easily be considered an issue. Right now, navigating between articles means clicking on the article you’d like to view and being taken to that specific address via a page reload. If Drew wanted to, it wouldn’t be difficult to update the page in place (via JavaScript) and change the address (again via JavaScript with the History API) to reflect the new content found at the new location. But what if Drew wanted to do that without JavaScript? And what if he wanted the site to not merely load the content but actually whisk you along the page in a compelling and delightful way, à la the Mag+ demo we all saw a few years ago when the iPad was first introduced? Uh, no.
We’re all familiar with websites that have attempted to go beyond the page by weaving many chunks of content together into a large document and for good reason. There is tremendous appeal in opening and exploring the canvas beyond the edges of our screens.
In one rather straightforward example from last year, Mozilla contacted Full Stop to build a website promoting Aza Raskin’s proposal for a set of Creative Commons-style privacy icons. Like a lot of the sites we build (including our own), the amount of information we were presenting was minimal. In these instances, we encourage our clients to consider including everything on a single page. The result was a horizontally driven site that was, if not whimsical, at least clever and attractive to the intended audience. An experience that is taken for granted when using device-native technology is utterly, maddeningly impossible to replicate on the web without jumping through JavaScript hoops.
In another, more complex example, we again had the pleasure of working with Aza earlier this year, this time on a redesign of the Massive Health website. Our assignment was to design and build a site that communicated Massive’s commitment to modern personal health. The site had to be visually and interactively stunning while maintaining a usable and clear interface for the casual visitor. Our solution was to extend the infinite company logo into a ribbon that carried the visitor through the site narrative. It also meant we’d be asking the browser to accommodate something it was never designed to handle: a non-linear design. (Be sure to play around. There’s a lot going on under the hood. We were also this close to a ZUI, if WebKit didn’t freak out when pages were scaled beyond 10×.) Despite the apparent and deliberate design simplicity, the techniques necessary to implement it are anything but. From updating the URL to moving the visitor from section to section, we’re firmly in JavaScript territory. And that’s a shame.
What can we do?
We might not be able to specify these layouts in HTML and CSS just yet, but that doesn’t mean we can’t learn a few new tricks while we wait. Let’s see how close we can come to recreating the privacy icons design, the Massive design, or the Mag+ design without resorting to JavaScript.
A horizontally paginated site
The first thing we’re going to need is the concept of a page within our HTML document. Using plain old HTML and CSS, we can stack a series of <div>s sideways (with a little assist from our new friend, the viewport-width unit, not that he was strictly necessary). All we need to know is how many pages we have. (And, boy, wouldn’t it be nice to be able to know that without having to predetermine it or use JavaScript?)
.window {
overflow: hidden;
width: 100%;
}
.pages {
width: 200vw;
}
.page {
float: left;
overflow: hidden;
width: 100vw;
}
If you look carefully, you’ll see that the conceit we’ll use in the rest of the demos is in place. Despite the document containing multiple pages, only one is visible at any given time. This allows us to keep the user focused on the task (or content) at hand.
By the way, you’ll need to use a modern, WebKit-based browser for these demos. I recommend downloading the WebKit nightly builds, Chrome Canary, or being comfortable with setting flags in Chrome.
A horizontally paginated site, with transitions
Ah, here’s the rub. We have functional navigation, but precious few cues for the user. It’s not much good shoving the visitor around various parts of the document if they don’t get the pleasant whooshing experience of the journey. You might be thinking, what about that new CSS selector, target-something…? Well, my friend, you’re on the right track. Let’s test it. We’re going to need to use a bit of sleight of hand. While we’d like to simply offset the containing element by the number of pages we’re moving (like we did on Massive), CSS alone can’t give us that information, and that means we’re going to need to fake it by expanding and collapsing pages as you navigate. Here are the bits we’re going to need:
.page {
-webkit-transition: width 1s; // Naturally you're going to want to include all the relevant prefixes here
float: left;
left: 0;
overflow: hidden;
position: relative;
width: 100vw;
}
.page:not(:target) {
width: 0;
}
Ah, but we’re not fooling anyone with that trick. As soon as you move beyond a single page, the visitor’s disbelief comes tumbling down when the linear page transitions are unaffected by the distance the pages are allegedly traveling. And you may have already noticed an even more fatal flaw: I secretly linked you to the first page rather than the unadorned URL. If you visit the same page with no URL fragment, you get a blank screen. Sure, we could force a redirect with some server-side trickery, but that feels like cheating. Perhaps if we had the CSS4 subject selector we could apply styles to the parent based on the child being targeted by the URL. We might also need a few more abilities, like determining the total number of pages and having relative sibling selectors (e.g. nth-sibling), but we’d sure be a lot closer.
A horizontally paginated site, with transitions – no cheating
Well, what other cards can we play? How about the checkbox hack? Sure, it’s a garish trick, but it might be the best we can do today. Check it out.
label {
cursor: pointer;
}
input {
display: none;
}
input:not(:checked) + .page {
max-height: 100vh;
width: 0;
}
Finally, we can see the first page thanks to the state we are able to set on the appropriate radio button. Of course, now we don’t have URLs, so maybe this isn’t a winning plan after all. While our HTML and CSS toolkit may feel primitive at the moment, we certainly don’t want to sacrifice the addressability of the web. If there’s one bedrock principle, that’s it.
A horizontally paginated site, with transitions – no cheating and a gorgeous homepage
Gorgeous may not be the right word, but our little magazine is finally shaping up. Thanks to the CSS regions spec, we’ve got an exciting new power, the ability to begin an article in one place and bend it to our will. (Remember, your everyday browser isn’t going to work for these demos. Try the WebKit nightly build to see what we’re talking about.) As with the rest of the examples, we’re clearly abusing these features. Off-canvas layouts (you can thank Luke Wroblewski for the name) are simply not considered to be normal patterns… yet.
Here’s a quick look at what’s going on:
.excerpt-container {
float: left;
padding: 2em;
position: relative;
width: 100%;
}
.excerpt {
height: 16em;
}
.excerpt_name_article-1,
.page-1 .article-flow-region {
-webkit-flow-from: article-1;
}
.article-content_for_article-1 {
-webkit-flow-into: article-1;
}
The regions pattern is comprised of at least three components: a beginning; an ending; and a source. Using CSS, we’re able to define specific elements that should be available for the content to flow through. If magazine-style layouts are something you’re interested in learning more about (and you should be), be sure to check out the great work Adobe has been doing.
Looking forward, and backward
As designers, builders, and consumers of the web, we share a desire to see the usability and enjoyability of websites continue to rise. We are incredibly lucky to be working in a time when a three-month-old website can be laughably outdated. Our goal ought to be to improve upon both the weaknesses and the strengths of the web platform. We seek not only smoother transitions and larger canvases, but fine-grained addressability. Our URLs should point directly and unambiguously to specific content elements, be they pages, sections, paragraphs or words. Moreover, off-screen design patterns are essential to accommodating and empowering the multitude of devices we use to access the web. We should express the desire that interpage links take advantage of the CSS transitions which have been put to such good effect in every other aspect of our designs. Transitions aren’t just nice to have, they’re table stakes in the highly competitive world of native applications.
The tools and technologies we have right now allow us to create smart, beautiful, useful webpages. With a little help, we can begin removing the seams and sutures that bind the web to an earlier, less sophisticated generation. |
2012 |
Nathan Peretic |
nathanperetic |
2012-12-21T00:00:00+00:00 |
https://24ways.org/2012/infinite-canvas-moving-beyond-the-page/ |
code |
92 |
Redesigning the Media Query |
Responsive web design is showing us that designing content is more important than designing containers. But if you’ve given RWD a serious try, you know that shifting your focus from the container is surprisingly hard to do. There are many factors and
instincts working against you, and one culprit is a perpetrator you’d least suspect.
The media query is the ringmaster of responsive design. It lets us establish the rules of the game and gives us what we need most: control. However, like some kind of evil double agent, the media query is actually working against you.
Its very nature diverts your attention away from content and forces you to focus on the container.
The very act of choosing a media query value means choosing a screen size.
Look at the history of the media query—it’s always been about the container. Values like screen, print, handheld and tv don’t have anything to do with content. The modern media query lets us choose screen dimensions, which is great because it makes RWD possible. But it’s still the act of choosing something that is completely unpredictable.
Content should dictate our breakpoints, not the container. In order to get our focus back to the only thing that matters, we need a reengineered media query—one that frees us from thinking about screen dimensions. A media query that works for your content, not the window. Fortunately, Sass 3.2 is ready and willing to take on this challenge.
Thinking in Columns
Fluid grids never clicked for me. I feel so disoriented and confused by their squishiness. Responsive design demands their use though, right?
I was ready to surrender until I found a grid that turned my world upright again. The Frameless Grid by Joni Korpi demonstrates that column and gutter sizes can stay fixed. As the screen size changes, you simply add or remove columns to accommodate. This made sense to me and armed with this concept I was able to give Sass the first component it needs to rewrite the media query: fixed column and gutter size variables.
$grid-column: 60px;
$grid-gutter: 20px;
We’re going to want some resolution independence too, so let’s create a function that converts those nasty pixel values into ems.
@function em($px, $base: $base-font-size) {
@return ($px / $base) * 1em;
}
We now have the components needed to figure out the width of multiple columns in ems. Let’s put them together in a function that will take any number of columns and return the fixed width value of their size.
@function fixed($col) {
@return $col * em($grid-column + $grid-gutter)
}
With the math in place we can now write a mixin that takes a column count as a parameter, then generates the perfect media query necessary to fit that number of columns on the screen. We can also build in some left and right margin for our layout by adding an additional gutter value (remembering that we already have one gutter built into our fixed function).
@mixin breakpoint($min) {
@media (min-width: fixed($min) + em($grid-gutter)) {
@content
}
}
And, just like that, we’ve rewritten the media query. Instead of picking a minimum screen size for our layout, we can simply determine the number of columns needed. Let’s add a wrapper class so that we can center our content on the screen.
@mixin breakpoint($min) {
@media (min-width: fixed($min) + em($grid-gutter)) {
.wrapper {
width: fixed($min) - em($grid-gutter);
margin-left: auto; margin-right: auto;
}
@content
}
}
Designing content with a column count gives us nice, easy, whole numbers to work with. Sizing content, sidebars or widgets is now as simple as specifying a single-digit number.
@include breakpoint(8) {
.main { width: fixed(5); }
.sidebar { width: fixed(3); }
}
Those four lines of Sass just created a responsive layout for us. When the screen is big enough to fit eight columns, it will trigger a fixed width layout. And give widths to our main content and sidebar. The following is the outputted CSS…
@media (min-width: 41.25em) {
.wrapper {
width: 38.75em;
margin-left: auto; margin-right: auto;
}
.main { width: 25em; }
.sidebar { width: 15em; }
}
Demo
I’ve created a Codepen demo that demonstrates what we’ve covered so far. I’ve added to the demo some grid classes based on Griddle by Nicolas Gallagher to create a floatless layout. I’ve also added a CSS gradient overlay to help you visualize columns. Try changing the column variable sizes or the breakpoint includes to see how the layout reacts to different screen sizes.
Responsive Images
Responsive images are a serious problem, but I’m excited to see the community talk so passionately about a solution. Now, there are some excellent stopgaps while we wait for something official, but these solutions require you to mirror your breakpoints in JavaScript or HTML. This poses a serious problem for my Sass-generated media queries, because I have no idea what the real values of my breakpoints are anymore. For responsive images to work, JavaScript needs to recognize which media query is active so that proper images can be loaded for that layout.
What I need is a way to label my breakpoints. Fortunately, people much smarter than I have figured this out. Jeremy Keith devised a labeling method by using CSS-generated content as the storage method for breakpoint labels. We can use this technique in our breakpoint mixin by passing a label as another argument.
@include breakpoint(8, 'desktop') { /* styles */ }
Sass can take that label and use it when writing the corresponding media query. We just need to slightly modify our breakpoint mixin.
@mixin breakpoint($min, $label) {
@media (min-width: fixed($min) + em($grid-gutter)) {
// label our mq with CSS generated content
body::before { content: $label; display: none; }
.wrapper {
width: fixed($min) - em($grid-gutter);
margin-left: auto; margin-right: auto;
}
@content
}
}
This allows us to label our breakpoints with a user-friendly string. Now that our media queries are defined and labeled, we just need JavaScript to step in and read which label is active.
// get css generated label for active media query
var label = getComputedStyle(document.body, '::before')['content'];
JavaScript now knows which layout is active by reading the label in the current media query—we just need to match that label to an image. I prefer to store references to different image sizes as data attributes on my image tag.
<img class="responsive-image" data-mobile="mobile.jpg" data-desktop="desktop.jpg" />
<noscript><img src="desktop.jpg" /></noscript>
These data attributes have names that match the labels set in my CSS. So while there is some duplication going on, setting a keyword like ‘tablet’ in two places is much easier than hardcoding media query values. With matching labels in CSS and HTML our script can marry the two and load the right sized image for our layout.
// get css generated label for active media query
var label = getComputedStyle(document.body, '::before')['content'];
// select image
var $image = $('.responsive-image');
// create source from data attribute
$image.attr('src', $image.data(label));
Demo
With some slight additions to our previous Codepen demo you can see this responsive image technique in action. While the above JavaScript will work it is not nearly robust enough for production so the demo uses a jQuery plugin that can accomodate multiple images, reloading on screen resize and fallbacks if something doesn’t match up.
Creating a Framework
This media query mixin and responsive image JavaScript are the center piece of a front end framework I use to develop websites. It’s a fluid, mobile first foundation that uses the breakpoint mixin to structure fixed width layouts for tablet and desktop. Significant effort was focused on making this framework completely cross-browser. For example, one of the problems with using media queries is that essential desktop structure code ends up being hidden from legacy Internet Explorer. Respond.js is an excellent polyfill, but if you’re comfortable serving a single desktop layout to older IE, we don’t need JavaScript. We simply need to capture layout code outside of a media query and sandbox it under an IE only class name.
// set IE fallback layout to 8 columns
$ie-support = 8;
// inside of our breakpoint mixin (but outside the media query)
@if ($ie-support and $min <= $ie-support) {
.lt-ie9 { @content; }
}
Perspective Regained
Thinking in columns means you are thinking about content layout. How big of a screen do you need for 12 columns? Who cares? Having Sass write media queries means you can use intuitive numbers for content layout. A fixed grid means more layout control and less edge cases to test than a fluid grid. Using CSS labels for activating responsive images means you don’t have to duplicate breakpoints across separations of concern.
It’s a harmonious blend of approaches that gives us something we need—responsive design that feels intuitive. And design that, from the very outset, focuses on what matters most. Just like our kindergarten teachers taught us: It’s what’s inside that counts. |
2012 |
Les James |
lesjames |
2012-12-13T00:00:00+00:00 |
https://24ways.org/2012/redesigning-the-media-query/ |
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 |
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 |
99 |
A Christmas hCard From Me To You |
So apparently Christmas is coming. And what is Christmas all about? Well, cleaning out your address book, of course! What better time to go through your contacts, making sure everyone’s details are up date and that you’ve deleted all those nasty clients who never paid on time?
It’s also a good time to make sure your current clients and colleagues have your most up-to-date details, so instead of filling up their inboxes with e-cards, why not send them something useful? Something like a… vCard! (See what I did there?)
Just in case you’ve been working in a magical toy factory in the upper reaches of Scandinavia for the last few years, I’m going to tell you that now would also be the perfect time to get into microformats. Using the hCard format, we’ll build a very simple web page and markup our contact details in such a way that they’ll be understood by microformats plugins, like Operator or Tails for Firefox, or the cross-browser Microformats Bookmarklet.
Oh, and because Christmas is all about dressing up and being silly, we’ll make the whole thing look nice and have a bit of fun with some CSS3 progressive enhancement.
If you can’t wait to see what we end up with, you can preview it here.
Step 1: Contact Details
First, let’s decide what details we want to put on the page. I’d put my full name, my email address, my phone number, and my postal address, but I’d rather not get surprise visits from strangers when I’m fannying about with my baubles, so I’m going to use Father Christmas instead (that’s Santa to you Yanks).
Father Christmas
fatherchristmas@elliotjaystocks.com
25 Laughingallthe Way
Snow Falls
Lapland
Finland
010 60 58 000
Step 2: hCard Creator
Now I’m not sure about you, but I rather like getting the magical robot pixies to do the work for me, so head on over to the hCard Creator and put those pixies to work! Pop in your details and they’ll give you some nice microformatted HTML in turn.
<div id="hcard-Father-Christmas" class="vcard">
<a class="url fn" href="http://elliotjaystocks.com/fatherchristmas">Father Christmas</a>
<a class="email" href="mailto:fatherchristmas@elliotjaystocks.com"> fatherchristmas@elliotjaystocks.com</a>
<div class="adr">
<div class="street-address">25 Laughingallthe Way</div>
<span class="locality">Snow Falls</span>
,
<span class="region">Lapland</span>
,
<span class="postal-code">FI-00101</span>
<span class="country-name">Finland</span>
</div>
<div class="tel">010 60 58 000</div>
<p style="font-size:smaller;">This <a href="http://microformats.org/wiki/hcard">hCard</a> created with the <a href="http://microformats.org/code/hcard/creator">hCard creator</a>.</p>
</div>
Step 3: Editing The Code
One of the great things about microformats is that you can use pretty much whichever HTML tags you want, so just because the hCard Creator Fairies say something should be wrapped in a <span> doesn’t mean you can’t change it to a <blink>. Actually, no, don’t do that. That’s not even excusable at Christmas.
I personally have a penchant for marking up each line of an address inside a <li> tag, where the parent url retains the class of adr. As long as you keep the class names the same, you’ll be fine.
<div id="hcard-Father-Christmas" class="vcard">
<h1><a class="url fn" href="http://elliotjaystocks.com/fatherchristmas">Father Christmas </a></h1>
<a class="email" href="mailto:fatherchristmas@elliotjaystocks.com?subject=Here, have some Christmas cheer!">fatherchristmas@elliotjaystocks.com</a>
<ul class="adr">
<li class="street-address">25 Laughingallthe Way</li>
<li class="locality">Snow Falls</li>
<li class="region">Lapland</li>
<li class="postal-code">FI-00101</li>
<li class="country-name">Finland</li>
</ul>
<span class="tel">010 60 58 000</span>
</div>
Step 4: Testing The Microformats
With our microformats in place, now would be a good time to test that they’re working before we start making things look pretty. If you’re on Firefox, you can install the Operator or Tails extensions, but if you’re on another browser, just add the Microformats Bookmarklet. Regardless of your choice, the results is the same: if you’ve code microformatted content on a web page, one of these bad boys should pick it up for you and allow you to export the contact info. Give it a try and you should see father Christmas appearing in your address book of choice. Now you’ll never forget where to send those Christmas lists!
Step 5: Some Extra Markup
One of the first things we’re going to do is put a photo of Father Christmas on the hCard. We’ll be using CSS to apply a background image to a div, so we’ll be needing an extra div with a class name of “photo”. In turn, we’ll wrap the text-based elements of our hCard inside a div cunningly called “text”. Unfortunately, because of the float technique we’ll be using, we’ll have to use one of those nasty float-clearing techniques. I shall call this “christmas-cheer”, since that is what its presence will inevitably bring, of course.
Oh, and let’s add a bit of text to give the page context, too:
<p>Send your Christmas lists my way...</p>
<div id="hcard-Father-Christmas" class="vcard">
<div class="text">
<h1><a class="url fn" href="http://elliotjaystocks.com/fatherchristmas">Father Christmas </a></h1>
<a class="email" href="mailto:fatherchristmas@elliotjaystocks.com?subject=Here, have some Christmas cheer!">fatherchristmas@elliotjaystocks.com</a>
<ul class="adr">
<li class="street-address">25 Laughingallthe Way</li>
<li class="locality">Snow Falls</li>
<li class="region">Lapland</li>
<li class="postal-code">FI-00101</li>
<li class="country-name">Finland</li>
</ul>
<span class="tel">010 60 58 000</span>
</div>
<div class="photo"></div>
<br class="christmas-cheer" />
</div>
<div class="credits">
<p>A tutorial by <a href="http://elliotjaystocks.com">Elliot Jay Stocks</a> for <a href="http://24ways.org/">24 Ways</a></p>
<p>Background: <a href="http://sxc.hu/photo/1108741">stock.xchng</a> | Father Christmas: <a href="http://istockphoto.com/file_closeup/people/4575943-active-santa.php?id=4575943">iStockPhoto</a></p>
</div>
Step 6: Some Christmas Sparkle
So far, our hCard-housing web page is slightly less than inspiring, isn’t it? It’s time to add a bit of CSS. There’s nothing particularly radical going on here; just a simple layout, some basic typographic treatment, and the placement of the Father Christmas photo. I’d usually use a more thorough CSS reset like the one found in the YUI or Eric Meyer’s, but for this basic page, the simple * solution will do.
Check out the step 6 demo to see our basic styles in place.
From this…
… to this:
Step 7: Fun With imagery
Now it’s time to introduce a repeating background image to the <body> element. This will seamlessly repeat for as wide as the browser window becomes.
But that’s fairly straightforward. How about having some fun with the Father Christmas image? If you look at the image file itself, you’ll see that it’s twice as wide as the area we can see and contains a ‘hidden’ photo of our rather camp St. Nick.
As a light-hearted visual… er… ‘treat’ for users who move their mouse over the image, we move the position of the background image on the “photo” div. Check out the step 7 demo to see it working.
Step 8: Progressive Enhancement
Finally, this fun little project is a great opportunity for us to mess around with some advanced CSS features (some from the CSS3 spec) that we rarely get to use on client projects. (Don’t forget: no Christmas pressies for clients who want you to support IE6!)
Here are the rules we’re using to give some browsers a superior viewing experience:
@font-face allows us to use Jos Buivenga’s free font ‘Fertigo Pro’ on all text;
text-shadow adds a little emphasis on the opening paragraph;
body > p:first-child causes only the first paragraph to receive this treatment;
border-radius created rounded corners on our main div and the links within it;
and webkit-transition allows us to gently fade in between the default and hover states of those links.
And with that, we’re done! You can see the results here. It’s time to customise the page to your liking, upload it to your site, and send out the URL. And do it quickly, because I’m sure you’ve got some last-minute Christmas shopping to finish off! |
2008 |
Elliot Jay Stocks |
elliotjaystocks |
2008-12-10T00:00:00+00:00 |
https://24ways.org/2008/a-christmas-hcard-from-me-to-you/ |
code |
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 |
104 |
Sitewide Search On A Shoe String |
One of the questions I got a lot when I was building web sites for smaller businesses was if I could create a search engine for their site. Visitors should be able to search only this site and find things without the maintainer having to put “related articles” or “featured content” links on every page by hand.
Back when this was all fields this wasn’t easy as you either had to write your own scraping tool, use ht://dig or a paid service from providers like Yahoo, Altavista or later on Google. In the former case you had to swallow the bitter pill of computing and indexing all your content and storing it in a database for quick access and in the latter it hurt your wallet.
Times have moved on and nowadays you can have the same functionality for free using Yahoo’s “Build your own search service” – BOSS. The cool thing about BOSS is that it allows for a massive amount of hits a day and you can mash up the returned data in any format you want. Another good feature of it is that it comes with JSON-P as an output format which makes it possible to use it without any server-side component!
Starting with a working HTML form
In order to add a search to your site, you start with a simple HTML form which you can use without JavaScript. Most search engines will allow you to filter results by domain. In this case we will search “bbc.co.uk”. If you use Yahoo as your standard search, this could be:
<form id="customsearch" action="http://search.yahoo.com/search">
<div>
<label for="p">Search this site:</label>
<input type="text" name="p" id="term">
<input type="hidden" name="vs" id="site" value="bbc.co.uk">
<input type="submit" value="go">
</div>
</form>
The Google equivalent is:
<form id="customsearch" action="http://www.google.co.uk/search">
<div>
<label for="p">Search this site:</label>
<input type="text" name="as_q" id="term">
<input type="hidden" name="as_sitesearch" id="site" value="bbc.co.uk">
<input type="submit" value="go">
</div>
</form>
In any case make sure to use the ID term for the search term and site for the site, as this is what we are going to use for the script. To make things easier, also have an ID called customsearch on the form.
To use BOSS, you should get your own developer API for BOSS and replace the one in the demo code. There is click tracking on the search results to see how successful your app is, so you should make it your own.
Adding the BOSS magic
BOSS is a REST API, meaning you can use it in any HTTP request or in a browser by simply adding the right parameters to a URL. Say for example you want to search “bbc.co.uk” for “christmas” all you need to do is open the following URL:
http://boss.yahooapis.com/ysearch/web/v1/christmas?sites=bbc.co.uk&format=xml&appid=YOUR-APPLICATION-ID
Try it out and click it to see the results in XML. We don’t want XML though, which is why we get rid of the format=xml parameter which gives us the same information in JSON:
http://boss.yahooapis.com/ysearch/web/v1/christmas?sites=bbc.co.uk&appid=YOUR-APPLICATION-ID
JSON makes most sense when you can send the output to a function and immediately use it. For this to happen all you need is to add a callback parameter and the JSON will be wrapped in a function call. Say for example we want to call SITESEARCH.found() when the data was retrieved we can do it this way:
http://boss.yahooapis.com/ysearch/web/v1/christmas?sites=bbc.co.uk&callback=SITESEARCH.found&appid=YOUR-APPLICATION-ID
You can use this immediately in a script node if you want to. The following code would display the total amount of search results for the term christmas on bbc.co.uk as an alert:
<script type="text/javascript">
var SITESEARCH = {};
SITESEARCH.found = function(o){
alert(o.ysearchresponse.totalhits);
}
</script>
<script type="text/javascript" src="http://boss.yahooapis.com/ysearch/web/v1/christmas?sites=bbc.co.uk&callback=SITESEARCH.found&appid=Kzv_lcHV34HIybw0GjVkQNnw4AEXeyJ9Rb1gCZSGxSRNrcif_HdMT9qTE1y9LdI-">
</script>
However, for our example, we need to be a bit more clever with this.
Enhancing the search form
Here’s the script that enhances a search form to show results below it.
SITESEARCH = function(){
var config = {
IDs:{
searchForm:'customsearch',
term:'term',
site:'site'
},
loading:'Loading results...',
noresults:'No results found.',
appID:'YOUR-APP-ID',
results:20
};
var form;
var out;
function init(){
if(config.appID === 'YOUR-APP-ID'){
alert('Please get a real application ID!');
} else {
form = document.getElementById(config.IDs.searchForm);
if(form){
form.onsubmit = function(){
var site = document.getElementById(config.IDs.site).value;
var term = document.getElementById(config.IDs.term).value;
if(typeof site === 'string' && typeof term === 'string'){
if(typeof out !== 'undefined'){
out.parentNode.removeChild(out);
}
out = document.createElement('p');
out.appendChild(document.createTextNode(config.loading));
form.appendChild(out);
var APIurl = 'http://boss.yahooapis.com/ysearch/web/v1/' +
term + '?callback=SITESEARCH.found&sites=' +
site + '&count=' + config.results +
'&appid=' + config.appID;
var s = document.createElement('script');
s.setAttribute('src',APIurl);
s.setAttribute('type','text/javascript');
document.getElementsByTagName('head')[0].appendChild(s);
return false;
}
};
}
}
};
function found(o){
var list = document.createElement('ul');
var results = o.ysearchresponse.resultset_web;
if(results){
var item,link,description;
for(var i=0,j=results.length;i<j;i++){
item = document.createElement('li');
link = document.createElement('a');
link.setAttribute('href',results[i].clickurl);
link.innerHTML = results[i].title;
item.appendChild(link);
description = document.createElement('p');
description.innerHTML = results[i]['abstract'];
item.appendChild(description);
list.appendChild(item);
}
} else {
list = document.createElement('p');
list.appendChild(document.createTextNode(config.noresults));
}
form.replaceChild(list,out);
out = list;
};
return{
config:config,
init:init,
found:found
};
}();
Oooohhhh scary code! Let’s go through this one bit at a time:
We start by creating a module called SITESEARCH and give it an configuration object:
SITESEARCH = function(){
var config = {
IDs:{
searchForm:'customsearch',
term:'term',
site:'site'
},
loading:'Loading results...',
appID:'YOUR-APP-ID',
results:20
}
Configuration objects are a great idea to make your code easy to change and also to override. In this case you can define different IDs than the one agreed upon earlier, define a message to show when the results are loading, when there aren’t any results, the application ID and the number of results that should be displayed.
Note: you need to replace “YOUR-APP-ID” with the real ID you retrieved from BOSS, otherwise the script will complain!
var form;
var out;
function init(){
if(config.appID === 'YOUR-APP-ID'){
alert('Please get a real application ID!');
} else {
We define form and out as variables to make sure that all the methods in the module have access to them. We then check if there was a real application ID defined. If there wasn’t, the script complains and that’s that.
form = document.getElementById(config.IDs.searchForm);
if(form){
form.onsubmit = function(){
var site = document.getElementById(config.IDs.site).value;
var term = document.getElementById(config.IDs.term).value;
if(typeof site === 'string' && typeof term === 'string'){
If the application ID was a winner, we check if the form with the provided ID exists and apply an onsubmit event handler. The first thing we get is the values of the site we want to search in and the term that was entered and check that those are strings.
if(typeof out !== 'undefined'){
out.parentNode.removeChild(out);
}
out = document.createElement('p');
out.appendChild(document.createTextNode(config.loading));
form.appendChild(out);
If both are strings we check of out is undefined. We will create a loading message and subsequently the list of search results later on and store them in this variable. So if out is defined, it’ll be an old version of a search (as users will re-submit the form over and over again) and we need to remove that old version.
We then create a paragraph with the loading message and append it to the form.
var APIurl = 'http://boss.yahooapis.com/ysearch/web/v1/' +
term + '?callback=SITESEARCH.found&sites=' +
site + '&count=' + config.results +
'&appid=' + config.appID;
var s = document.createElement('script');
s.setAttribute('src',APIurl);
s.setAttribute('type','text/javascript');
document.getElementsByTagName('head')[0].appendChild(s);
return false;
}
};
}
}
};
Now it is time to call the BOSS API by assembling a correct REST URL, create a script node and apply it to the head of the document. We return false to ensure the form does not get submitted as we want to stay on the page.
Notice that we are using SITESEARCH.found as the callback method, which means that we need to define this one to deal with the data returned by the API.
function found(o){
var list = document.createElement('ul');
var results = o.ysearchresponse.resultset_web;
if(results){
var item,link,description;
We create a new list and then get the resultset_web array from the data returned from the API. If there aren’t any results returned, this array will not exist which is why we need to check for it. Once we done that we can define three variables to repeatedly store the item title we want to display, the link to point to and the description of the link.
for(var i=0,j=results.length;i<j;i++){
item = document.createElement('li');
link = document.createElement('a');
link.setAttribute('href',results[i].clickurl);
link.innerHTML = results[i].title;
item.appendChild(link);
description = document.createElement('p');
description.innerHTML = results[i]['abstract'];
item.appendChild(description);
list.appendChild(item);
}
We then loop over the results array and assemble a list of results with the titles in links and paragraphs with the abstract of the site. Notice the bracket notation for abstract as abstract is a reserved word in JavaScript2 :).
} else {
list = document.createElement('p');
list.appendChild(document.createTextNode(config.noresults));
}
form.replaceChild(list,out);
out = list;
};
If there aren’t any results, we define a paragraph with the no results message as list. In any case we replace the old out (the loading message) with the list and re-define out as the list.
return{
config:config,
init:init,
found:found
};
}();
All that is left to do is return the properties and methods we want to make public. In this case found needs to be public as it is accessed by the API return. We return init to make it accessible and config to allow implementers to override any of the properties.
Using the script
In order to use this script, all you need to do is to add it after the form in the document, override the API key with your own and call init():
<form id="customsearch" action="http://search.yahoo.com/search">
<div>
<label for="p">Search this site:</label>
<input type="text" name="p" id="term">
<input type="hidden" name="vs" id="site" value="bbc.co.uk">
<input type="submit" value="go">
</div>
</form>
<script type="text/javascript" src="boss-site-search.js"></script>
<script type="text/javascript">
SITESEARCH.config.appID = 'copy-the-id-you-know-to-get-where';
SITESEARCH.init();
</script>
Where to go from here
This is just a very simple example of what you can do with BOSS. You can define languages and regions, retrieve and display images and news and mix the results with other data sources before displaying them. One very cool feature is that by adding a view=keyterms parameter to the URL you can get the keywords of each of the results to drill deeper into the search. An example for this written in PHP is available on the YDN blog. For JavaScript solutions there is a handy wrapper called yboss available to help you go nuts. |
2008 |
Christian Heilmann |
chrisheilmann |
2008-12-04T00:00:00+00:00 |
https://24ways.org/2008/sitewide-search-on-a-shoestring/ |
code |
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 |
110 |
Shiny Happy Buttons |
Since Mac OS X burst onto our screens, glossy, glassy, shiny buttons have been almost de rigeur, and have essentially, along with reflections and rounded corners, become a cliché of Web 2.0 “design”. But if you can’t beat ‘em you’d better join ‘em. So, in this little contribution to our advent calendar, we’re going to take a plain old boring HTML button, and 2.0 it up the wazoo.
But, here’s the catch. We’ll use no images, either in our HTML or our CSS. No sliding doors, no image replacement techniques. Just straight up, CSS, CSS3 and a bit of experimental CSS. And, it will be compatible with pretty much any browser (though with some progressive enhancement for those who keep up with the latest browsers).
The HTML
We’ll start with our HTML.
<button type="submit">This is a shiny button</button>
OK, so it’s not shiny yet – but boy will it ever be.
Before styling, that’s going to look like this.
Ironically, depending on the operating system and browser you are using, it may well be a shiny button already, but that’s not the point. We want to make it shiny 2.0. Our mission is to make it look something like this
If you want to follow along at home keep in mind that depending on which browser you are using you may see fewer of the CSS effects we’ve added to create the button. As of writing, only in Safari are all the effects we’ll apply supported.
Taking a look at our finished product, here’s what we’ve done to it:
We’ve given the button some padding and a width.
We’ve changed the text color, and given the text a drop shadow.
We’ve given the button a border.
We’ve given the button some rounded corners.
We’ve given the button a drop shadow.
We’ve given the button a gradient background.
and remember, all without using any images.
Styling the button
So, let’s get to work.
First, we’ll add given the element some padding and a width:
button {
padding: .5em;
width: 15em;
}
Next, we’ll add the text color, and the drop shadow:
color: #ffffff;
text-shadow: 1px 1px 1px #000;
A note on text-shadow
If you’ve not seen text-shadows before well, here’s the quick back-story. Text shadow was introduced in CSS2, but only supported in Safari (version 1!) some years later. It was removed from CSS2.1, but returned in CSS3 (in the text module). It’s now supported in Safari, Opera and Firefox (3.1). Internet Explorer has a shadow filter, but the syntax is completely different.
So, how do text-shadows work? The three length values specify respectively a horizontal offset, a vertical offset and a blur (the greater the number the more blurred the shadow will be), and finally a color value for the shadow.
Rounding the corners
Now we’ll add a border, and round the corners of the element:
border: solid thin #882d13;
-webkit-border-radius: .7em;
-moz-border-radius: .7em;
border-radius: .7em;
Here, we’ve used the same property in three slightly different forms. We add the browser specific prefix for Webkit and Mozilla browsers, because right now, both of these browsers only support border radius as an experimental property. We also add the standard property name, for browsers that do support the property fully in the future.
The benefit of the browser specific prefix is that if a browser only partly supports a given property, we can easily avoid using the property with that browser simply by not adding the browser specific prefix. At present, as you might guess, border-radius is supported in Safari and Firefox, but in each the relevant prefix is required.
border-radius takes a length value, such as pixels. (It can also take two length values, but that’s for another Christmas.) In this case, as with padding, I’ve used ems, which means that as the user scales the size of text up and down, the radius will scale as well. You can test the difference by making the radius have a value of say 5px, and then zooming up and down the text size.
We’re well and truly on the way now. All we need to do is add a shadow to the button, and then a gradient background.
In CSS3 there’s the box-shadow property, currently only supported in Safari 3. It’s very similar to text-shadow – you specify a horizontal and vertical offset, a blur value and a color.
-webkit-box-shadow: 2px 2px 3px #999;
box-shadow: 2px 2px 2px #bbb;
Once more, we require the “experimental” -webkit- prefix, as Safari’s support for this property is still considered by its developers to be less than perfect.
Gradient Background
So, all we have left now is to add our shiny gradient effect. Now of course, people have been doing this kind of thing with images for a long time. But if we can avoid them all the better. Smaller pages, faster downloads, and more scalable designs that adapt better to the user’s font size preference. But how can we add a gradient background without an image?
Here we’ll look at the only property that is not as yet part of the CSS standard – Apple’s gradient function for use anywhere you can use images with CSS (in this case backgrounds). In essence, this takes SVG gradients, and makes them available via CSS syntax.
Here’s what the property and its value looks like:
background-image: -webkit-gradient(linear, left top, left bottom, from(#e9ede8), to(#ce401c),color-stop(0.4, #8c1b0b));
Zooming in on the gradient function, it has this basic form:
-webkit-gradient(type, point, point, from(color), to(color),color-stop(where, color));
Which might look complicated, but is less so than at first glance.
The name of the function is gradient (and in this case, because it is an experimental property, we use the -webkit- prefix).
You might not have seen CSS functions before, but there are others, including the attr() function, used with generated content. A function returns a value that can be used as a property value – here we are using it as a background image.
Next we specify the type of the gradient. Here we have a linear gradient, and there are also radial gradients.
After that, we specify the start and end points of the gradient – in our case the top and bottom of the element, in a vertical line.
We then specify the start and end colors – and finally one stop color, located at 40% of the way down the element. Together, this creates a gradient that smoothly transitions from the start color in the top, vertically to the stop color, then smoothly transitions to the end color.
There’s one last thing. What color will the background of our button be if the browser doesn’t support gradients? It will be white (or possibly some default color for buttons). Which may make the text difficult or impossible to read. So, we’ll add a background color as well (see why the validator is always warning you when a color but not a background color is specified for an element?).
If we put it all together, here’s what we have:
button {
width: 15em;
padding: .5em;
color: #ffffff;
text-shadow: 1px 1px 1px #000;
border: solid thin #882d13;
-webkit-border-radius: .7em;
-moz-border-radius: .7em;
border-radius: .7em;
-webkit-box-shadow: 2px 2px 3px #999;
box-shadow: 2px 2px 2px #bbb;
background-color: #ce401c;
background-image: -webkit-gradient(linear, left top, left bottom, from(#e9ede8), to(#ce401c),color-stop(0.4, #8c1b0b));
}
Which looks like this in various browsers:
In Safari (3)
In Firefox 3.1 (3.0 supports border-radius but not text-shadow)
In Opera 10
and of course in Internet Explorer (version 8 shown here)
But it looks different in different browsers
Yes, it does look different in different browsers, but we all know the answer to the question “do web sites need to look the same in every browser?“.
Even if you really think sites should look the same in every browser, hopefully this little tutorial has whet your appetite for what CSS3 and experimental CSS that’s already supported in widely used browsers (and we haven’t even touched on animations and similar effects!).
I hope you’ve enjoyed out little CSSMas present, and look forward to seeing your shiny buttons everywhere on the web.
Oh, and there’s just a bit of homework – your job is to use the :hover selector, and make a gradient in the hover state. |
2008 |
John Allsopp |
johnallsopp |
2008-12-18T00:00:00+00:00 |
https://24ways.org/2008/shiny-happy-buttons/ |
code |
116 |
The IE6 Equation |
It is the destiny of one browser to serve as the nemesis of web developers everywhere. At the birth of the Web Standards movement, that role was played by Netscape Navigator 4; an outdated browser that refused to die. Its tenacious existence hampered the adoption of modern standards. Today that role is played by Internet Explorer 6.
There’s a sensation that I’m sure you’re familiar with. It’s a horrible mixture of dread and nervousness. It’s the feeling you get when—after working on a design for a while in a standards-compliant browser like Firefox, Safari or Opera—you decide that you can no longer put off the inevitable moment when you must check the site in IE6. Fingers are crossed, prayers are muttered, but alas, to no avail. The nemesis browser invariably screws something up.
What do you do next? If the differences in IE6 are minor, you could just leave it be. After all, websites don’t need to look exactly the same in all browsers. But if there are major layout issues and a significant portion of your audience is still using IE6, you’ll probably need to roll up your sleeves and start fixing the problems.
A common approach is to quarantine IE6-specific CSS in a separate stylesheet. This stylesheet can then be referenced from the HTML document using conditional comments like this:
<!--[if lt IE 7]>
<link rel="stylesheet" href="ie6.css" type="text/css" media="screen" />
<![endif]-->
That stylesheet will only be served up to Internet Explorer where the version number is less than 7.
You can put anything inside a conditional comment. You could put a script element in there. So as well as serving up browser-specific CSS, it’s possible to serve up browser-specific JavaScript.
A few years back, before Microsoft released Internet Explorer 7, JavaScript genius Dean Edwards wrote a script called IE7. This amazing piece of code uses JavaScript to make Internet Explorer 5 and 6 behave like a standards-compliant browser. Dean used JavaScript to bootstrap IE’s CSS support.
Because the script is specifically targeted at Internet Explorer, there’s no point in serving it up to other browsers. Conditional comments to the rescue:
<!--[if lt IE 7]>
<script src="http://ie7-js.googlecode.com/svn/version/2.0(beta3)/IE7.js" type="text/javascript"></script>
<![endif]-->
Standards-compliant browsers won’t fetch the script. Users of IE6, on the hand, will pay a kind of bad browser tax by having to download the JavaScript file.
So when should you develop an IE6-specific stylesheet and when should you just use Dean’s JavaScript code? This is the question that myself and my co-worker Natalie Downe set out to answer one morning at Clearleft. We realised that in order to answer that question you need to first answer two other questions, how much time does it take to develop for IE6? and how much of your audience is using IE6?
Let’s say that t represents the total development time. Let t6 represent the portion of that time you spend developing for IE6. If your total audience is a, then a6 is the portion of your audience using IE6. With some algebraic help from our mathematically minded co-worker Cennydd Bowles, Natalie and I came up with the following equation to calculate the percentage likelihood that you should be using Dean’s IE7 script:
p = 50 [ log ( at6 / ta6 ) + 1 ]
Try plugging in your own numbers. If you spend a lot of time developing for IE6 and only a small portion of your audience is using that browser, you’ll get a very high number out of the equation; you should probably use the IE7 script. But if you only spend a little time developing for IE6 and a significant portion of you audience are still using that browser, you’ll get a very small value for p; you might as well write an IE6-specific stylesheet.
Of course this equation is somewhat disingenuous. While it’s entirely possible to research the percentage of your audience still using IE6, it’s not so easy to figure out how much of your development time will be spent developing for that one browser. You can’t really know until you’ve already done the development, by which time the equation is irrelevant.
Instead of using the equation, you could try imposing a limit on how long you will spend developing for IE6. Get your site working in standards-compliant browsers first, then give yourself a time limit to get it working in IE6. If you can’t solve all the issues in that time limit, switch over to using Dean’s script. You could even make the time limit directly proportional to the percentage of your audience using IE6. If 20% of your audience is still using IE6 and you’ve just spent five days getting the site working in standards-compliant browsers, give yourself one day to get it working in IE6. But if 50% of your audience is still using IE6, be prepared to spend 2.5 days wrestling with your nemesis.
All of these different methods for dealing with IE6 demonstrate that there’s no one single answer that works for everyone. They also highlight a problem with the current debate around dealing with IE6. There’s no shortage of blog posts, articles and even entire websites discussing when to drop support for IE6. But very few of them take the time to define what they mean by “support.” This isn’t a binary issue. There is no Boolean answer. Instead, there’s a sliding scale of support:
Block IE6 users from your site.
Develop with web standards and don’t spend any development time testing in IE6.
Use the Dean Edwards IE7 script to bootstrap CSS support in IE6.
Write an IE6 stylesheet to address layout issues.
Make your site look exactly the same in IE6 as in any other browser.
Each end of that scale is extreme. I don’t think that anybody should be actively blocking any browser but neither do I think that users of an outdated browser should get exactly the same experience as users of a more modern browser. The real meanings of “supporting” or “not supporting” IE6 lie somewhere in-between those extremes.
Just as I think that semantics are important in markup, they are equally important in our discussion of web development. So let’s try to come up with some better terms than using the catch-all verb “support.” If you say in your client contract that you “support” IE6, define exactly what that means. If you find yourself in a discussion about “dropping support” for IE6, take the time to explain what you think that entails.
The web developers at Yahoo! are on the right track with their concept of graded browser support. I’m interested in hearing more ideas of how to frame this discussion. If we can all agree to use clear and precise language, we stand a better chance of defeating our nemesis. |
2008 |
Jeremy Keith |
jeremykeith |
2008-12-08T00:00:00+00:00 |
https://24ways.org/2008/the-ie6-equation/ |
code |
117 |
The First Tool You Reach For |
Microsoft recently announced that Internet Explorer 8 will be released in the first half of 2009. Compared to the standards support of other major browsers, IE8 will not be especially great, but it will finally catch up with the state of the art in one specific area: support for CSS tables. This milestone has the potential to trigger an important change in the way you approach web design.
To show you just how big a difference CSS tables can make, think about how you might code a fluid, three-column layout from scratch. Just to make your life more difficult, give it one fixed-width column, with a background colour that differs from the rest of the page. Ready? Go!
Okay, since you’re the sort of discerning web designer who reads 24ways, I’m going to assume you at least considered doing this without using HTML tables for the layout. If you’re especially hardcore, I imagine you began thinking of CSS floats, negative margins, and faux columns. If you did, colour me impressed!
Now admit it: you probably also gave an inward sigh about the time it would take to figure out the math on the negative margin overlaps, check for dropped floats in Internet Explorer and generally wrestle each of the major browsers into giving you what you want. If after all that you simply gave up and used HTML tables, I can’t say I blame you.
There are plenty of professional web designers out there who still choose to use HTML tables as their main layout tool. Sure, they may know that users with screen readers get confused by inappropriate use of tables, but they have a job to do, and they want tools that will make that job easy, not difficult.
Now let me show you how to do it with CSS tables. First, we have a div element for each of our columns, and we wrap them all in another two divs:
<div class="container">
<div>
<div id="menu">
⋮
</div>
<div id="content">
⋮
</div>
<div id="sidebar">
⋮
</div>
</div>
</div>
Don’t sweat the “div clutter” in this code. Unlike tables, divs have no semantic meaning, and can therefore be used liberally (within reason) to provide hooks for the styles you want to apply to your page.
Using CSS, we can set the outer div to display as a table with collapsed borders (i.e. adjacent cells share a border) and a fixed layout (i.e. cell widths unaffected by their contents):
.container {
display: table;
border-collapse: collapse;
table-layout: fixed;
}
With another two rules, we set the middle div to display as a table row, and each of the inner divs to display as table cells:
.container > div {
display: table-row;
}
.container > div > div {
display: table-cell;
}
Finally, we can set the widths of the cells (and of the table itself) directly:
.container {
width: 100%;
}
#menu {
width: 200px;
}
#content {
width: auto;
}
#sidebar {
width: 25%;
}
And, just like that, we have a rock solid three-column layout, ready to be styled to your own taste, like in this example:
This example will render perfectly in reasonably up-to-date versions of Firefox, Safari and Opera, as well as the current beta release of Internet Explorer 8.
CSS tables aren’t only useful for multi-column page layout; they can come in handy in most any situation that calls for elements to be displayed side-by-side on the page. Consider this simple login form layout:
The incantation required to achieve this layout using CSS floats may be old hat to you by now, but try to teach it to a beginner, and watch his eyes widen in horror at the hoops you have to jump through (not to mention the assumptions you have to build into your design about the length of the form labels).
Here’s how to do it with CSS tables:
<form action="/login" method="post">
<div>
<div>
<label for="username">Username:</label>
<span class="input"><input type="text" name="username" id="username"/></span>
</div>
<div>
<label for="userpass">Password:</label>
<span class="input"><input type="password" name="userpass" id="userpass"/></span>
</div>
<div class="submit">
<label for="login"></label>
<span class="input"><input type="submit" name="login" id="login" value="Login"/></span>
</div>
</div>
</form>
This time, we’re using a mixture of divs and spans as semantically transparent styling hooks. Let’s look at the CSS code.
First, we set up the outer div to display as a table, the inner divs to display as table rows, and the labels and spans as table cells (with right-aligned text):
form > div {
display: table;
}
form > div > div {
display: table-row;
}
form label,
form span {
display: table-cell;
text-align: right;
}
We want the first column of the table to be wide enough to accommodate our labels, but no wider. With CSS float techniques, we had to guess at what that width was likely to be, and adjust it whenever we changed our form labels. With CSS tables, we can simply set the width of the first column to something very small (1em), and then use the white-space property to force the column to the required width:
form label {
white-space: nowrap;
width: 1em;
}
To polish off the layout, we’ll make our text and password fields occupy the full width of the table cells that contain them:
input[type=text],
input[type=password] {
width: 100%;
}
The rest is margins, padding and borders to get the desired look. Check out the finished example.
As the first tool you reach for when approaching any layout task, CSS tables make a lot more sense to your average designer than the cryptic incantations called for by CSS floats. When IE8 is released and all major browsers support CSS tables, we can begin to gradually deploy CSS table-based layouts on sites that are more and more mainstream.
In our new book, Everything You Know About CSS Is Wrong!, Rachel Andrew and I explore in much greater detail how CSS tables work as a page layout tool in the real world. CSS tables have their quirks just like floats do, but they don’t tend to affect common layout tasks, and the workarounds tend to be less fiddly too. Check it out, and get ready for the next big step forward in web design with CSS. |
2008 |
Kevin Yank |
kevinyank |
2008-12-13T00:00:00+00:00 |
https://24ways.org/2008/the-first-tool-you-reach-for/ |
code |
121 |
Hide And Seek in The Head |
If you want your JavaScript-enhanced pages to remain accessible and understandable to scripted and noscript users alike, you have to think before you code. Which functionalities are required (ie. should work without JavaScript)? Which ones are merely nice-to-have (ie. can be scripted)? You should only start creating the site when you’ve taken these decisions.
Special HTML elements
Once you have a clear idea of what will work with and without JavaScript, you’ll likely find that you need a few HTML elements for the noscript version only.
Take this example: A form has a nifty bit of Ajax that automatically and silently sends a request once the user enters something in a form field. However, in order to preserve accessibility, the user should also be able to submit the form normally. So the form should have a submit button in noscript browsers, but not when the browser supports sufficient JavaScript.
Since the button is meant for noscript browsers, it must be hard-coded in the HTML:
<input type="submit" value="Submit form" id="noScriptButton" />
When JavaScript is supported, it should be removed:
var checkJS = [check JavaScript support];
window.onload = function () {
if (!checkJS) return;
document.getElementById('noScriptButton').style.display = 'none';
}
Problem: the load event
Although this will likely work fine in your testing environment, it’s not completely correct. What if a user with a modern, JavaScript-capable browser visits your page, but has to wait for a huge graphic to load? The load event fires only after all assets, including images, have been loaded. So this user will first see a submit button, but then all of a sudden it’s removed. That’s potentially confusing.
Fortunately there’s a simple solution: play a bit of hide and seek in the <head>:
var checkJS = [check JavaScript support];
if (checkJS) {
document.write('<style>#noScriptButton{display: none}</style>');
}
First, check if the browser supports enough JavaScript. If it does, document.write an extra <style> element that hides the button.
The difference with the previous technique is that the document.write command is outside any function, and is therefore executed while the JavaScript is being parsed. Thus, the #noScriptButton{display: none} rule is written into the document before the actual HTML is received.
That’s exactly what we want. If the rule is already present at the moment the HTML for the submit button is received and parsed, the button is hidden immediately. Even if the user (and the load event) have to wait for a huge image, the button is already hidden, and both scripted and noscript users see the interface they need, without any potentially confusing flashes of useless content.
In general, if you want to hide content that’s not relevant to scripted users, give the hide command in CSS, and make sure it’s given before the HTML element is loaded and parsed.
Alternative
Some people won’t like to use document.write. They could also add an empty <link /> element to the <head> and give it an href attribute once the browser’s JavaScript capabilities have been evaluated. The <link /> element is made to refer to a style sheet that contains the crucial #noScriptButton{display: none}, and everything works fine.
Important note: The script needs access to the <link />, and the only way to ensure that access is to include the empty <link /> element before your <script> tag. |
2006 |
Peter-Paul Koch |
ppk |
2006-12-06T00:00:00+00:00 |
https://24ways.org/2006/hide-and-seek-in-the-head/ |
code |
124 |
Writing Responsible JavaScript |
Without a doubt, JavaScript has been making something of a comeback in the last year. If you’re involved in client-side development in any way at all, chances are that you’re finding yourself writing more JavaScript now than you have in a long time.
If you learned most of your JavaScript back when DHTML was all the rage and before DOM Scripting was in vogue, there have been some big shifts in the way scripts are written. Most of these are in the way event handlers are assigned and functions declared. Both of these changes are driven by the desire to write scripts that are responsible page citizens, both in not tying behaviour to content and in taking care not to conflict with other scripts. I thought it may be useful to look at some of these more responsible approaches to learn how to best write scripts that are independent of the page content and are safely portable between different applications.
Event Handling
Back in the heady days of Web 1.0, if you wanted to have an object on the page react to something like a click, you would simply go ahead and attach an onclick attribute. This was easy and understandable, but much like the font tag or the style attribute, it has the downside of mixing behaviour or presentation in with our content. As we’re learned with CSS, there are big benefits in keeping those layers separate. Hey, if it works for CSS, it should work for JavaScript too.
Just like with CSS, instead of adding an attribute to our element within the document, the more responsible way to do that is to look for the item from your script (like CSS does with a selector) and then assign the behaviour to it. To give an example, take this oldskool onclick use case:
<a id="anim-link" href="#" onclick="playAnimation()">Play the animation</a>
This could be rewritten by removing the onclick attribute, and instead doing the following from within your JavaScript.
document.getElementById('anim-link').onclick = playAnimation;
It’s all in the timing
Of course, it’s never quite that easy. To be able to attach that onclick, the element you’re targeting has to exist in the page, and the page has to have finished loading for the DOM to be available. This is where the onload event is handy, as it fires once everything has finished loading. Common practise is to have a function called something like init() (short for initialise) that sets up all these event handlers as soon as the page is ready.
Back in the day we would have used the onload attibute on the <body> element to do this, but of course what we really want is:
window.onload = init;
As an interesting side note, we’re using init here rather than init() so that the function is assigned to the event. If we used the parentheses, the init function would have been run at that moment, and the result of running the function (rather than the function itself) would be assigned to the event. Subtle, but important.
As is becoming apparent, nothing is ever simple, and we can’t just go around assigning our initialisation function to window.onload. What if we’re using other scripts in the page that might also want to listen out for that event? Whichever script got there last would overwrite everything that came before it. To manage this, we need a script that checks for any existing event handlers, and adds the new handler to it. Most of the JavaScript libraries have their own systems for doing this. If you’re not using a library, Simon Willison has a good stand-alone example
function addLoadEvent(func) {
var oldonload = window.onload;
if (typeof window.onload != 'function') {
window.onload = func;
} else {
window.onload = function() {
if (oldonload) {
oldonload();
}
func();
}
}
}
Obviously this is just a toe in the events model’s complex waters. Some good further reading is PPK’s Introduction to Events.
Carving out your own space
Another problem that rears its ugly head when combining multiple scripts on a single page is that of making sure that the scripts don’t conflict. One big part of that is ensuring that no two scripts are trying to create functions or variables with the same names. Reusing a name in JavaScript just over-writes whatever was there before it.
When you create a function in JavaScript, you’ll be familiar with doing something like this.
function foo() {
... goodness ...
}
This is actually just creating a variable called foo and assigning a function to it. It’s essentially the same as the following.
var foo = function() {
... goodness ...
}
This name foo is by default created in what’s known as the ‘global namespace’ – the general pool of variables within the page. You can quickly see that if two scripts use foo as a name, they will conflict because they’re both creating those variables in the global namespace.
A good solution to this problem is to add just one name into the global namespace, make that one item either a function or an object, and then add everything else you need inside that. This takes advantage of JavaScript’s variable scoping to contain you mess and stop it interfering with anyone else.
Creating An Object
Say I was wanting to write a bunch of functions specifically for using on a site called ‘Foo Online’. I’d want to create my own object with a name I think is likely to be unique to me.
var FOOONLINE = {};
We can then start assigning functions are variables to it like so:
FOOONLINE.message = 'Merry Christmas!';
FOOONLINE.showMessage = function() {
alert(this.message);
};
Calling FOOONLINE.showMessage() in this example would alert out our seasonal greeting. The exact same thing could also be expressed in the following way, using the object literal syntax.
var FOOONLINE = {
message: 'Merry Christmas!',
showMessage: function() {
alert(this.message);
}
};
Creating A Function to Create An Object
We can extend this idea bit further by using a function that we run in place to return an object. The end result is the same, but this time we can use closures to give us something like private methods and properties of our object.
var FOOONLINE = function(){
var message = 'Merry Christmas!';
return {
showMessage: function(){
alert(message);
}
}
}();
There are two important things to note here. The first is the parentheses at the end of line 10. Just as we saw earlier, this runs the function in place and causes its result to be assigned. In this case the result of our function is the object that is returned at line 4.
The second important thing to note is the use of the var keyword on line 2. This ensures that the message variable is created inside the scope of the function and not in the global namespace. Because of the way closure works (which if you’re not familiar with, just suspend your disbelief for a moment) that message variable is visible to everything inside the function but not outside. Trying to read FOOONLINE.message from the page would return undefined.
This is useful for simulating the concept of private class methods and properties that exist in other programming languages. I like to take the approach of making everything private unless I know it’s going to be needed from outside, as it makes the interface into your code a lot clearer for someone else to read.
All Change, Please
So that was just a whistle-stop tour of a couple of the bigger changes that can help to make your scripts better page citizens. I hope it makes useful Sunday reading, but obviously this is only the tip of the iceberg when it comes to designing modular, reusable code.
For some, this is all familiar ground already. If that’s the case, I encourage you to perhaps submit a comment with any useful resources you’ve found that might help others get up to speed. Ultimately it’s in all of our interests to make sure that all our JavaScript interoperates well – share your tips. |
2006 |
Drew McLellan |
drewmclellan |
2006-12-10T00:00:00+00:00 |
https://24ways.org/2006/writing-responsible-javascript/ |
code |
126 |
Intricate Fluid Layouts in Three Easy Steps |
The Year of the Script may have drawn attention away from CSS but building fluid, multi-column, cross-browser CSS layouts can still be as unpleasant as a lump of coal. Read on for a worry-free approach in three quick steps.
The layout system I developed, YUI Grids CSS, has three components. They can be used together as we’ll see, or independently.
The Three Easy Steps
Choose fluid or fixed layout, and choose the width (in percents or pixels) of the page.
Choose the size, orientation, and source-order of the main and secondary blocks of content.
Choose the number of columns and how they distribute (for example 50%-50% or 25%-75%), using stackable and nestable grid structures.
The Setup
There are two prerequisites: We need to normalize the size of an em and opt into the browser rendering engine’s Strict Mode.
Ems are a superior unit of measure for our case because they represent the current font size and grow as the user increases their font size setting. This flexibility—the container growing with the user’s wishes—means larger text doesn’t get crammed into an unresponsive container. We’ll use YUI Fonts CSS to set the base size because it provides consistent-yet-adaptive font-sizes while preserving user control.
The second prerequisite is to opt into Strict Mode (more info on rendering modes) by declaring a Doctype complete with URI. You can choose XHTML or HTML, and Transitional or Strict. I prefer HTML 4.01 Strict, which looks like this:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
Including the CSS
A single small CSS file powers a nearly-infinite number of layouts thanks to a recursive system and the interplay between the three distinct components. You could prune to a particular layout’s specific needs, but why bother when the complete file weighs scarcely 1.8kb uncompressed? Compressed, YUI Fonts and YUI Grids combine for a miniscule 0.9kb over the wire.
You could save an HTTP request by concatenating the two CSS files, or by adding their contents to your own CSS, but I’ll keep them separate for now:
<link href="fonts.css" rel="stylesheet" type="text/css">
<link href="grids.css" rel="stylesheet" type="text/css">
Example: The Setup
Now we’re ready to build some layouts.
Step 1: Choose Fluid or Fixed Layout
Choose between preset widths of 750px, 950px, and 100% by giving a document-wrapping div an ID of doc, doc2, or doc3. These options cover most use cases, but it’s easy to define a custom fixed width.
The fluid 100% grid (doc3) is what I’ve been using almost exclusively since it was introduced in the last YUI released.
<body>
<div id="doc3"></div>
</body>
All pages are centered within the viewport, and grow with font size. The 100% width page (doc3) preserves 10px of breathing room via left and right margins. If you prefer your content flush to the viewport, just add doc3 {margin:auto} to your CSS.
Regardless of what you choose in the other two steps, you can always toggle between these widths and behaviors by simply swapping the ID value. It’s really that simple.
Example: 100% fluid layout
Step 2: Choose a Template Preset
This is perhaps the most frequently omitted step (they’re all optional), but I use it nearly every time. In a source-order-independent way (good for accessibility and SEO), “Template Presets” provide commonly used template widths compatible with ad-unit dimension standards defined by the Interactive Advertising Bureau, an industry association.
Choose between the six Template Presets (.yui-t1 through .yui-t6) by setting the class value on the document-wrapping div established in Step 1. Most frequently I use yui-t3, which puts the narrow secondary block on the left and makes it 300px wide.
<body>
<div id="doc3" class="yui-t3"></div>
</body>
The Template Presets control two “blocks” of content, which are defined by two divs, each with yui-b (“b” for “block”) class values. Template Presets describe the width and orientation of the secondary block; the main block will take up the rest of the space.
<body>
<div id="doc3" class="yui-t3">
<div class="yui-b"></div>
<div class="yui-b"></div>
</div>
</body>
Use a wrapping div with an ID of yui-main to structurally indicate which block is the main block. This wrapper—not the source order—identifies the main block.
<body>
<div id="doc3" class="yui-t3">
<div id="yui-main">
<div class="yui-b"></div>
</div>
<div class="yui-b"></div>
</div>
</body>
Example: Main and secondary blocks sized and oriented with .yui-t3 Template Preset
Again, regardless of what values you choose in the other steps, you can always toggle between these Template Presets by toggling the class value of your document-wrapping div. It’s really that simple.
Step 3: Nest and Stack Grid Structures.
The bulk of the power of the system is in this third step. The key is that columns are built by parents telling children how to behave. By default, two children each consume half of their parent’s area. Put two units inside a grid structure, and they will sit side-by-side, and they will each take up half the space. Nest this structure and two columns become four. Stack them for rows of columns.
An Even Number of Columns
The default behavior creates two evenly-distributed columns. It’s easy. Define one parent grid with .yui-g (“g” for grid) and two child units with .yui-u (“u” for unit). The code looks like this:
<div class="yui-g">
<div class="yui-u first"></div>
<div class="yui-u"></div>
</div>
Be sure to indicate the “first“ unit because the :first-child pseudo-class selector isn’t supported across all A-grade browsers. It’s unfortunate we need to add this, but luckily it’s not out of place in the markup layer since it is structural information.
Example: Two evenly-distributed columns in the main content block
An Odd Number of Columns
The default system does not work for an odd number of columns without using the included “Special Grids” classes. To create three evenly distributed columns, use the “yui-gb“ Special Grid:
<div class="yui-gb">
<div class="yui-u first"></div>
<div class="yui-u"></div>
<div class="yui-u"></div>
</div>
Example: Three evenly distributed columns in the main content block
Uneven Column Distribution
Special Grids are also used for unevenly distributed column widths. For example, .yui-ge tells the first unit (column) to take up 75% of the parent’s space and the other unit to take just 25%.
<div class="yui-ge">
<div class="yui-u first"></div>
<div class="yui-u"></div>
</div>
Example: Two columns in the main content block split 75%-25%
Putting It All Together
Start with a full-width fluid page (div#doc3). Make the secondary block 180px wide on the right (div.yui-t4). Create three rows of columns: Three evenly distributed columns in the first row (div.yui-gb), two uneven columns (66%-33%) in the second row (div.yui-gc), and two evenly distributed columns in the thrid row.
<body>
<!-- choose fluid page and Template Preset -->
<div id="doc3" class="yui-t4">
<!-- main content block -->
<div id="yui-main">
<div class="yui-b">
<!-- stacked grid structure, Special Grid "b" -->
<div class="yui-gb">
<div class="yui-u first"></div>
<div class="yui-u"></div>
<div class="yui-u"></div>
</div>
<!-- stacked grid structure, Special Grid "c" -->
<div class="yui-gc">
<div class="yui-u first"></div>
<div class="yui-u"></div>
</div>
<!-- stacked grid structure -->
<div class="yui-g">
<div class="yui-u first"></div>
<div class="yui-u"></div>
</div>
</div>
</div>
<!-- secondary content block -->
<div class="yui-b"></div>
</div>
</body>
Example: A complex layout.
Wasn’t that easy? Now that you know the three “levers” of YUI Grids CSS, you’ll be creating headache-free fluid layouts faster than you can say “Peace on Earth”. |
2006 |
Nate Koechley |
natekoechley |
2006-12-20T00:00:00+00:00 |
https://24ways.org/2006/intricate-fluid-layouts/ |
code |
128 |
Boost Your Hyperlink Power |
There are HTML elements and attributes that we use every day. Headings, paragraphs, lists and images are the mainstay of every Web developer’s toolbox. Perhaps the most common tool of all is the anchor. The humble a element is what joins documents together to create the gloriously chaotic collection we call the World Wide Web.
Anatomy of an Anchor
The power of the anchor element lies in the href attribute, short for hypertext reference. This creates a one-way link to another resource, usually another page on the Web:
<a href="http://allinthehead.com/">
The href attribute sits in the opening a tag and some descriptive text sits between the opening and closing tags:
<a href="http://allinthehead.com/">Drew McLellan</a>
“Whoop-dee-freakin’-doo,” I hear you say, “this is pretty basic stuff” – and you’re quite right. But there’s more to the anchor element than just the href attribute.
The Theory of relativity
You might be familiar with the rel attribute from the link element. I bet you’ve got something like this in the head of your documents:
<link rel="stylesheet" type="text/css" media="screen" href="styles.css" />
The rel attribute describes the relationship between the linked document and the current document. In this case, the value of rel is “stylesheet”. This means that the linked document is the stylesheet for the current document: that’s its relationship.
Here’s another common use of rel:
<link rel="alternate" type="application/rss+xml" title="my RSS feed" href="index.xml" />
This describes the relationship of the linked file – an RSS feed – as “alternate”: an alternate view of the current document.
Both of those examples use the link element but you are free to use the rel attribute in regular hyperlinks. Suppose you’re linking to your RSS feed in the body of your page:
Subscribe to <a href="index.xml">my RSS feed</a>.
You can add extra information to this anchor using the rel attribute:
Subscribe to <a href="index.xml" rel="alternate" type="application/rss+xml">my RSS feed</a>.
There’s no prescribed list of values for the rel attribute so you can use whatever you decide is semantically meaningful. Let’s say you’ve got a complex e-commerce application that includes a link to a help file. You can explicitly declare the relationship of the linked file as being “help”:
<a href="help.html" rel="help">need help?</a>
Elemental Microformats
Although it’s completely up to you what values you use for the rel attribute, some consensus is emerging in the form of microformats. Some of the simplest microformats make good use of rel. For example, if you are linking to a license that covers the current document, use the rel-license microformat:
Licensed under a <a href="http://creativecommons.org/licenses/by/2.0/" rel="license">Creative Commons attribution license</a>
That describes the relationship of the linked document as “license.”
The rel-tag microformat goes a little further. It uses rel to describe the final part of the URL of the linked file as a “tag” for the current document:
Learn more about <a href="http://en.wikipedia.org/wiki/Microformats" rel="tag">semantic markup</a>
This states that the current document is being tagged with the value “Microformats.”
XFN, which stands for XHTML Friends Network, is a way of describing relationships between people:
<a href="http://allinthehead.com/" rel="friend">Drew McLellan</a>
This microformat makes use of a very powerful property of the rel attribute. Like the class attribute, rel can take multiple values, separated by spaces:
<a href="http://allinthehead.com/" rel="friend met colleague">Drew McLellan</a>
Here I’m describing Drew as being a friend, someone I’ve met, and a colleague (because we’re both Web monkies).
You Say You Want a revolution
While rel describes the relationship of the linked resource to the current document, the rev attribute describes the reverse relationship: it describes the relationship of the current document to the linked resource. Here’s an example of a link that might appear on help.html:
<a href="shoppingcart.html" rev="help">continue shopping</a>
The rev attribute declares that the current document is “help” for the linked file.
The vote-links microformat makes use of the rev attribute to allow you to qualify your links. By using the value “vote-for” you can describe your document as being an endorsement of the linked resource:
I agree with <a href="http://richarddawkins.net/home" rev="vote-for">Richard Dawkins</a>.
There’s a corresponding vote-against value. This means that you can link to a document but explicitly state that you don’t agree with it.
I agree with <a href="http://richarddawkins.net/home" rev="vote-for">Richard Dawkins</a>
about those <a href="http://www.icr.org/" rev="vote-against">creationists</a>.
Of course there’s nothing to stop you using both rel and rev on the same hyperlink:
<a href="http://richarddawkins.net/home" rev="vote-for" rel="muse">Richard Dawkins</a>
The Wisdom of Crowds
The simplicity of rel and rev belies their power. They allow you to easily add extra semantic richness to your hyperlinks. This creates a bounty that can be harvested by search engines, aggregators and browsers. Make it your New Year’s resolution to make friends with these attributes and extend the power of hypertext. |
2006 |
Jeremy Keith |
jeremykeith |
2006-12-18T00:00:00+00:00 |
https://24ways.org/2006/boost-your-hyperlink-power/ |
code |
129 |
Knockout Type - Thin Is Always In |
OS X has gorgeous native anti-aliasing (although I will admit to missing 10px aliased Geneva — *sigh*). This is especially true for dark text on a light background. However, things can go awry when you start using light text on a dark background. Strokes thicken. Counters constrict. Letterforms fill out like seasonal snackers.
So how do we combat the fat? In Safari and other Webkit-based browsers we can use the CSS ‘text-shadow’ property. While trying to add a touch more contrast to the navigation on haveamint.com I noticed an interesting side-effect on the weight of the type.
The second line in the example image above has the following style applied to it:
This creates an invisible drop-shadow. (Why is it invisible? The shadow is positioned directly behind the type (the first two zeros) and has no spread (the third zero). So the color, black, is completely eclipsed by the type it is supposed to be shadowing.)
Why applying an invisible drop-shadow effectively lightens the weight of the type is unclear. What is clear is that our light-on-dark text is now of a comparable weight to its dark-on-light counterpart.
You can see this trick in effect all over ShaunInman.com and in the navigation on haveamint.com and Subtraction.com. The HTML and CSS source code used to create the example images used in this article can be found here. |
2006 |
Shaun Inman |
shauninman |
2006-12-17T00:00:00+00:00 |
https://24ways.org/2006/knockout-type/ |
code |
132 |
Tasty Text Trimmer |
In most cases, when designing a user interface it’s best to make a decision about how data is best displayed and stick with it. Failing to make a decision ultimately leads to too many user options, which in turn can be taxing on the poor old user.
Under some circumstances, however, it’s good to give the user freedom in customising their workspace. One good example of this is the ‘Article Length’ tool in Apple’s Safari RSS reader. Sliding a slider left of right dynamically changes the length of each article shown. It’s that kind of awesomey magic stuff that’s enough to keep you from sleeping. Let’s build one.
The Setup
Let’s take a page that has lots of long text items, a bit like a news page or like Safari’s RSS items view. If we were to attach a class name to each element we wanted to resize, that would give us something to hook onto from the JavaScript.
Example 1: The basic page.
As you can see, I’ve wrapped my items in a DIV and added a class name of chunk to them. It’s these chunks that we’ll be finding with the JavaScript. Speaking of which …
Our Core Functions
There are two main tasks that need performing in our script. The first is to find the chunks we’re going to be resizing and store their original contents away somewhere safe. We’ll need this so that if we trim the text down we’ll know what it was if the user decides they want it back again. We’ll call this loadChunks.
var loadChunks = function(){
var everything = document.getElementsByTagName('*');
var i, l;
chunks = [];
for (i=0, l=everything.length; i<l; i++){
if (everything[i].className.indexOf(chunkClass) > -1){
chunks.push({
ref: everything[i],
original: everything[i].innerHTML
});
}
}
};
The variable chunks is stored outside of this function so that we can access it from our next core function, which is doTrim.
var doTrim = function(interval) {
if (!chunks) loadChunks();
var i, l;
for (i=0, l=chunks.length; i<l; i++){
var a = chunks[i].original.split(' ');
a = a.slice(0, interval);
chunks[i].ref.innerHTML = a.join(' ');
}
};
The first thing that needs to be done is to call loadChunks if the chunks variable isn’t set. This should only happen the first time doTrim is called, as from that point the chunks will be loaded.
Then all we do is loop through the chunks and trim them. The trimming itself (lines 6-8) is very simple. We split the text into an array of words (line 6), then select only a portion from the beginning of the array up until the number we want (line 7). Finally the words are glued back together (line 8).
In essense, that’s it, but it leaves us needing to know how to get the number into this function in the first place, and how that number is generated by the user. Let’s look at the latter case first.
The YUI Slider Widget
There are lots of JavaScript libraries available at the moment. A fair few of those are really good. I use the Yahoo! User Interface Library professionally, but have only recently played with their pre-build slider widget. Turns out, it’s pretty good and perfect for this task.
Once you have the library files linked in (check the docs linked above) it’s fairly straightforward to create yourself a slider.
slider = YAHOO.widget.Slider.getHorizSlider("sliderbg", "sliderthumb", 0, 100, 5);
slider.setValue(50);
slider.subscribe("change", doTrim);
All that’s needed then is some CSS to make the slider look like a slider, and of course a few bits of HTML. We’ll see those later.
See It Working!
Rather than spell out all the nuts and bolts of implementing this fairly simple script, let’s just look at in it action and then pick on some interesting bits I’ve added.
Example 2: Try the Tasty Text Trimmer.
At the top of the JavaScript file I’ve added a small number of settings.
var chunkClass = 'chunk';
var minValue = 10;
var maxValue = 100;
var multiplier = 5;
Obvious candidates for configuration are the class name used to find the chunks, and also the some minimum and maximum values. The minValue is the fewest number of words we wish to display when the slider is all the way down. The maxValue is the length of the slider, in this case 100.
Moving the slider makes a call to our doTrim function with the current value of the slider. For a slider 100 pixels long, this is going to be in the range of 0-100. That might be okay for some things, but for longer items of text you’ll want to allow for displaying more than 100 words. I’ve accounted for this by adding in a multiplier – in my code I’m multiplying the value by 5, so a slider value of 50 shows 250 words. You’ll probably want to tailor the multiplier to the type of content you’re using.
Keeping it Accessible
This effect isn’t something we can really achieve without JavaScript, but even so we must make sure that this functionality has no adverse impact on the page when JavaScript isn’t available. This is achieved by adding the slider markup to the page from within the insertSliderHTML function.
var insertSliderHTML = function(){
var s = '<a id="slider-less" href="#less"><img src="icon_min.gif" width="10" height="10" alt="Less text" class="first" /></a>';
s +=' <div id="sliderbg"><div id="sliderthumb"><img src="sliderthumbimg.gif" /></div></div>';
s +=' <a id="slider-more" href="#more"><img src="icon_max.gif" width="10" height="10" alt="More text" /></a>';
document.getElementById('slider').innerHTML = s;
}
The other important factor to consider is that a slider can be tricky to use unless you have good eyesight and pretty well controlled motor skills. Therefore we should provide a method of changing the value by the keyboard.
I’ve done this by making the icons at either end of the slider links so they can be tabbed to. Clicking on either icon fires the appropriate JavaScript function to show more or less of the text.
In Conclusion
The upshot of all this is that without JavaScript the page just shows all the text as it normally would. With JavaScript we have a slider for trimming the text excepts that can be controlled with the mouse or with a keyboard.
If you’re like me and have just scrolled to the bottom to find the working demo, here it is again:
Try the Tasty Text Trimmer
Trimmer for Christmas? Don’t say I never give you anything! |
2006 |
Drew McLellan |
drewmclellan |
2006-12-01T00:00:00+00:00 |
https://24ways.org/2006/tasty-text-trimmer/ |
code |
135 |
A Scripting Carol |
We all know the stories of the Ghost of Scripting Past – a time when the web was young and littered with nefarious scripting, designed to bestow ultimate control upon the developer, to pollute markup with event handler after event handler, and to entrench advertising in the minds of all that gazed upon her.
And so it came to be that JavaScript became a dirty word, thrown out of solutions by many a Scrooge without regard to the enhancements that JavaScript could bring to any web page. JavaScript, as it was, was dead as a door-nail.
With the arrival of our core philosophy that all standardistas hold to be true: “separate your concerns – content, presentation and behaviour,” we are in a new era of responsible development the Web Standards Way™. Or are we? Have we learned from the Ghosts of Scripting Past? Or are we now faced with new problems that come with new ways of implementing our solutions?
The Ghost of Scripting Past
If the Ghost of Scripting Past were with us it would probably say:
You must remember your roots and where you came from, and realize the misguided nature of your early attempts for control. That person you see down there, is real and they are the reason you exist in the first place… without them, you are nothing.
In many ways we’ve moved beyond the era of control and we do take into account the user, or at least much more so than we used to. Sadly – there is one advantage that old school inline event handlers had where we assigned and reassigned CSS style property values on the fly – we knew that if JavaScript wasn’t supported, the styles wouldn’t be added because we ended up doing them at the same time.
If anything, we need to have learned from the past that just because it works for us doesn’t mean it is going to work for anyone else – we need to test more scenarios than ever to observe the multitude of browsing arrangements we’ll observe: CSS on with JavaScript off, CSS off/overridden with JavaScript on, both on, both off/not supported. It is a situation that is ripe for conflict.
This may shock some of you, but there was a time when testing was actually easier: back in the day when Netscape 4 was king. Yes, that’s right. I actually kind of enjoyed Netscape 4 (hear me out, please). With NS4’s CSS implementation known as JavaScript Style Sheets, you knew that if JavaScript was off the styles were off too.
The Ghost of Scripting Present
With current best practice – we keep our CSS and JavaScript separate from each other. So what happens when some of our fancy, unobtrusive DOM Scripting doesn’t play nicely with our wonderfully defined style rules?
Lets look at one example of a collapsing and expanding menu to illustrate where we are now:
Simple Collapsing/Expanding Menu Example
We’re using some simple JavaScript (I’m using jquery in this case) to toggle between a CSS state for expanded and not expanded:
JavaScript
$(document).ready(function(){
TWOFOURWAYS.enableTree();
});
var TWOFOURWAYS = new Object();
TWOFOURWAYS.enableTree = function ()
{
$("ul li a").toggle(function(){
$(this.parentNode).addClass("expanded");
}, function() {
$(this.parentNode).removeClass("expanded");
});
return false;
}
CSS
ul li ul {
display: none;
}
ul li.expanded ul {
display: block;
}
At this point we’ve separated our presentation from our content and behaviour, and all is well, right?
Not quite.
Here’s where I typically see failures in the assessment work that I do on web sites and applications (Yes, call me Scrooge – I don’t care!). We know our page needs to work with or without scripting, and we know it needs to work with or without CSS. All too often the testing scenarios don’t take into account combinations.
Testing it out
So what happens when we test this? Make sure you test with:
CSS off
JavaScript off
Use the simple example again.
With CSS off, we revert to a simple nested list of links and all functionality is maintained. With JavaScript off, however, we run into a problem – we have now removed the ability to expand the menu using the JavaScript triggered CSS change.
Hopefully you see the problem – we have a JavaScript and CSS dependency that is critical to the functionality of the page. Unobtrusive scripting and binary on/off tests aren’t enough. We need more.
This Ghost of Scripting Present sighting is seen all too often.
Lets examine the JavaScript off scenario a bit further – if we require JavaScript to expand/show the branch of the tree we should use JavaScript to hide them in the first place. That way we guarantee functionality in all scenarios, and have achieved our baseline level of interoperability.
To revise this then, we’ll start with the sub items expanded, use JavaScript to collapse them, and then use the same JavaScript to expand them.
HTML
<ul>
<li><a href="#">Main Item</a>
<ul class="collapseme">
<li><a href="#">Sub item 1</a></li>
<li><a href="#">Sub item 2</a></li>
<li><a href="#">Sub item 3</a></li>
</ul>
</li>
</ul>
CSS
/* initial style is expanded */
ul li ul.collapseme {
display: block;
}
JavaScript
// remove the class collapseme after the page loads
$("ul ul.collapseme").removeClass("collapseme");
And there you have it – a revised example with better interoperability.
This isn’t rocket surgery by any means. It is a simple solution to a ghostly problem that is too easily overlooked (and often is).
The Ghost of Scripting Future
Well, I’m not so sure about this one, but I’m guessing that in a few years’ time, we’ll all have seen a few more apparitions and have a few more tales to tell. And hopefully we’ll be able to share them on 24 ways.
Thanks to Drew for the invitation to contribute and thanks to everyone else out there for making this a great (and haunting) year on the web! |
2006 |
Derek Featherstone |
derekfeatherstone |
2006-12-21T00:00:00+00:00 |
https://24ways.org/2006/a-scripting-carol/ |
code |
136 |
Making XML Beautiful Again: Introducing Client-Side XSL |
Remember that first time you saw XML and got it? When you really understood what was possible and the deep meaning each element could carry? Now when you see XML, it looks ugly, especially when you navigate to a page of XML in a browser. Well, with every modern browser now supporting XSL 1.0, I’m going to show you how you can turn something as simple as an ATOM feed into a customised page using a browser, Notepad and some XSL.
What on earth is this XSL?
XSL is a family of recommendations for defining XML document transformation and presentation. It consists of three parts:
XSLT 1.0 – Extensible Stylesheet Language Transformation, a language for transforming XML
XPath 1.0 – XML Path Language, an expression language used by XSLT to access or refer to parts of an XML document. (XPath is also used by the XML Linking specification)
XSL-FO 1.0 – Extensible Stylesheet Language Formatting Objects, an XML vocabulary for specifying formatting semantics
XSL transformations are usually a one-to-one transformation, but with newer versions (XSL 1.1 and XSL 2.0) its possible to create many-to-many transformations too. So now you have an overview of XSL, on with the show…
So what do I need?
So to get going you need a browser an supports client-side XSL transformations such as Firefox, Safari, Opera or Internet Explorer. Second, you need a source XML file – for this we’re going to use an ATOM feed from Flickr.com. And lastly, you need an editor of some kind. I find Notepad++ quick for short XSLs, while I tend to use XMLSpy or Oxygen for complex XSL work.
Because we’re doing a client-side transformation, we need to modify the XML file to tell it where to find our yet-to-be-written XSL file. Take a look at the source XML file, which originates from my Flickr photos tagged sky, in ATOM format.
The top of the ATOM file now has an additional <?xml-stylesheet /> instruction, as can been seen on Line 2 below. This instructs the browser to use the XSL file to transform the document.
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<?xml-stylesheet type="text/xsl" href="flickr_transform.xsl"?>
<feed xmlns="http://www.w3.org/2005/Atom"
xmlns:dc="http://purl.org/dc/elements/1.1/">
Your first transformation
Your first XSL will look something like this:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:atom="http://www.w3.org/2005/Atom"
xmlns:dc="http://purl.org/dc/elements/1.1/">
<xsl:output method="html" encoding="utf-8"/>
</xsl:stylesheet>
This is pretty much the starting point for most XSL files. You will notice the standard XML processing instruction at the top of the file (line 1). We then switch into XSL mode using the XSL namespace on all XSL elements (line 2). In this case, we have added namespaces for ATOM (line 4) and Dublin Core (line 5). This means the XSL can now read and understand those elements from the source XML.
After we define all the namespaces, we then move onto the xsl:output element (line 6). This enables you to define the final method of output. Here we’re specifying html, but you could equally use XML or Text, for example. The encoding attributes on each element do what they say on the tin. As with all XML, of course, we close every element including the root.
The next stage is to add a template, in this case an <xsl:template /> as can be seen below:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:atom="http://www.w3.org/2005/Atom"
xmlns:dc="http://purl.org/dc/elements/1.1/">
<xsl:output method="html" encoding="utf-8"/>
<xsl:template match="/">
<html>
<head>
<title>Making XML beautiful again : Transforming ATOM</title>
</head>
<body>
<xsl:apply-templates select="/atom:feed"/>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
The beautiful thing about XSL is its English syntax, if you say it out loud it tends to make sense.
The / value for the match attribute on line 8 is our first example of XPath syntax. The expression / matches any element – so this <xsl:template/> will match against any element in the document. As the first element in any XML document is the root element, this will be the one matched and processed first.
Once we get past our standard start of a HTML document, the only instruction remaining in this <xsl:template/> is to look for and match all <atom:feed/> elements using the <xsl:apply-templates/> in line 14, above.
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:atom="http://www.w3.org/2005/Atom"
xmlns:dc="http://purl.org/dc/elements/1.1/">
<xsl:output method="html" encoding="utf-8"/>
<xsl:template match="/">
<xsl:apply-templates select="/atom:feed"/>
</xsl:template>
<xsl:template match="/atom:feed">
<div id="content">
<h1>
<xsl:value-of select="atom:title"/>
</h1>
<p>
<xsl:value-of select="atom:subtitle"/>
</p>
<ul id="entries">
<xsl:apply-templates select="atom:entry"/>
</ul>
</div>
</xsl:template>
</xsl:stylesheet>
This new template (line 12, above) matches <feed/> and starts to write the new HTML elements out to the output stream. The <xsl:value-of/> does exactly what you’d expect – it finds the value of the item specifed in its select attribute. With XPath you can select any element or attribute from the source XML.
The last part is a repeat of the now familiar <xsl:apply-templates/> from before, but this time we’re using it inside of a called template. Yep, XSL is full of recursion…
<xsl:template match="atom:entry">
<li class="entry">
<h2>
<a href="{atom:link/@href}">
<xsl:value-of select="atom:title"/>
</a>
</h2>
<p class="date">
(<xsl:value-of select="substring-before(atom:updated,'T')"/>)
</p>
<p class="content">
<xsl:value-of select="atom:content" disable-output-escaping="yes"/>
</p>
<xsl:apply-templates select="atom:category"/>
</li>
</xsl:template>
The <xsl:template/> which matches atom:entry (line 1) occurs every time there is a <entry/> element in the source XML file. So in total that is 20 times, this is naturally why XSLT is full of recursion. This <xsl:template/> has been matched and therefore called higher up in the document, so we can start writing list elements directly to the output stream. The first part is simply a <h2/> with a link wrapped within it (lines 3-7). We can select attributes using XPath using @.
The second part of this template selects the date, but performs a XPath string function on it. This means that we only get the date and not the time from the string (line 9). This is achieved by getting only the part of the string that exists before the T.
Regular Expressions are not part of the XPath 1.0 string functions, although XPath 2.0 does include them. Because of this, in XSL we tend to rely heavily on the available XML output.
The third part of the template (line 12) is a <xsl:value-of/> again, but this time we use an attribute of <xsl:value-of/> called disable output escaping to turn escaped characters back into XML.
The very last section is another <xsl:apply-template/> call, taking us three templates deep. Do not worry, it is not uncommon to write XSL which go 20 or more templates deep!
<xsl:template match="atom:category">
<xsl:for-each select=".">
<xsl:element name="a">
<xsl:attribute name="rel">
<xsl:text>tag</xsl:text>
</xsl:attribute>
<xsl:attribute name="href">
<xsl:value-of select="concat(@scheme, @term)"/>
</xsl:attribute>
<xsl:value-of select="@term"/>
</xsl:element>
<xsl:text> </xsl:text>
</xsl:for-each>
</xsl:template>
In our final <xsl:template/>, we see a combination of what we have done before with a couple of twists. Once we match atom:category we then count how many elements there are at that same level (line 2). The XPath . means ‘self’, so we count how many category elements are within the <entry/> element.
Following that, we start to output a link with a rel attribute of the predefined text, tag (lines 4-6). In XSL you can just type text, but results can end up with strange whitespace if you do (although there are ways to simply remove all whitespace).
The only new XPath function in this example is concat(), which simply combines what XPaths or text there might be in the brackets. We end the output for this tag with an actual tag name (line 10) and we add a space afterwards (line 12) so it won’t touch the next tag. (There are better ways to do this in XSL using the last() XPath function).
After that, we go back to the <xsl:for-each/> element again if there is another category element, otherwise we end the <xsl:for-each/> loop and end this <xsl:template/>.
A touch of style
Because we’re using recursion through our templates, you will find this is the end of the templates and the rest of the XML will be ignored by the parser. Finally, we can add our CSS to finish up. (I have created one for Flickr and another for News feeds)
<style type="text/css" media="screen">@import "flickr_overview.css?v=001";</style>
So we end up with a nice simple to understand but also quick to write XSL which can be used on ATOM Flickr feeds and ATOM News feeds. With a little playing around with XSL, you can make XML beautiful again.
All the files can be found in the zip file (14k) |
2006 |
Ian Forrester |
ianforrester |
2006-12-07T00:00:00+00:00 |
https://24ways.org/2006/beautiful-xml-with-xsl/ |
code |
138 |
Rounded Corner Boxes the CSS3 Way |
If you’ve been doing CSS for a while you’ll know that there are approximately 3,762 ways to create a rounded corner box. The simplest techniques rely on the addition of extra mark-up directly to your page, while the more complicated ones add the mark-up though DOM manipulation. While these techniques are all very interesting, they do seem somewhat of a kludge. The goal of CSS is to separate structure from presentation, yet here we are adding superfluous mark-up to our code in order to create a visual effect. The reason we are doing this is simple. CSS2.1 only allows a single background image per element.
Thankfully this looks set to change with the addition of multiple background images into the CSS3 specification. With CSS3 you’ll be able to add not one, not four, but eight background images to a single element. This means you’ll be able to create all kinds of interesting effects without the need of those additional elements.
While the CSS working group still seem to be arguing over the exact syntax, Dave Hyatt went ahead and implemented the currently suggested mechanism into Safari. The technique is fiendishly simple, and I think we’ll all be a lot better off once the W3C stop arguing over the details and allow browser vendors to get on and provide the tools we need to build better websites.
To create a CSS3 rounded corner box, simply start with your box element and apply your 4 corner images, separated by commas.
.box {
background-image: url(top-left.gif), url(top-right.gif), url(bottom-left.gif), url(bottom-right.gif);
}
We don’t want these background images to repeat, which is the normal behaviour, so lets set all their background-repeat properties to no-repeat.
.box {
background-image: url(top-left.gif), url(top-right.gif), url(bottom-left.gif), url(bottom-right.gif);
background-repeat: no-repeat, no-repeat, no-repeat, no-repeat;
}
Lastly, we need to define the positioning of each corner image.
.box {
background-image: url(top-left.gif), url(top-right.gif), url(bottom-left.gif), url(bottom-right.gif);
background-repeat: no-repeat, no-repeat, no-repeat, no-repeat;
background-position: top left, top right, bottom left, bottom right;
}
And there we have it, a simple rounded corner box with no additional mark-up.
As well as using multiple background images, CSS3 also has the ability to create rounded corners without the need of any images at all. You can do this by setting the border-radius property to your desired value as seen in the next example.
.box {
border-radius: 1.6em;
}
This technique currently works in Firefox/Camino and creates a nice, if somewhat jagged rounded corner. If you want to create a box that works in both Mozilla and WebKit based browsers, why not combine both techniques and see what happens. |
2006 |
Andy Budd |
andybudd |
2006-12-04T00:00:00+00:00 |
https://24ways.org/2006/rounded-corner-boxes-the-css3-way/ |
code |
139 |
Flickr Photos On Demand with getFlickr |
In case you don’t know it yet, Flickr is great. It is a lot of fun to upload, tag and caption photos and it is really handy to get a vast network of contacts through it.
Using Flickr photos outside of it is a bit of a problem though. There is a Flickr API, and you can get almost every page as an RSS feed, but in general it is a bit tricky to use Flickr photos inside your blog posts or web sites. You might not want to get into the whole API game or use a server side proxy script as you cannot retrieve RSS with Ajax because of the cross-domain security settings.
However, Flickr also provides an undocumented JSON output, that can be used to hack your own solutions in JavaScript without having to use a server side script.
If you enter the URL http://flickr.com/photos/tags/panda you get to the flickr page with photos tagged “panda”.
If you enter the URL http://api.flickr.com/services/feeds/photos_public.gne?tags=panda&format=rss_200 you get the same page as an RSS feed.
If you enter the URL http://api.flickr.com/services/feeds/photos_public.gne?tags=panda&format=json you get a JavaScript function called jsonFlickrFeed with a parameter that contains the same data in JSON format
You can use this to easily hack together your own output by just providing a function with the same name. I wanted to make it easier for you, which is why I created the helper getFlickr for you to download and use.
getFlickr for Non-Scripters
Simply include the javascript file getflickr.js and the style getflickr.css in the head of your document:
<script type="text/javascript" src="getflickr.js"></script>
<link rel="stylesheet" href="getflickr.css" type="text/css">
Once this is done you can add links to Flickr pages anywhere in your document, and when you give them the CSS class getflickrphotos they get turned into gallery links. When a visitor clicks these links they turn into loading messages and show a “popup” gallery with the connected photos once they were loaded. As the JSON returned is very small it won’t take long. You can close the gallery, or click any of the thumbnails to view a photo. Clicking the photo makes it disappear and go back to the thumbnails.
Check out the example page and click the different gallery links to see the results.
Notice that getFlickr works with Unobtrusive JavaScript as when scripting is disabled the links still get to the photos on Flickr.
getFlickr for JavaScript Hackers
If you want to use getFlickr with your own JavaScripts you can use its main method leech():
getFlickr.leech(sTag, sCallback);
sTag
the tag you are looking for
sCallback
an optional function to call when the data was retrieved.
After you called the leech() method you have two strings to use:
getFlickr.html[sTag]
contains an HTML list (without the outer UL element) of all the images linked to the correct pages at flickr. The images are the medium size, you can easily change that by replacing _m.jpg with _s.jpg for thumbnails.
getFlickr.tags[sTag]
contains a string of all the other tags flickr users added with the tag you searched for(space separated)
You can call getFlickr.leech() several times when the page has loaded to cache several result feeds before the page gets loaded. This’ll make the photos quicker for the end user to show up. If you want to offer a form for people to search for flickr photos and display them immediately you can use the following HTML:
<form onsubmit="getFlickr.leech(document.getElementById('tag').value, 'populate');return false">
<label for="tag">Enter Tag</label>
<input type="text" id="tag" name="tag" />
<input type="submit" value="energize" />
<h3>Tags:</h3><div id="tags"></div>
<h3>Photos:</h3><ul id="photos"></ul>
</form>
All the JavaScript you’ll need (for a basic display) is this:
function populate(){
var tag = document.getElementById('tag').value;
document.getElementById('photos').innerHTML = getFlickr.html[tag].replace(/_m\.jpg/g,'_s.jpg');
document.getElementById('tags').innerHTML = getFlickr.tags[tag];
return false;
}
Easy as pie, enjoy!
Check out the example page and try the form to see the results. |
2006 |
Christian Heilmann |
chrisheilmann |
2006-12-03T00:00:00+00:00 |
https://24ways.org/2006/flickr-photos-on-demand/ |
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 |
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 |
147 |
Christmas Is In The AIR |
That’s right, Christmas is coming up fast and there’s plenty of things to do. Get the tree and lights up, get the turkey, buy presents and who know what else. And what about Santa? He’s got a list. I’m pretty sure he’s checking it twice.
Sure, we could use an existing list making web site or even a desktop widget. But we’re geeks! What’s the fun in that? Let’s build our own to-do list application and do it with Adobe AIR!
What’s Adobe AIR?
Adobe AIR, formerly codenamed Apollo, is a runtime environment that runs on both Windows and OSX (with Linux support to follow). This runtime environment lets you build desktop applications using Adobe technologies like Flash and Flex. Oh, and HTML. That’s right, you web standards lovin’ maniac. You can build desktop applications that can run cross-platform using the trio of technologies, HTML, CSS and JavaScript.
If you’ve tried developing with AIR before, you’ll need to get re-familiarized with the latest beta release as many things have changed since the last one (such as the API and restrictions within the sandbox.)
To get started
To get started in building an AIR application, you’ll need two basic things:
The AIR runtime. The runtime is needed to run any AIR-based application.
The SDK. The software development kit gives you all the pieces to test your application. Unzip the SDK into any folder you wish.
You’ll also want to get your hands on the JavaScript API documentation which you’ll no doubt find yourself getting into before too long. (You can download it, too.)
Also of interest, some development environments have support for AIR built right in. Aptana doesn’t have support for beta 3 yet but I suspect it’ll be available shortly.
Within the SDK, there are two main tools that we’ll use: one to test the application (ADL) and another to build a distributable package of our application (ADT). I’ll get into this some more when we get to that stage of development.
Building our To-do list application
The first step to building an application within AIR is to create an XML file that defines our default application settings. I call mine application.xml, mostly because Aptana does that by default when creating a new AIR project. It makes sense though and I’ve stuck with it. Included in the templates folder of the SDK is an example XML file that you can use.
The first key part to this after specifying things like the application ID, version, and filename, is to specify what the default content should be within the content tags. Enter in the name of the HTML file you wish to load. Within this HTML file will be our application.
<content>ui.html</content>
Create a new HTML document and name it ui.html and place it in the same directory as the application.xml file. The first thing you’ll want to do is copy over the AIRAliases.js file from the frameworks folder of the SDK and add a link to it within your HTML document.
<script type="text/javascript" src="AIRAliases.js"></script>
The aliases create shorthand links to all of the Flash-based APIs.
Now is probably a good time to explain how to debug your application.
Debugging our application
So, with our XML file created and HTML file started, let’s try testing our ‘application’. We’ll need the ADL application located in BIN folder of the SDK and tell it to run the application.xml file.
/path/to/adl /path/to/application.xml
You can also just drag the XML file onto ADL and it’ll accomplish the same thing. If you just did that and noticed that your blank application didn’t load, you’d be correct. It’s running but isn’t visible. Which at this point means you’ll have to shut down the ADL process. Sorry about that!
Changing the visibility
You have two ways to make your application visible. You can do it automatically by setting the placing true in the visible tag within the application.xml file.
<visible>true</visible>
The other way is to do it programmatically from within your application. You’d want to do it this way if you had other startup tasks to perform before showing the interface. To turn the UI on programmatically, simple set the visible property of nativeWindow to true.
<script type="text/javascript">
nativeWindow.visible = true;
</script>
Sandbox Security
Now that we have an application that we can see when we start it, it’s time to build the to-do list application. In doing so, you’d probably think that using a JavaScript library is a really good idea — and it can be but there are some limitations within AIR that have to be considered.
An HTML document, by default, runs within the application sandbox. You have full access to the AIR APIs but once the onload event of the window has fired, you’ll have a limited ability to make use of eval and other dynamic script injection approaches. This limits the ability of external sources from gaining access to everything the AIR API offers, such as database and local file system access. You’ll still be able to make use of eval for evaluating JSON responses, which is probably the most important if you wish to consume JSON-based services.
If you wish to create a greater wall of security between AIR and your HTML document loading in external resources, you can create a child sandbox. We won’t need to worry about it for our application so I won’t go any further into it but definitely keep this in mind.
Finally, our application
Getting tired of all this preamble? Let’s actually build our to-do list application. I’ll use jQuery because it’s small and should suit our needs nicely. Let’s begin with some structure:
<body>
<input type="text" id="text" value="">
<input type="button" id="add" value="Add">
<ul id="list"></ul>
</body>
Now we need to wire up that button to actually add a new item to our to-do list.
<script type="text/javascript">
$(document).ready(function(){
// make sure the application is visible
nativeWindow.visible = true;
$('#add').click(function(){
var t = $('#text').val();
if(t)
{
// use DOM methods to create the new list item
var li = document.createElement('li');
// the extra space at the end creates a buffer between the text
// and the delete link we're about to add
li.appendChild(document.createTextNode(t + ' '));
// create the delete link
var del = document.createElement('a');
// this makes it a true link. I feel dirty doing this.
del.setAttribute('href', '#');
del.addEventListener('click', function(evt){
this.parentNode.parentNode.removeChild(this.parentNode);
});
del.appendChild(document.createTextNode('[del]'));
li.appendChild(del);
// append everything to the list
$('#list').append(li);
//reset the text box
$('#text').val('');
}
})
});
</script>
And just like that, we’ve got a to-do list! That’s it! Just never close your application and you’ll remember everything. Okay, that’s not very practical. You need to have some way of storing your to-do items until the next time you open up the application.
Storing Data
You’ve essentially got 4 different ways that you can store data:
Using the local database. AIR comes with SQLLite built in. That means you can create tables and insert, update and select data from that database just like on a web server.
Using the file system. You can also create files on the local machine. You have access to a few folders on the local system such as the documents folder and the desktop.
Using EcryptedLocalStore. I like using the EcryptedLocalStore because it allows you to easily save key/value pairs and have that information encrypted. All this within just a couple lines of code.
Sending the data to a remote API. Our to-do list could sync up with Remember the Milk, for example.
To demonstrate some persistence, we’ll use the file system to store our files. In addition, we’ll let the user specify where the file should be saved. This way, we can create multiple to-do lists, keeping them separate and organized.
The application is now broken down into 4 basic tasks:
Load data from the file system.
Perform any interface bindings.
Manage creating and deleting items from the list.
Save any changes to the list back to the file system.
Loading in data from the file system
When the application starts up, we’ll prompt the user to select a file or specify a new to-do list. Within AIR, there are 3 main file objects: File, FileMode, and FileStream. File handles file and path names, FileMode is used as a parameter for the FileStream to specify whether the file should be read-only or for write access. The FileStream object handles all the read/write activity.
The File object has a number of shortcuts to default paths like the documents folder, the desktop, or even the application store. In this case, we’ll specify the documents folder as the default location and then use the browseForSave method to prompt the user to specify a new or existing file. If the user specifies an existing file, they’ll be asked whether they want to overwrite it.
var store = air.File.documentsDirectory;
var fileStream = new air.FileStream();
store.browseForSave("Choose To-do List");
Then we add an event listener for when the user has selected a file. When the file is selected, we check to see if the file exists and if it does, read in the contents, splitting the file on new lines and creating our list items within the interface.
store.addEventListener(air.Event.SELECT, fileSelected);
function fileSelected()
{
air.trace(store.nativePath);
// load in any stored data
var byteData = new air.ByteArray();
if(store.exists)
{
fileStream.open(store, air.FileMode.READ);
fileStream.readBytes(byteData, 0, store.size);
fileStream.close();
if(byteData.length > 0)
{
var s = byteData.readUTFBytes(byteData.length);
oldlist = s.split(“\r\n”);
// create todolist items
for(var i=0; i < oldlist.length; i++)
{
createItem(oldlist[i], (new Date()).getTime() + i );
}
}
}
}
Perform Interface Bindings
This is similar to before where we set the click event on the Add button but we’ve moved the code to save the list into a separate function.
$('#add').click(function(){
var t = $('#text').val();
if(t){
// create an ID using the time
createItem(t, (new Date()).getTime() );
}
})
Manage creating and deleting items from the list
The list management is now in its own function, similar to before but with some extra information to identify list items and with calls to save our list after each change.
function createItem(t, id)
{
if(t.length == 0) return;
// add it to the todo list
todolist[id] = t;
// use DOM methods to create the new list item
var li = document.createElement('li');
// the extra space at the end creates a buffer between the text
// and the delete link we're about to add
li.appendChild(document.createTextNode(t + ' '));
// create the delete link
var del = document.createElement('a');
// this makes it a true link. I feel dirty doing this.
del.setAttribute('href', '#');
del.addEventListener('click', function(evt){
var id = this.id.substr(1);
delete todolist[id]; // remove the item from the list
this.parentNode.parentNode.removeChild(this.parentNode);
saveList();
});
del.appendChild(document.createTextNode('[del]'));
del.id = 'd' + id;
li.appendChild(del);
// append everything to the list
$('#list').append(li);
//reset the text box
$('#text').val('');
saveList();
}
Save changes to the file system
Any time a change is made to the list, we update the file. The file will always reflect the current state of the list and we’ll never have to click a save button. It just iterates through the list, adding a new line to each one.
function saveList(){
if(store.isDirectory) return;
var packet = '';
for(var i in todolist)
{
packet += todolist[i] + '\r\n';
}
var bytes = new air.ByteArray();
bytes.writeUTFBytes(packet);
fileStream.open(store, air.FileMode.WRITE);
fileStream.writeBytes(bytes, 0, bytes.length);
fileStream.close();
}
One important thing to mention here is that we check if the store is a directory first. The reason we do this goes back to our browseForSave call. If the user cancels the dialog without selecting a file first, then the store points to the documentsDirectory that we set it to initially. Since we haven’t specified a file, there’s no place to save the list.
Hopefully by this point, you’ve been thinking of some cool ways to pimp out your list. Now we need to package this up so that we can let other people use it, too.
Creating a Package
Now that we’ve created our application, we need to package it up so that we can distribute it. This is a two step process. The first step is to create a code signing certificate (or you can pay for one from Thawte which will help authenticate you as an AIR application developer).
To create a self-signed certificate, run the following command. This will create a PFX file that you’ll use to sign your application.
adt -certificate -cn todo24ways 1024-RSA todo24ways.pfx mypassword
After you’ve done that, you’ll need to create the package with the certificate
adt -package -storetype pkcs12 -keystore todo24ways.pfx todo24ways.air application.xml .
The important part to mention here is the period at the end of the command. We’re telling it to package up all files in the current directory.
After that, just run the AIR file, which will install your application and run it.
Important things to remember about AIR
When developing an HTML application, the rendering engine is Webkit. You’ll thank your lucky stars that you aren’t struggling with cross-browser issues. (My personal favourites are multiple backgrounds and border radius!)
Be mindful of memory leaks. Things like Ajax calls and event binding can cause applications to slowly leak memory over time. Web pages are normally short lived but desktop applications are often open for hours, if not days, and you may find your little desktop application taking up more memory than anything else on your machine!
The WebKit runtime itself can also be a memory hog, usually taking about 15MB just for itself. If you create multiple HTML windows, it’ll add another 15MB to your memory footprint. Our little to-do list application shouldn’t be much of a concern, though.
The other important thing to remember is that you’re still essentially running within a Flash environment. While you probably won’t notice this working in small applications, the moment you need to move to multiple windows or need to accomplish stuff beyond what HTML and JavaScript can give you, the need to understand some of the Flash-based elements will become more important.
Lastly, the other thing to remember is that HTML links will load within the AIR application. If you want a link to open in the users web browser, you’ll need to capture that event and handle it on your own. The following code takes the HREF from a clicked link and opens it in the default web browser.
air.navigateToURL(new air.URLRequest(this.href));
Only the beginning
Of course, this is only the beginning of what you can do with Adobe AIR. You don’t have the same level of control as building a native desktop application, such as being able to launch other applications, but you do have more control than what you could have within a web application. Check out the Adobe AIR Developer Center for HTML and Ajax for tutorials and other resources.
Now, go forth and create your desktop applications and hopefully you finish all your shopping before Christmas!
Download the example files. |
2007 |
Jonathan Snook |
jonathansnook |
2007-12-19T00:00:00+00:00 |
https://24ways.org/2007/christmas-is-in-the-air/ |
code |