Category Archives: {categories backspace="2" show_group="3"}<a href="/topic/{category_url_title}">{category_name}</a>, {/categories}

What Really Matters: Focusing on Top Tasks

Posted by The fine folks at A List Apart |21 Apr 15 |

Digital is a space of endless replication. It has never been easier to create—and create, and create. People love to publish, but they hate to remove, which leads to overloaded websites and constant, inevitable redesigns. The top layers get a shiny new coat of graphics and meaningless “we really care” content—but underneath, a teeming mass of out-of-date, badly organized information still swirls about.

The solution is to make hard choices using Top Tasks Management. Top tasks are the small set of tasks (usually less than 10, often less than five) that matter most to your customers. Make these tasks work well, and you’ll be on the right track. Get them wrong, and chances are you’ll lose the customer.

Top Tasks Management is a model that says: “Focus on what really matters (the top tasks) and defocus on what matters less (the tiny tasks).”

Tiny tasks are a nightmare for web teams. On their own, these tasks seem innocent enough. It’s just one more page, one more link, one more graphic. But gather them up, and many a web professional has found themselves nibbled to death.

Tiny tasks are also full of organizational ego. Often, the more important the task is to the customer, the less content is being produced for it; the less important the task is to the customer, the more content is being produced. This inverse relationship is very typical.

Identifying top tasks

The purpose of Top Tasks Management is to reduce complexity by identifying what really matters to customers. The following steps are involved in a task identification process:

  1. Comprehensively engage the organization in a process of gathering customer tasks.
  2. Work with key stakeholders to come up with a shortlist of these tasks.
  3. Get a representative sample of customers to vote.
  4. Create a league table of tasks from the one with the highest vote to the one with the lowest vote.

Step 1: Gathering the longlist of potential tasks

Use the process of gathering tasks to get outside of organization thinking and inside the customers’ mind and world. Actively engage the key stakeholders in this process. It can be a great way to get the whole organization thinking about what the customer wants to do, rather than what the organization wants the customer to do.

When gathering the list of customer tasks, use as much data as possible. Here are some common data sources for customer tasks:

  • Corporate philosophy: Strategy, mission and vision, and corporate objectives.
  • Customer feedback: Survey results, frequent help requests, insight from support or service teams.
  • Stakeholder reviews: Interview key stakeholders and ask them what they consider top customer tasks.
  • Competitor or peer websites: Review competitor or peer websites and see what sorts of tasks are cropping up.
  • Traditional and social media: What sorts of tasks are being mentioned by customers on social media? Are there specialist traditional media that cover your industry?
  • Site behavior analysis: Most visited pages, most popular downloads.
  • Search analysis: Top search terms on the website, as well as Google public search behavior for your industry.

Why go to all this bother? Why not just depend on the numbers for your most visited pages and top search terms? The truth is that these can be unreliable metrics:

  1. Page visits reflect what you have, not necessarily what customers want. There may be tasks that you don’t have content for—so it’s unlikely they will show up in search and site data. And analyses of page views often reflect an amalgam of tasks; it’s hard to separate the top tasks on these pages from the tiny tasks.
  2. Search is a window into customer behavior, but it doesn’t tell the whole story. For example, when we worked on the BBC intranet, we found they had a feature called “Top Searches” on their homepage. The problem was that once they published the top searches list, these terms no longer needed to be searched for, so in time a new list of top searches emerged! Similarly, top tasks tend to get bookmarked, so they don’t show up as much in search. And the better the navigation, the more likely the site search is to reflect tiny tasks.

Cisco recently undertook a project using Top Tasks Management. When we completed their research, we had over 600 tasks. (In a typical project, we tend to gather between 300 and 500.) Here is a small sample of what the initial tasks looked like for Cisco:

  • Add a network diagram
  • Annual reports
  • Attendant console
  • Benefits of product
  • Network engineer blogs
  • US forums and communities
  • Bug toolkit
  • Bugs, debugging
  • Certifications
  • Cisco MeetingPlace
  • Collaboration
  • Get pricing
  • How to configure
  • Discussion forums
  • Technical forums
  • Support community
  • RV082 installation
  • Network Magic
  • Self-service

There were duplicates, areas of overlap, branding words, and internal jargon. It needed a lot of cleaning up!

Step 2: Getting to a shortlist of tasks

The next step is to bring the longlist of tasks down to a shortlist of no more than 100. Getting a feel for the tasks takes time, which is why we recommend planning on four to six weeks to do the task research and get to the shortlist. Here are some guidelines for shortening your list:

  1. Don’t use brands, jargon, tools, or formats. Get to the essence of what the thing helps the customer do. Avoid specialized or vague phrases like “MeetingPlace,” “Network Magic,” or “Videos.” What is the essence of the task? Is it Pricing, Configuration, Troubleshooting, Training?
  2. Avoid product names or groups. Instead of “RV082 installation,” use “Installation,” as that covers all products. Don’t use “Collaboration” or “TelePresence,” as these are product groups.
  3. Eliminate overlap. “Bug toolkit” and “Bugs, debugging” are essentially the same thing, so you can bring them together into one task. There’s also a lot of overlap between “Technical forums,” “Support community,” “Forums and communities.” We probably only need one task here.
  4. Avoid lofty concepts and goals. A goal is wanting to spend more time with your family, but a web task is booking a vacation. All of the tasks on the list should be roughly at the same level. What do “Self-service” and “Knowledge Base” actually mean?
  5. Ignore audiences and demographics. Keep tasks universal. We don’t want “Network engineer blogs” or “US forums and communities.”
  6. Avoid verbs. The noun is the task. Only use verbs when they’re essential. The list becomes very difficult to scan when so many tasks begin with “find,” “get,” etc. We don’t need “Get Pricing”; the word “Pricing” is fine.
  7. Avoid phrase repetition. Try not to have more than four tasks in your final list begin with the same word. In the longlist, we had lots of tasks beginning with “Cisco.” In the final shortlist, we only used “Cisco” where we felt it was absolutely essential.
  8. Be concise. Use a maximum of seven words or 55 characters for any particular task.

Your tasks might also include subtasks in parentheses. Subtasks should not be exhaustive—typically just two or three examples—and we do not use “etc.” at the end (or else every task would have it).

At the end of the process with Cisco, they agreed on 67 tasks that reflected what customers wanted to do. It was the first time this organizational consensus had ever occurred. Here’s a sample of the list:

  • Troubleshooting (bug fixes, diagnostics, guides)
  • Blogs
  • Calculate return on investment (ROI)
  • Check product or service availability (lead times, back order, in stock, in my region)
  • Compare Cisco products, services and solutions to each other
  • Customer / user reviews and ratings
  • Download software, firmware, drivers, patches, updates
  • Follow Cisco on Twitter, Facebook, YouTube
  • Network design (tech guides, notes, examples)
  • Pricing for an individual product or service
  • Training (courses, calendar, locations)
  • Troubleshooting (bug fixes, diagnostics, guides)

Notice that we did include “Blogs,” despite our rule against including formats. Sometimes we leave in a word or phrase just to prove that it will not get a big vote. If there’s a buzzword that is all the rage internally, consider leaving it on the list just to see how customers react.

By far the most important part of the shortlisting process is involving as many key stakeholders as possible. We brought together people from Cisco’s marketing, support, communications, product, and other teams. It was a hugely enlightening process for everyone involved. They began to understand where there was overlap, and how they would need to collaborate on content and navigation.

Step 3: Getting customers to vote

The third step is to have customers weigh in on the shortlist. We usually send out a survey and ask each person to rank five tasks, giving 5 to the most important, 4 to the next-most important, and so on:

A screenshot of a long survey, showing instructions, a list of 67 tasks, and spaces to rank the tasks.

That’s a joke, right? Nobody would do that. It breaks all the rules of psychology and survey design. It’s simply not possible. Yet in the last 10 years, we have done over 400 similar surveys with close to 400,000 people voting. It’s crazy, but it works.

The voting survey needs to be designed this way because:

  1. We want to find out what really matters to people—what they do versus what they say they do. The very length and overload of the survey forces the gut instinct to kick in. You don’t “read” the list; rather, the tasks that really matter to you jump out.
  2. The core deliverable of the survey is a league table of tasks. You get to know not just the top tasks, but also the tiny tasks, and how each task ranks in relation to other tasks. It gives you a hierarchy of importance that will allow you to make design and content decisions—what to prioritize, what not to prioritize.

Step 4: Analyzing the results

Cisco is a complex world. The 67 tasks in the final task list were all seen as top tasks. They had been edited down from a list of more than 600. And yet, when the votes were counted, here’s what happened:

A pie chart divided into 67 unequal pieces, showing that three tasks take up a quarter of the chart and the bottom 44 tasks take up another quarter.

Three tasks got the first 25 percent of the vote. Six tasks got from 25–50 percent of the vote, 14 tasks got from 50–75 percent of the vote, and 44 tasks got from 75–100 percent. Yes, three tasks got as much of the vote as the bottom 44. In fact, the top task (“Download software”) got as much of the vote as the bottom 23 tasks.

We have done this process over 400 times and the same patterns emerge every single time.

This is Cisco’s league table of the top 20 tasks:

A table displaying the same data as the pie chart, but showing only the top 20 tasks and their percentage of the total vote.

The top task (“Download software”) got 2,408 votes out of a total of 26,160 votes cast, representing 9.2 percent of the overall vote.

Here are the tasks at the bottom of the vote:

A table displaying the same data as the pie chart, but showing only the bottom 20 tasks and their percentage of the total vote.

The bottom task (“Financing, leasing options”) got 29 votes. This is not to say that financing and leasing are unimportant; it’s just that people don’t go to Cisco.com for them. Also, notice how “Blogs” got just 76 votes out of 26,160 cast. People don’t care about the format. They care about the task of installing the RV082 router, for example. If they find a blog post about how best to install the RV082, then, sure, they’ll read that.

Using the results

The benefits of such an evidence-based, collaborative approach are worth the effort. For example, in 2010, downloading a typical piece of software could take 15 convoluted steps and an average of 280 seconds. Now, much of the software can be downloaded in four steps and an average of 45 seconds. Success rates have improved for many tasks by as much as 30 percent.

Every six months, Cisco does a formal test of its top tasks, giving real customers real examples of top tasks and measuring success rates and time on task. These “Task Performance Indicators” have become Key Performance Indicators for the Cisco web team.

Another key outcome of Top Tasks Management is a more collaborative work environment, where people come together to manage a task, rather than just manage a website or an app or publish content for a particular department. Cisco has embraced this approach; the Marketing and Support divisions are in regular contact, and employees from IT, usability, content, and experience design work closely and coordinate their efforts.

The essence of a great customer experience is to help people quickly and easily complete their tasks—but to do that, you need evidence of those tasks, not opinions. Top Tasks Management gives you the data to focus on what really matters: removing (or at least deemphasizing) a whole plethora of tiny tasks, and improving the small set of top tasks that your customers really want.

Let Links Be Links

Posted by The fine folks at A List Apart |31 Mar 15 |

The concept of the web as an application platform has never been more popular, but the tools used to create these so-called “web apps” are still fraught with pitfalls that are often ignored or misunderstood. Single-page web app frameworks have gained traction because they can easily be used to create fast, complex applications that feel much more solid and interactive than traditional websites. But this benefit, and the changes in mindset and development practices that accompany it, comes at the cost of basic browser functionality that web developers sometimes take for granted.

JavaScript can be fragile

With vendors making it increasingly difficult to disable, we can get lulled into thinking that we don’t need to provide a fallback for users whose browsers don’t execute JavaScript. But explicitly choosing to disable JavaScript is far from the only reason a user’s browser might not run it. Government Digital Service (GDS), the team that maintains the UK government website, found that, out of every 500 visitors to GOV.UK, five did not receive JavaScript, but only one had JavaScript explicitly disabled. The other four could be missing out on JavaScript for any of several reasons: an overzealous corporate proxy server; a request for JavaScript timing out due to high latency; or even an unnoticed syntax error.

Furthermore, JavaScript—unlike CSS and HTML—does not degrade gracefully. This means that if developers use a single ES6 syntax feature, or even make a single standard library function call without checking that the function has been defined first, their JavaScript could either stop running midway through execution or not run at all. When JavaScript is used to enhance websites, this doesn’t matter so much—visitors can still follow links and submit forms and generally use the web as intended. But when JavaScript is a requirement, anyone using even a slightly older browser is likely to get a blank page—and no explanation of what to do about it.

Semantic structure is still important

As designed by Tim Berners-Lee in 1993, HTML defined a common structure for the mesh of interconnected documents we now know as the web. The semantic meanings imbued in this common structure provide machine-readable context for the information contained in a web page. In practical terms, this extra information enables web browsers to enhance the user experience. For example, a web browser can implement a way to add events defined with time elements to a user’s calendar; a screen reader can read through a list differently than it would a paragraph. The difference between a list and a paragraph is clear to human viewers of a document; the common structure provided by HTML makes it clear to computers, too.

The semantic meaning behind HTML sets the web apart from native application environments like Cocoa, Windows Presentation Foundation, and Qt. Structured information matters more to the web because of the diverse ways in which it can be accessed. When I create an iPhone application, I can safely assume that every person using that application will use it in a similar way. The information my app presents will always be presented in much the same way, and I will always have complete control over that presentation. Even if someone using my app interacts with it through VoiceOver (Apple’s assistive technology for people with vision impairments), they still interact with the application in a similar way to a sighted user: by tapping around on the screen. They just happen to be hearing the text instead of seeing it.

The web doesn’t work that way. Websites aren’t viewed solely through web browsers. People consume websites through apps like Pocket or Instapaper, which try to use the structured information of a web page to extract its relevant content. A browser on a smartwatch might ignore your layout and present your information in a way that’s more suitable for a one-inch screen. Or—who knows?—your website might be used through some future device that will transform the information into thoughts beamed directly into a user’s brain. Even web screen readers don’t work like VoiceOver does on an iPhone, reading out the text in the order it’s laid out under a user’s finger. Web screen readers read through the whole document, ignoring layout, and infer meaning from the standardized semantic definitions of HTML tags. A simple example of when semantics like this matter is the recently introduced main element, used to define the main part of a document. To a sighted user viewing your website through Google Chrome, whether you use <main> or <div id=“main”> makes no difference. To someone using another web client, though, such as a screen reader or Instapaper, the meaning implied by the main element is very important to their software in helping them navigate your document.

Developing an application for the web, therefore, is not as simple as developing for a native platform. Making sure it works the way we want it to in the five major browsers and pushing it out isn’t good enough for the web. We need to test our work in screen readers. We need to review our markup to make sure it provides as much semantic metadata as possible—not just for today’s web clients, but for tomorrow’s as well.

Single-page web app frameworks

When using “single-page web app” frameworks like Angular and Ember, the trend is to treat websites like native apps, with little regard for the nuances that make the web unique. Developers make assumptions about their users that can seriously damage the experience of people who don’t meet those assumptions. As an example of what this mindset can result in, consider the markup for a login button (since changed) that I recently found on Patreon’s site:

<span class="patreon-button sub-section navigation-active" data-ng-click="triggerChangeWindow(navigation.login_url)">Log In</span>
Example of a login button that once appeared on Patreon’s site
Patreon’s fairly standard login button acts just like a link. No need for special JavaScript here.

This link works fine for me in Safari, but in any environment other than a current mainstream browser, this button is totally useless. Let’s say we have a hypothetical smartwatch browser called WatchBrowse. Maybe it displays a list of links for the user to navigate through because this particular smartwatch doesn’t have a cursor that can interact with the page. Because HTML defines a standard way to create links on a web page (the a element), WatchBrowse could theoretically just list every a tag on the page with its href attribute and content—until a site like Patreon comes along and decides to shun web standards in favor of reimplementing basic browser functionality from scratch.

If Patreon had used an a tag instead of a span, WatchBrowse could perhaps find the link and display it in the list. When a user selected the link, it could simulate a click event instead of just using the href attribute. But what about functionality that requires the browser to know where the link is going to lead ahead of time? A browser extension might allow you to search links on a page by their href values, which would be useful if you wanted to quickly find where somebody links to their Twitter account, for example. Firefox shows where a link is going to take me when I hover over it. When link href attributes are no longer static values but are, instead, decided by arbitrary JavaScript in click handlers, these helpful features are no longer possible.

Patreon’s site is built with Angular, and while Angular is not at fault here per se, the mentality of treating HTML as a view layer that goes along with using these frameworks probably contributed to Patreon’s poor decision.

What if we created the same link the way the framework developers recommend in their documentation? A more standard way to make a link in Angular might look like this:

<a ng-href="/login">Log In</a>

When rendered into the DOM by client-side JavaScript, that snippet turns into this:

<a ng-href="/login" class="ng-binding" href="/login">Log In</a>

Ember handles this similarly. A link is defined in an Ember template like so:

{{#link-to sessions.new}}Log In{{/link-to}}

And when it’s rendered into the DOM, it becomes this:

<a id="ember-563" class="ember-view" href="/sessions/new">Log In</a>

Ember and Angular then intercept the link’s click event to render the new content without reloading the page. Crucially, though, if the click event were never fired and the browser loaded the value of href, there would be no visible difference to the user other than an extra page reload, because Ember and Angular by default don’t try to reinvent the wheel by defining their routing in terms of URLs.

In their current forms, however, Ember and Angular still require JavaScript to render their templates and create those links in the first place. Four out of every 500 people who visit a website built with Angular or Ember will encounter a completely blank page.

A solution?

When dynamic web page content is rendered by a server, rendering code only has to be able to run on that one server. When it’s rendered on a client, the code now has to work with every client that could possibly visit the website. Developers are now moving away from server-rendered websites because they don’t offer the sort of rich application experience that client-rendered sites can provide. But I think there’s still a role for server rendering in the new world of client-side applications.

At the moment, requiring JavaScript is a tradeoff that developers using single-page web app frameworks have to make, but it seems to me that this is exactly the sort of problem that should be handled by a framework. We are fortunate as web developers in that we write application code for the web in one of the most universal programming languages that has ever existed. If framework developers could put in the effort (which, admittedly, seems large) to get apps running in Node just as they run in the browser, initial page rendering could be handled by the server, with all subsequent activity handled by the browser. Crucially, if a server can render links into a tags, like Ember currently does on the client, it would be possible for a user who did not receive JavaScript (for whatever reason) to navigate around the website. It might be possible to get forms working as well, by running all the validation and submission logic on the server instead of on the client. If this effort could be made at the outset by a framework maintainer, then every developer using that framework could immediately transform an app that only worked on the latest web browsers into a progressively enhanced experience compatible with virtually any web client—past, present, or future.

Progressive enhancement has been important to web developers for a while now. It recognizes that the vital part of the web experience is content, and that any additional improvement to the user experience should not undermine the universal availability of content provided by the web. Current approaches to single-page web apps tend to abandon this principle, but progressive enhancement and single-page web apps are not fundamentally incompatible.

In fact, progress is being made in this arena. To improve Ember’s compatibility with search engines, for example, an in-house team is working on implementing server-side rendering. But the solution to the problems caused by single-page web apps is not purely technical: there’s a growing problem in the way people think about the web. It has become commonplace to treat the web as just another application platform—but the web is so much more than that. The web is the universal information platform. It doesn’t matter if somebody visits a website on a $2,000 iMac, or a $50 Android tablet, or the $5 web client of a future we can’t even imagine yet—in theory, at least. In practice, it’s important to make sure that we don’t sacrifice the experiences of a small number of users just so we can slightly improve the experiences of the rest, damaging the universal nature of the web in the process.

Initiation to Code

Posted by The fine folks at A List Apart |31 Mar 15 |

When you imagine a programming mentor, certain archetypes might flash into your mind. Maybe you see the wise monk who’s meditated on design patterns for decades. Perhaps it’s the sophisticated keynote speaker with a staggering list of open source contributions. Or it might be that mad scientist polyglot obsessed with a dozen languages you’ve never heard of.

But if these characters aren’t on your team when the new hire straight out of school joins up, who’s going to take the reins of training?

You, of course.

With the rise of coding boot camps and increased enrollment in computer science courses at universities, the pool of junior developers is larger than ever. But when it comes to nurturing all this talent, many teams don’t know where to start. Some developers think they don’t yet know enough to be a good mentor, while others think they’re just too busy for it.

Whatever your initial reservations may be, you can mentor, and you can do it well. All you need are the right guidelines and a little bit of structure.

Starting the mentor–mentee relationship

When you’re seeking a mentee, look for “someone who has something to teach you, but doesn’t know it yet,” as a friend of mine who mentors at RailsBridge recently suggested.

I take this to mean two things. The first is to stay open to a range of personality types. Look for a mentee who’s not similar to you. It can be tempting to compare juniors to yourself-three-years-ago and jump to conclusions from there. But mentorship is a two-way street—it’s not about lecturing. In fact, it’s not even about passing your knowledge down to another person. It’s about making a mutual agreement to get better at what you both do. You’ll learn more from each other if you have different ways of thinking.

The second is to choose someone you want to learn from. If your mentee isn’t the type of person you’d be happy to march into code battle with, you won’t get anywhere. The primary quality to avoid is arrogance; an arrogant person will have a slower rate of growth than someone who takes feedback gracefully.

Because team dynamics are constantly in flux, you might not often establish formal mentor–mentee relationships with people on your team. That doesn’t mean you won’t find opportunities to mentor. Look for little moments to step in and help; you’ll be viewed as a leader, and more mentoring opportunities will begin to materialize.

Agility is the key

The key to being a good mentor is a concept you’re already familiar with, since it’s also the key to developing good software and learning new information effectively. That key is agility.

Of course, “agile” has become a pretty loaded term that tends to confuse more than it clarifies. In a 2014 blog post, Dave Thomas, one of the original signatories of the Agile Manifesto, acknowledged this confusion. Then he reminded us how to do anything in an agile fashion:

  • Find out where you are
  • Take a small step toward your goal
  • Adjust your understanding based on your goal
  • Repeat

Or as the Scrum Guide puts it: “inspect and adapt.” Inspecting and adapting are foundational to being a good mentor. If you don’t take the time to check up on your mentees and listen to their concerns, travails, and triumphs, then you will have no metric for achievement.

Employing agility as a mentor requires sensitivity, creativity, and solid communication skills. It also requires the foresight to see what your mentee should be aiming for, and the hindsight to see what your mentee has already accomplished.

To establish a framework for gauging your mentee’s progress, consider the three phases every new team member goes through in some form. The first phase is total unfamiliarity and constant discovery; the second is a transitional period with a clear trajectory of progress; and the third is self-driven competence. In all three phases, remember that agility remains your most vital tool.

Phase 1: a little respect

On the very first day, have a conversation with your mentee in which your goal is to discover exactly what their level and type of experience is right now. This conversation serves a dual purpose. First, it establishes a two-way discourse, a communicative relationship that will underpin your agile approach to mentorship. Second, it gives you a basis to decide what to assign to your mentee first. Starting off with a direct conversation can prevent an incredible amount of confusion and wasted time.

Pair programming at this stage is pretty much mandatory. It’s far and away the best method for getting a new developer up to speed, especially if you have a large or confusing code base. A recent article by Sarah Mei makes some excellent points about how to pair effectively, but the most salient one is this: don’t touch the keyboard (much). Ask questions, and answer questions with more questions. The closer you are to your mentee’s level of experience, the harder it is to take the backseat approach, since you’re often just figuring things out yourself. But whenever you feel the urge to barge ahead and solve the problem, resist! Your mentee will learn much more effectively in the Socratic style.

Keep in mind, though, that you aren’t only a technical guide. Early on, gaining technical experience probably won’t be the first thing on a junior developer’s mind—much to their surprise. They’ll be confronted with social puzzles and process nuances that everyone else takes for granted. Clear away confusion over all the things surrounding the work so your mentee has no obstacles to digging down into the work itself.

As eager as you might be to keep things moving, make sure to be honest about your own limitations, too. Consider phrases like: “I don’t understand this, either.” “I need to take a break.” “I can’t help right now, but try asking Oleg.” All of these can be music to a beginner’s ears. The more truthful you are about when and how you and others can help, the more realistic your mentee’s outlook will be. And a realistic outlook leads to good decisions.

Phase 2: challenge accepted

With a solid communicative relationship established, your mentee will quickly move past the green stage. You’ll know that they’re in Phase 2 when they can easily figure out what needs to be done on a ticket, even if they don’t know quite how to do it. This means they’re starting to get comfortable, and it’s also when things get really fun. It’s time to add challenge to the mix.

Whatever you do, don’t simply assign your mentee whatever happens to come up. Instead, inspect, adapt, and select assignments that build on what your mentee has done before. If possible, try to tell a story with your assignments. Something in the next ticket could elaborate on or reinforce a concept from the previous ticket. Or you could tell the story of a single request, from UI to database and back again.

If you must assign your mentee something that looks relatively simple, use it as an opportunity to train them in looking at code with a pessimistic eye. What would a null input do? Does this open any vectors for attack? Could you have refactored another component to make this change easier? Do your tests cover all the new code? Even if your mentee decides that the code is airtight (which it never is), they’ll exercise their programming muscles trying to answer your questions.

While you challenge your mentee at every turn, don’t forget to take a lot of opportunities to encourage. A task that seems routine to you might feel like a triumph for your mentee, so when they finish something, congratulate them. And never underestimate the power of a simple “Good job.”

Phase 3: the initiation game

Your ultimate goal is to transform your mentee into a productive, contributing team member—an equal. With enough time and practice, they’ll eventually get there. But why wait? There’s a better, faster way. When your mentee is ready, you can help the transition along with a tool as old as humankind: initiation.

No matter who you are or where you’re from, you’re familiar with the narrative of initiation. Joseph Campbell identified it as one of the major elements of the hero’s journey, the underlying pattern shared by epic tales all across the world. From ancient mythology to pop culture mainstays like Star Wars and Fight Club, initiation stories have taken countless forms. The framework, however, is always the same: a harrowing ordeal that, if survived, yields the initiate to a new and higher level of awareness.

Initiation isn’t just for epic heroes. It’s a powerful tool for transformation in any context. When you feel your mentee is ready to take a big step, assign a task that seems a little too complex, a little too far outside the scope of what has been done before, and just difficult enough to accelerate the transition into an equal, independent team member.

An effective initiation for a software developer should have three qualities:

  1. It would not be trivial for someone with a few more years of experience.
  2. It demands communication with senior-level people. Ideally, the mentee will gain some insight into the factors that go into a high-level technical decision. Overhauling a UI component, modifying your deployment architecture, or hand-rolling a new caching strategy are all good candidates for this type of experience.
  3. It has a demonstrable, preferably quantifiable, value. It might be a new front-end feature, or it might be a graph that shows a decrease in page load time, but ideally, your mentee will be able to point to a visual representation of the change and say, “I’m responsible for that.”

Often, initiations are accidental, a natural outgrowth of increasing experience and responsibility. But if you do set up a conscious initiation for your mentee, you don’t need to tell them that you’re doing it. In fact, you probably shouldn’t. Show your mentee you believe in them by treating them like a regular engineer.

If the initiation is successful, your mentee will become an equal—though an equal who still has a lot to learn. They’ll be able to drive their own progress without much hand-holding, and pairing sessions will feel more collaborative than instructive. After this transition, you can take a big step back, but continue to guide and challenge when necessary. After all, as Robert Anton Wilson said, a true initiation never ends.

Mentoring benefits the whole team

When I first joined my team, I was the only junior developer. Now, our membership has grown and shifted, and almost half of us are juniors.

I’ve seen firsthand how much this shift has changed our dynamic for the better. Experienced engineers pose questions to the juniors, motivating them to refine their knowledge—and the juniors pose questions right back. Instead of a couple good communicators bearing the brunt of training, everyone is actively skill-sharing all the time. Where once individuals were siloed, there’s now a spirit of collaboration and fun. Willingness to learn and adapt has become a core value for the entire team.

It has also observably driven up our code quality. Fresh eyes are great at identifying anti-patterns, style issues, and confusing bits of code. With a healthy mix of juniors, we’ve become better at balancing technical debt repayment and pushing out new features, and the new code we merge is easier to maintain. Without mentorship, these improvements would never have come about.

Software engineers are fortunate to work in an industry where the tools and processes for collaboration are both well-defined and popular. But to paraphrase the Agile Manifesto, it’s the people and interactions that really make or break a product. Mentorship is a powerful interaction that, done right, can elevate your team’s quality of both life and code, and lay the groundwork for a more successful organization.

Pluralization for JavaScript

Posted by The fine folks at A List Apart |17 Mar 15 |

Seventy-one percent of today’s internet users don’t speak English as a first language, and that number keeps growing. But few people specialize in internationalization. As a result, most sites get it wrong—because things that seem straightforward are often anything but.

Take pluralization. Turning singular words into plurals within strings gets tricky quickly—even in English, where most plural words end with an s. For instance, I worked on a photo-sharing app that supported two languages, English and Chinese. It was easy to add an s to display “X like[s]” or “Y comment[s].” But what if we needed to pluralize “foot” or “inch” or “quiz”? Our simple solution became a broken hack.

And English is a relatively simple case. Many languages have more than two plural forms: Arabic, for example, has six, and many Slavic languages have more than three. In fact, at least 39 languages have more than two plural forms. Some languages only have one form, such as Chinese and Japanese, meaning that plural and singular nouns are the same.

How can we make sense of these complex pluralization issues—and solve them in our projects? In this article, I’ll show you some of the most common pluralization problems, and explain how to overcome them.

Problems with pluralization

Pluralization gets even more complex: each language also has its own rules for defining each plural form. A plural rule defines a plural form using a formula that includes a counter. A counter is the number of items you’re trying to pluralize. Say we’re working with “2 rabbits.” The number before the word “rabbits” is the counter. In this case, it has the value 2. Now, if we take the English language as an example, it has two plural forms: singular and plural. Therefore, our rules look like this:

  • If the counter has the integer value of 1, use the singular: “rabbit.”
  • If the counter has a value that is not equal to 1, use the plural: “rabbits.”

However, the same isn’t true in Polish, where the same word—“rabbit,” or “królik”—can take more than two forms:

  • If the counter has the integer value of 1, use “królik.”
  • If the counter has a value that ends in 2–4, excluding 12–14, use “królika.”
  • If the counter is not 1 and has a value that ends in either 0 or 1, or the counter ends in 5–9, or the counter ends in 12–14, use “królików.”
  • If the counter has any other value than the above, use “króliki.”

So much for “singular” and “plural.” For languages with three or more plural forms, we need more specific labels.

Different languages use different types of numbers

You may also want to display the counter along with the pluralized noun, such as, “You have 3 rabbits.” However, not all languages use the Arabic numbers you may be accustomed to—for example, Arabic uses Arabic Indic numbers, ٠١٢٣٤٥٦٧٨٩:

  • 0 books: ٠ كتاب
  • 1 book: كتاب
  • 3 books: ٣ كتب
  • 11 books: ١١ كتابًا
  • 100 books: ١٠٠ كتاب

Different languages or regions use different number formats

We also often aim to make large numbers more readable by adding separators, as when we render the number 1000 as “1,000” in English. But many languages and regions use different fractional and thousand separators. For example, German renders the number 1000 as “1.000.” Other languages don’t group numbers by thousands, but rather by tens of thousands.

Solution: ICU’s MessageFormat

Pluralization is a complex problem to solve—at least, if you want to handle all these edge cases. Recently, International Components for Unicode (ICU) did precisely that with MessageFormat. ICU’s MessageFormat is a markup language specifically tailored to localization. It allows you to define, in a declarative way, how nouns should be rendered in various plural forms. It sorts all the plural forms and rules for you, and formats numbers correctly. Unfortunately, many of you probably haven’t heard of MessageFormat yet, because it’s mostly used by people who work specifically with internationalization—known to insiders as i18n—and JavaScript has only recently evolved to handle it.

Let’s talk about how it works.

Using CLDR  for  plural forms

CLDR stands for Common Locale Data Repository, and it’s a repo that companies like Google, IBM, and Apple draw on to get information about number, date, and time formatting. CLDR also contains data on the plural forms and rules for many languages. It’s probably the largest locale data repository in the world, which makes it ideal as the basis for any internationalization JavaScript tool.

CLDR defines up to six different plural forms. Each form is assigned a name: zero, one, two, few, many, or other. Not all locales need every form; remember, English only has two: one and other. The name of each form is based on its corresponding plural rule. Here is a CLDR example for the Polish language—a slightly altered version of our earlier counter rules:

  • If the counter has the integer value of 1, use the plural form one.
  • If the counter has a value that ends in 2–4, excluding 12–14, use the plural form few.
  • If the counter is not 1 and has a value that ends in either 0 or 1, or the counter ends in 5–9, or the counter ends in 12–14, use the plural form many.
  • If the counter has any other value than the above, use the plural form other.

Instead of manually implementing CLDR plural forms, you can make use of tools and libraries. For example, I created L10ns, which compiles the code for you; Yahoo’s FormatJS has all the plural forms built in. The big benefits of these tools and libraries are that they scale well, as they abstract the plural-form handling. If you choose to hard-code these plural forms yourself, you will end up exhausting yourself and your teammates, because you’ll need to keep track of all the forms and rules, and define them over and over whenever and wherever you want to format a plural string.

MessageFormat

MessageFormat is a domain-specific language that uses CLDR, and is specifically tailored for localizing strings. You define markup inline. For example, we want to format the message “I have X rabbit[s]” using the right plural word for “rabbit”:


var message = 'I have {rabbits, plural, one{# rabbit} other{# rabbits}}';

As you can see, a plural format is defined inside curly brackets {}. It takes a counter, rabbits, as the first argument. The second argument defines which type of formatting. The third argument includes CLDR’s plural form (one, many). You need to define a sub-message inside the curly brackets that corresponds to each plural form. You can also pass in the symbol # to render the counter with the correct number format and numbering system, so it will solve the problems we identified earlier with the Arabic Indic numbering system and with number formatting.

Here we parse the message in the en-US locale and output different messages depending on which plural form the variable rabbits takes:


var message = 'I have {rabbits, plural, one{# rabbit} other{# rabbits}}.';
var messageFormat = new MessageFormat('en-US');
var output = messageFormat.parse(message);

// Will output "I have 1 rabbit."
console.log(output({ rabbits: 1 }));

// Will output "I have 10 rabbits."
console.log(output({ rabbits 10}));

Benefits of inlining

As you can see in the preceding message, we defined a plural format inline. If it weren’t inlined, we might need to repeat the words “I have…” for all plural forms, instead of just typing them once. Imagine if you needed to use even more words, as in the following example:


{
  one: 'My name is Emily and I got 1 like in my latest post.'
  other:  'My name is Emily and I got # likes in my latest post.'
}

Without inlining, we’d need to repeat “My name is Emily and I got…in my latest post” every single time. That’s a lot of words.

In contrast, inlining in ICU’s MessageFormat simplifies things. Instead of repeating the phrase for every plural form, all we need to do is localize the word “like”:


var message = 'My name is Emily and I got {likes, plural, one{# like} other{# likes}} in my latest post';

Here we don’t need to repeat the words “My name is Emily and I got…in my latest post” for every plural form. Instead, we can simply localize the word “like.”

Benefits of nesting messages

MessageFormat’s nested nature also helps us by giving us endless possibilities to define a multitude of complex strings. Here we define a select format in a plural format to demonstrate how flexible MessageFormat is:


var message = '{likeRange, select,
  range1{I got no likes}
  range2{I got {likes, plural, one{# like} other{# likes}}}
  other{I got too many likes}
}';

A select format matches a set of cases and, depending on which case it matches, it outputs the corresponding sub-message. And it is perfect to construct range-based messages. In the preceding example, we want to construct three kinds of messages for each like range. As you can see in range2, we defined a plural format to format the message “I got X like[s],” and then nested the plural format inside a select format. This example showcases a very complex formatting that very few syntaxes can achieve, demonstrating MessageFormat’s flexibility.

With the above format, here are the messages we can expect to get:

  • “I got no likes,” if likeRange is in range1.
  • “I got 1 like,” if likeRange is in range2 and the number of likes is 1.
  • “I got 10 likes,” if likeRange is in range2 and the number of likes is 10.
  • “I got too many likes,” if likeRange is in neither range1 nor range2.

These are very hard concepts to localize—even one of the most popular internationalization tools, gettext, can’t do this.

Storage and pre-compiled messages

However, instead of storing MessageFormat messages in a JavaScript variable, you might want to use some kind of storage format, such as multiple JSON files. This will allow you to pre-compile the messages to simple localization getters. If you don’t want to handle this alone, you might try L10ns, which handles storage and pre-compilation for you, as well as syncing translation keys between source and storage.

Do translators need to know MessageFormat?

You might think it would be too overwhelming for non-programming translators to know Messageformat and CLDR’s plural form. But in my experience, teaching them the basics of how the markup looks and what it does, and what CLDR’s plural forms are, takes just a few minutes and provides enough information for translators to do their job using MessageFormat. L10ns’ web interface also displays the example numbers for each CLDR plural form for easy reference.


Screencapture of the L10ns interface, showing plural variables for the phrase 'I got X likes.

Pluralization isn’t easy—but it’s worth it

Yes, pluralization has a lot of edge cases that aren’t easily solvable. But ICU’s MessageFormat has helped me tremendously in my work, giving me endless flexibility to translate plural strings. As we move to a more connected world, localizing applications to more languages and regions is a must-do. Knowledge about general localization problems and tools to solve them are must-haves. We need to localize apps because the world is more connected, but we can also localize apps to help make the world more connected.

80/20 Practitioners Make Better Communicators

Posted by The fine folks at A List Apart |17 Mar 15 |

I spent the better part of 2014 working on two redesigns: one for a major pizza chain, the other for a major bike retailer. The five of us working on the redesigns were excited beyond words—two large-scale sites about two things we loved: pizza and bikes! We all wanted to be heavily involved in every phase of these projects to ensure their success. Along the way, we learned important lessons about how to fine-tune that involvement to arrive at a better outcome.

Working with the same team on two simultaneous projects allowed us to experiment a little with our process and compare notes. The ecommerce-driven Pizza Site had a strong focus on user flows, so we began by creating HTML wireframes for every page. What had once seemed like a bunch of grandiose ideas on whiteboards morphed into actual working prototypes. As we moved into design, the prototypes came to life in all their melted-cheese glory. But by month nine of the engagement, as we started to polish up the templates, we realized that we were looking at the third installment of the same redesign.

This isn’t an unusual occurrence. Teams often inadvertently recreate designs multiple times across phases; the end result looks almost nothing like what the team set out to achieve. What causes this disconnect?

In my experience, it comes from insufficient communication among teams with varying skillsets. Some teams are composed of specialists who all want their ideas and voices heard (yielding vastly different results) while fighting for time, resources, and budget. Alternately, when a generalist works on the entire site, they risk getting spread too thin; the struggle to explore and iterate can produce stale, predictable solutions. Either too much specialization or too much generalization can overwhelm practitioners (and budgets)—and neither approach works.

How to become an 80/20 practitioner

Luckily, there’s a better way. When designers and developers (and entire web teams) work closely together with flexibility and shared understanding, they can use their time and resources more efficiently and creatively. Whether your process is waterfall or agile, a solid team foundation applies to everyone: it allows you to shape a solution that benefits all teammates on a project.

To avoid the mistakes we made on our Pizza Site process, we balanced our responsibilities differently with the Bike Site. We became what I call 80/20 practitioners, focusing 80 percent of our time on our own respective strengths while distributing the remaining 20 percent across other disciplines to benefit the entire project.

80/20 collaboration is about people. It’s about passions. Sounds great, right? So, where do we start?

Establish the foundation

Being a good practitioner means seeing beyond yourself to your team’s broader needs and goals. While molding your process, it’s important to maintain an open, honest discussion with your teammates. Take a comprehensive inventory of the people on your team. Instead of labeling someone a “designer” or a “developer,” take stock of their true skillsets and passions. I’ve worked with amazing graphic designers, amazing UX designers, and amazing interaction designers, all of whom had the same title: designer. What works depends on the person.

We’ve all heard the argument that designers need to code. And while that might be ideal in some cases, the point is to expand your personal spectrum of skills to be more useful to your team, whether that manifests itself in the form of design, content strategy, UX, or even project management. A strong team foundation begins by addressing gaps that need to be filled and the places where people can meet in the middle. This is also how you, as a practitioner, can identify where you should develop your 20 percent of surplus abilities for a given project.

If you imagine your team as a spectrum of skills, each person should have a skillset that covers one part of that spectrum (overlapping to some extent with another part). Let’s pretend this spectrum goes from graphic design (red), to code (blue), with every shade of purple in between. As a designer, I span from the reddest of reds to a reddish purple. That leaves the rest of the purple and blue to be picked up. Let’s say my team includes a designer/developer hybrid, Ava, who is all the varying shades of purple. And let’s say I also have a strictly blue backend developer, Carter, on my team. In this instance, we’ve covered all our bases. If it was just Carter and me, though, we’d be left with a significant void in the middle. We would need either to extend our 20-percent skillset into the purple area or to bring in an additional person to bridge the gap. The spectrum’s endpoints will vary from person to person and team to team.

Strengthen weaknesses

Whenever someone told me, “You should code!” I would think: “But Developer McCoderson can do it so much better and faster than I ever could!” Which was true, so I continued my deep dive into design. Over time, though, working very closely with my developers every day on the Pizza Site, my interest was slowly piqued. Once I started incorporating HTML wireframes into my design process, I began to see how it benefitted me. I could make faster content updates, my layout was automatically responsive, and I could focus purely on content hierarchy rather than worrying about resizing boxes every time content changed.

The more I realized that coded deliverables could be design deliverables, the more I understood that I could get interactions in front of a client earlier. Animations, dropdowns, popovers, etc.—these things are design. We want the client’s feedback on this early, because seemingly minor details like hovers reflect the brand and reinforce the design just as much as an image or color choice do.

This discovery was so liberating that I actually wanted to include code in my process from then on because I preferred working that way, not just because I thought “This will make me a better designer.” I now catch myself voluntarily reading about things like inline SVG and the picture element and almost don’t recognize myself!

Take a candid look at your process and see where you want to expand your 20 percent, not where you think you should expand it. Let’s go back to Carter, the backend developer, for a second. Maybe he wants to improve his front-end skills—but by “front-end,” does he mean his code or his design eye? What’s missing is probably not a talent for writing beautiful DRY code, but rather the ability to recognize design nuances. Maybe the place to start is by reading articles about typography or checking out other design resources, instead of plunging into JavaScript.

Once you start recognizing these secondary areas, you can begin to take your newfound interests offline and look into different meetups or talks than you’d normally attend. I discovered that nothing helped me improve my 20-percent skills more than simply befriending wildly talented developers, both in and out of the workplace.

Learn from each other

The developer on the Bike Site team created a Grunt file to accommodate our entire team’s needs, including design deliverables and how we handle wireframes. Once everything started being delivered within a code-based project hub, we were all on the same page—literally. We could jump in and help each other as necessary, especially on stressful delivery days. Even the project manager was able to use and update the hub.

And the developers learned from me, too. Having them involved from day one meant that they were included in a lot of our design reviews. They began to understand the thought process behind our design decisions, and everyone could holistically understand the system we all were building together. When we began to figure out the wireframing and user-experience part of the site, every member of the team had behavior- and experience-driven suggestions that found their way into the project, both in terms of how it would ultimately look and how it would be built. With everyone involved from the beginning, new ideas that previously never would have been considered cross-pollinated the deliverables—whether it was a developer suggesting an out-of-the-box design pattern or a designer creating a performance budget.

When these conversations happen, barriers between teammates gradually fall away. You’ll probably suggest tools to one another and start to merge processes; in that merging, a new collaborative process will take shape. When we borrow one another’s tools, we begin to learn their benefits and how they may work for our own needs, and we ultimately start speaking the same language. Being aligned on objective project goals helps to keep reviews on track and to more easily settle discrepancies. It isn’t about making anyone’s job easier; it’s about focusing on what’s best for the project. Shared process isn’t something that you can just decide to do; rather, it emerges from learning how another person works.

Let go of ego

To rapidly take a design to code, the overall direction needs to be mostly approved by the client. I say “mostly” because the best iterations happen in the browser once we begin interacting with our designs. This is where our 20-percent-spectrum overlap really kicks in. There will be holes in the design that need to be filled, and it’s up to the developer to create a useful roadmap for the designer to iterate on. Imagine that an early homepage concept is approved and we jump into developmental iterations, but I haven’t had a chance to style the navigation dropdowns yet. I love it when developers take a stab at styling these things. If need be, I can always tweak details that feel off to me. When developers have some design sense, they are able to jump in and make design decisions that the designer may not have considered in a fluid layout or behavior. Designers love to be perfectionists, but we need to learn to let go and not be afraid to allow developers to jump into coding a template of an “imperfect” mockup.

There’s nothing wrong with piece-designing parts and modules as the developer finds holes in the page or media queries. As Dan Mall has stated, it’s about deciding in the browser, not designing in the browser. Everything might not be figured out yet, but that’s okay: we’ll figure it out together. Our websites are fluid; our process should be, too.

Shaking up a process isn’t easy

Change can be hard for any organization, especially when strict guidelines are in place for current processes. You have to work toward breaking down any barriers in communication—whether by getting to know a new teammate on a new project, working within your organization to dissolve silos, or trying to introduce a new workflow idea to your boss. A malleable process is a strong one.

The best place to start is with your project manager. It’s difficult to fit a new process into an ongoing project retroactively, so try to address this at the planning stage. If you’re about to begin a project, make the manager aware of your ideas and how the project plan could be shaped a little differently. It’s important for the project manager to understand the plan so that they can set the expectations with the client accordingly. It’s equally important for them to understand how the timeline will be affected, as it may depart from the typical flow your team is used to.

In large organizations, managers may need to run ideas past the managers of other departments. See if your next project can be a trial run for experimenting with a new process, and volunteer to head the initiative. Samantha Warren gave a fantastic presentation at An Event Apart on getting design ideas moved through an organization. If this doesn’t seem feasible, try building relationships with your counterparts yourself. See if they are open to trying new methods and working more closely together. If you get multiple people on board, it may be easier to convince the powers that be to try something new. Teams organically working well together are a powerful demonstration of just how effective collaboration can be.

Everybody benefits

Dive deeply into your passions while understanding the moving parts around you. Mastering your specialty is not only crucial for professional development and personal satisfaction, but it will also serve your team as you help to stretch that spectrum further. Projects benefit from experts who understand the whole while focusing on their strengths.

When we speak openly about shared end goals, our teamwork gets stronger. When we jump in and help out on cross-discipline deliverables, our teamwork gets stronger. Most importantly, when we combine our collective strengths and work together fluidly, it gives us the perfect recipe for an amazing project.

Remain true to your passions, but take the time to learn something about the skillsets of others to help you craft a unique team dynamic. The 80/20 guideline is a place to strive for—a place where we push our own skills and passions while rounding out our knowledge so that we can work better with our teammates. Being an 80/20 practitioner makes a stronger you and a stronger team.

Quantity Queries for CSS

Posted by The fine folks at A List Apart |03 Mar 15 |

Don’t you just hate documentaries that don’t deliver? They have enticing names like In Search of the Giant Squid, and tease you with shots of murky underwater shapes and excited scientists pointing far out to sea. You settle down to watch, eyes narrowed with suspicion, thinking, “I better see some squid or I’m writing an angry letter to the network.”

Sure enough, 90 minutes of interviews with bored-looking fishermen later, the presenter is forced to conclude, “No… no, we didn’t find any big squids. But maybe one day [majestic orchestral flourish].” Great. You wanted Finding Nemo and got Not Finding Nemo instead.

I wouldn’t do that to you, friends. This is your guide to creating style breakpoints for quantities of HTML elements, much as you already do with @media queries for viewport dimensions. I’m not pointing at some blurry specification in the distance or a twinkle in an implementer’s eye. We’re going to do this today, with CSS that’s already available.

Dynamic content

Responsive web design is primarily concerned with one variable: space. In testing responsive layouts, we take an amount of content and see which spaces it will successfully fit into. The content is deemed constant; the space, variable.

The @media query is the darling of responsive web design because it allows us to insert “breakpoints” wherever one layout strategy ceases to be viable and another should succeed it. However, it’s not just viewport dimensions, but the quantity of content that can put pressure on space.

Just as your end users are liable to operate devices with a multitude of different screen sizes, your content editors are liable to add and remove content. That’s what content management systems are for.  This makes Photoshop mockups of web pages doubly obsolete: they are snapshots of just one viewport, with content in just one state.

In this article, I will be outlining a technique to make CSS quantity-aware using specially formed selectors. I will be applying these selectors to one classic problem in particular: how to alter the display of items in a horizontal navigation menu when there are too many to suit the initial layout mode. That is, I will demonstrate how to switch from a display: table-cell to a display: inline-block layout when the number of items in the menu becomes “more than or equal to 6.”

I will not be relying on any JavaScript or template logic, and the menu’s list markup will remain devoid of class attribution. By using CSS only, the technique honors the separation of concerns principle, according to which content (HTML) and presentation (CSS) have clearly defined roles. Layout is CSS’s job and, where possible, CSS’s only.

Comparing the initial menu bar layout for fewer than six items with the layout for six or more items

The demonstration is available on CodePen and will be referred to throughout the article.

To help me illustrate this qualification of quantity, I’ll be employing diagrams of squids in the article to represent HTML elements. Green squids with ticks represent elements that match the CSS selector in question, red squids with crosses are unselected elements, and grayed-out squids denote elements that don’t exist.

A key for the three squid symbols to be used in following diagrams. A green squid (for selected elements), a red squid (for unselected elements) and a grey squid for elements that don't exist

Counting

The key to determining the quantity of elements in a given context is to count them. CSS doesn’t provide an explicit “counting API,” but we can solve the same problem with an inventive combination of selectors.

Counting to one

The :only-child selector provides a means to style elements if they appear in isolation. Essentially, it lets us “style all the child elements of a particular element, if counting those children returns 1 as the total.” Aside from its stablemate :only-of-type, it is the only simple selector that can be described as quantity-based.

In the following example, I use :only-of-type to add a special style to any buttons that are the only elements of their element type among sibling elements. I give these lone buttons an increased font-size because singularity suggests importance.


button { 
  font-size: 1.25em;
}

button:only-of-type {
  font-size: 2em;
}

Here’s the crucial part. If I were to start out with one button, replete with a larger font size, and add buttons before or after it, each button would then adopt a smaller font size. The style of all the elements in the set is dependent on a quantity threshold of two: if there are “fewer than two” elements, the larger font size is honored. Take a look at that code again with the “fewer than two” notion in mind:


button {
  font-size: 1.25em;
}

button:only-of-type {
  font-size: 2em;
}

The fewer than two logic means one selected element (green squid) becomes two unselected elements (red squids) when an element is added

If it feels more natural, you can turn the CSS logic on its head using negation and make the condition “more than one.”


/* "More than one" results in a smaller font size */
button {
  font-size: 2em;
}

button:not(:only-of-type) {
  font-size: 1.25em;
}

The more than one logic means one unselected element (red squid) becomes two selected elements (green squids) when an element is added

Quantity n

Styling elements based on the “more than one” and “fewer than two” thresholds is a neat trick, but a flexible “quantity query” interface would accept any quantity. That is, I should be able to style “more than or equal to n” for any value of n. Then I can style “more than or equal to 6” in our navigation menu.

With a view to achieving this final goal, what if I were able to style discrete quantities like “exactly 6 in total” or “exactly 745”? How would I go about that? I would need to use a selector that allowed me to traverse sets of elements of any quantity numerically.

Fortunately, the :nth-last-child(n) selector accepts the number “n”, enabling me to count sets of elements from the end of the set toward the beginning. For example, :nth-last-child(6) matches the element that is sixth from last among sibling elements.

Things get interesting when concatenating :nth-last-child(6) with :first-child, introducing a second condition. In this case, I am looking for any element that is both the sixth element from the end and the first element.


li:nth-last-child(6):first-child {
  /* green squid styling */
}

If this element exists, the set of elements must be exactly six in quantity. Somewhat radically, I have written CSS that tells me how many elements I am looking at.

Of six squids, the first is green and the rest red. The first is subject to the nth-last-child(6) selector as well as the first-child selector

All that remains is to leverage this key element to style the remaining elements in the set. For this, I employ the general sibling combinator.

Six green squids because the first green squid is combined with the general sibling combinator to make all the red squids that follow green

If you’re not familiar with the general sibling combinator, the ~ li in li:nth-last-child(6):first-child ~ li means “any li elements that occur after li:nth-last-child(6):first-child.” In the following example, the elements each adopt a green font color if there are precisely six of them in total.


li:nth-last-child(6):first-child, 
li:nth-last-child(6):first-child ~ li {
  color: green;
}

More than or equal to 6

Targeting a discrete quantity—whether it’s 6, 19, or 653—is not especially useful because it pertains to such a specific situation. Using discrete widths rather than min-width or max-width in our @media queries would be similarly unhelpful:


@media screen and (width: 500px) {
  /* styles for exactly 500px wide viewports */
}

In the navigation menu, I really want to switch layouts at a threshold: a quantity watershed. I want to switch at six or more items—not exactly six items. When I reach that threshold, I would like to change from a distributed table layout to a simpler, wrappable inline-block configuration. Importantly, I would like to retain that switched configuration as the number of items further increases.

The question is, how does one begin to construct such a selector? It’s a question of offsets.

The n+6 argument

Another arithmetical argument adoptable by the :nth-child() selector takes the form “n + [integer]”. For example, :nth-child(n+6) styles all the elements in a set starting from the sixth.

A set of red squids that become green at the sixth squid for the remainder of the set (which can be of any size), counting upwards.

Though this has conceivable applications all its own, it’s not a “quantity-aware” selection method as such: we’re not styling anything because there are six elements or more in total; we’re just styling the ones that happen to enumerate higher than five.

To begin solving the problem properly, what we really need is to create a set of elements that excludes the last five items. Using the opposite of :nth-child(n+6):nth-last-child(n+6)—I can apply the switched layout properties to all “last elements” starting from the sixth, counting back toward the beginning of the set.


li:nth-last-child(n+6) {
  /* properties here */
}

This omits the last five items from a set of any length, meaning that when you reduce the length of the set below six, you cease to see any selected items. It’s a sort of “sliding doors” effect.

A set of green squids (to the left) and red squids (to the right) become a set of just red squids when the set becomes fewer than six in number

If, indeed, the set is greater than or equal to six in total, then all that remains is to style those last five items as well. This is easy: where there are more than six items, one or more items that “return true” (in JavaScript-speak) for the nth-last-child(n+6) condition must exist. Any and all of these extant elements can be combined with “~” to affect all items (including the last five) that follow it.

When a set of red squids has squids added to it, the squids to the right of the set become green and can be used to make the rest of the red squids green too (with the general sibling combinator)

The surprisingly terse solution to our problem is this:


li:nth-last-child(n+6),
li:nth-last-child(n+6) ~ li {
  /* properties here */
}

Naturally, 6 can be replaced with any positive integer, even 653,279.

Fewer than or equal to n

As in the earlier :only-of-type example, you can turn the logic on its head, switching from “more than or equal to n” to “fewer than or equal to n.” Which brand of logic you use depends on which state you consider the more natural default state. “Fewer than or equal to n” is possible by negating n and reinstating the :first-child condition.


li:nth-last-child(-n+6):first-child,
li:nth-last-child(-n+6):first-child ~ li {
  /* properties here */
}

In effect, the use of “-” switches the direction of the selection: instead of pointing toward the start from the sixth, it points toward the end from the sixth. In each case, the selector is inclusive of the sixth item.

nth-child versus nth-of-type

Note that I am using :nth-child() and :nth-last-child() in the preceding examples, not :nth-of-type() and :nth-last-of-type(). Because I am dealing in <li> elements and <li>s are the only legitimate children of <ul>s, :last-child() and :last-of-type() would both work here.

The :nth-child() and :nth-of-type() families of selectors have different advantages depending on what you are trying to achieve. Because :nth-child() is element agnostic, you could apply the described technique across different element type siblings:


<div class="container">

  <p>...</p>

  <p>...</p>

  <blockquote>...</blockquote>

  <figure>...</figure>

  <p>...</p>

  <p>...</p>

</div>


.container > :nth-last-child(n+3),
.container > :nth-last-child(n+3) ~ * {
  /* properties here */
}

(Note how I am using the universal selector to maintain element agnosticism here. :last-child(n+3) ~ * means “any element of any type following :last-child(n+3).”)

The advantage of :nth-last-of-type(), on the other hand, is that you are able to target groups of like elements where other siblings of different types are present. For example, you could target the quantity of paragraphs in the following snippet, despite them being bookended by a <div> and a <blockquote>.


<div class="container">

  <div>...</div>

  <p>...</p>

  <p>...</p>

  <p>...</p>

  <p>...</p>

  <p>...</p>

  <p>...</p>

  <p>...</p>

  <blockquote>...</blockquote>

</div>


p:nth-last-of-type(n+6),
p:nth-last-of-type(n+6) ~ p {
  /* properties here */
}

Selector support

All of the CSS2.1 and CSS3 selectors used in this article are supported in Internet Explorer 9 and above, including all reasonably recent mobile/handheld stock browsers.

Internet Explorer 8 support is good for most selector types, but technically partial, so you might want to consider a JavaScript polyfill. Alternately, you could pair the selectors for the “safer” of the layout strategies with IE9-specific classes. In the case of the navigation menu, the safer option is the one catering to more items, using inline-block. The declaration block would look something like this:


nav li:nth-last-child(n+6),
nav li:nth-last-child(n+6) ~ li, 

.lt-ie9 nav li {
  display: inline-block;
  /* etc */
}

In the real world

Suppose our navigation menu belongs to a content-managed site. Depending on who is administering the theme, it will be populated with a greater or fewer number of options. Some authors will keep things simple with just “Home” and “About” links provided, while others will cram their menu full of custom page and category options.

By providing alternative layouts depending on the number of menu items present, we increase the elegance with which we tolerate different implementations of the theme: we address variable content as we might variable screen dimensions.

Comparing the initial menu bar layout for fewer than six items with the layout for six or more items

So, there you have it: squid ahoy! You can now add quantity as a styling condition to your repertoire.

Content-independent design

Responsive web design solves an important problem: it makes the same content comfortably digestible between different devices. For folks to receive different content just because they have different devices would be unacceptable. Similarly, it’s unacceptable for a design to dictate the nature of the content. We wouldn’t tell an editor, “Lose that, will you? It makes the design look wrong.”

But what form the content takes, and how much of it there is at any one time, is frequently indeterminate—another unknown. And we can’t always rely on text wrapping and truncation scripts. To get a real handle on content independence, we need to develop new tools and techniques. Quantity queries are just one idea.

Web design is about mutability, difference, uncertainty. It’s about not knowing. Uniquely, it is a mode of visual design not about manifesting a form, but about anticipating the different forms something might take. To some it is unbearably perplexing, but to you and me it is a challenge to relish. Like the elusive giant squid, it is a seriously slippery customer.