A Comprehensive Guide To Web Design

(This is a sponsored post). Web design is tricky. Designers and developers have to take a lot of things into account when designing a website, from visual appearance (how the website looks) to functional design (how the website works). To simplify the task, we’ve prepared this little guide.

In this article, I’ll focus on the main principles, heuristics, and approaches that will help you to create a great user experience for your website. I’ll start with global things like the user journey (how to define the “skeleton” of the website) and work down to the individual page (what should be considered during web page design). We’ll also cover other essential aspects of design, such as mobile considerations and testing.

Designing The User Journey

Information Architecture

People often use the term “information architecture” (IA) to mean the menus on a website. But that’s not correct. While menus are a part of IA, they are only one aspect of it.

IA is all about the organization of information in a clear and logical way. Such organization follows a clear purpose: helping users to navigate a complex set of information. Good IA creates a hierarchy that aligns with user’s expectations. But good hierarchy and intuitive navigation don’t happen by chance. They are a result of proper user research and testing.

There are a number of ways to research user needs. Often, an information architect will take an active part in user interviews or card sorting, where they would hear of user expectations directly or see how prospective users would categorize a variety of information groups. Information architects also need access to the results of usability tests to see whether users are able to navigate efficiently.

Card sorting is a simple way to figure out how best to group and organize content based on user input. One of the reasons why information architects like card sorting is because of the clarity of patterns that typically emerges. (Image credit: FosterMilo)

A menu structure would be created based on the results of user interviews, and card sorting would be tested for whether it satisfies the user’s mental model. UX researchers use a technique called “tree testing” to prove that it will work. This happens before designing the actual interface.

Tree testing is a reliable method of finding whether users can work with the proposed menu structure. (Image credit: Nielsen Norman Group) (View large version)

Global Navigation

Navigation is a cornerstone of usability. It doesn’t matter how good your website is if users can’t find their way around it. That’s why navigation on your website should adhere to a few principles:

  • SimplicityNavigation should be designed in a way that gets visitors where they want to go with the fewest clicks possible.
  • ClarityThere shouldn’t be any guessing about what each navigation option means. Every navigation option should be self-evident to visitors.
  • ConsistencyThe navigation system should be the same for all pages on the website.

Consider a few things when designing navigation:

  • Select a navigation pattern based on the user’s needs.Navigation should accommodate the needs of the majority of your app’s users. A given target group expects a particular type of interaction with your website, so make these expectations work in your favor. For example, avoid hamburger-menu navigation if the majority of your users aren’t familiar with the meaning of the icon itself.
  • Prioritize navigation options.One simple way to prioritize navigation options is to assign different priority levels (high, medium, low) to common user tasks, and then give prominence in the layout to paths and destinations with high priority levels and frequent use.
  • Make it visible.As Jakob Nielsen says, recognizing something is easier than remembering it. Minimize the user’s memory load by making all important navigation options permanently visible. The most important navigation options should be available at all times, not just when we anticipate that the user will need them.
  • Communicate the current location.“Where am I?” is a fundamental question to which users need an answer in order to effectively navigate. Failing to indicate the current location is a common problem on many websites. Think about location indicators.

Links and Navigation Options

Links and navigation options are key factors in the navigation process and have a direct effect on the user journey. Follow a few rules with these interactive elements:

  • Recognize the difference between internal and external links.Users expect different behavior for internal and external links. All internal links should open in the same tab (this way, you’ll allow users to use the “back” button). If you decide to open external links in a new window, you should provide an advanced warning before automatically opening a new window or tab. This might take the form of text added to the link text stating “(opens in a new window)”.
  • Change the color of visited links.When visited links don’t change color, users could unintentionally revisit the same pages.
Knowing which pages they’ve visited keeps the user from unintentionally revisiting the same pages.
  • Double-check all links.A user can easily get frustrated by clicking a link and getting a 404 error page in response. When a visitor is searching for content, they expect every link to take them where it says it will, not to a 404 error page or another place they weren’t expecting.
(View large version)

“Back” Button in Browser

The “back” button is perhaps the second-most popular UI control in the browser (after the URL input field). Make sure the “back” button works according to user expectations. When a user follows a link on a page and then clicks the “back” button, they expect to return to the same spot on the original page. Avoid situations in which clicking “back” brings the user to the top of the initial page, instead of where they left off, especially on pages. Losing their spot forces the user to scroll through content they have already seen. It’s no surprise that users get frustrated quickly with no proper “back to position” functionality.

Breadcrumbs

Breadcrumbs are a set of contextual links that function as a navigation aid on websites. It’s a secondary navigation scheme that usually shows the user’s location on a website.

While this element doesn’t require a lot of explanation, a few things are worth mentioning:

  • Don’t use breadcrumbs as a substitute for primary navigation.The main navigation should be the element that leads the user, whereas breadcrumbs should only support the user. Relying on breadcrumbs as a primary method of navigation, rather than an extra feature, is usually an indication of poor navigation design.
  • Use arrowheads, not slashes, as separators. Separate each level clearly.A more-than sign (>) or right-pointing arrow (→) is recommended, because these symbols signal direction. A forward slash (/) isn’t recommended as a separator for e-commerce websites. If you’re going to use it, be certain that no product category will ever use a slash:
Distinguishing between different levels of this breadcrumb trail is hard. (View large version)

Search

Some users come to a website looking for one particular item. They don’t want to use the navigation options. They want to type text in a search box, submit their search query and find the page they’re looking for.

Take these few basic rules into account when designing the search box:

  • Put the search box where users expect to find it.The chart below was created based on a study by A. Dawn Shaikh and Keisi Lenz. It shows the expected location of the search field, according to a survey of 142 participants. The study found that the most convenient spot is the top left or top right of every page on a website. Users can easily find it using the common F-shaped scanning pattern.

  • Display search prominently on content-rich websites.

    If search is an important function on your website, display it prominently, because it can be the fastest route to discovery for users.
  • Size the input box appropriately.

    Making the input field too short is a common mistake among designers. Of course, users can type a long query into a short field, but only a portion of the text will be visible at a time, which is bad for usability because seeing the entire query at once won’t be possible. In fact, when a search box is too short, users are forced to use short, imprecise queries, because longer queries would be hard and inconvenient to read. Nielsen Norman Group recommends a 27-character input field, which would accommodate 90% of queries.
  • Put the search box on every page.

    Show the search box on every page, because if users cannot navigate to the content they are looking for, they will try to use search regardless of where they are on the website.
  • Designing Individual Pages

    Content Strategy

    Perhaps the most important thing about content strategy is to focus the design on page objectives. Understand the goal of the page, and write content according to the goal.

    Here are a few practical tips to improve content comprehension:

    • Prevent information overload.Information overload is a serious problem. It prevents users from making decisions or taking action because they feel they have too much information to consume. There are some simple ways to minimize information overload. One common technique is chunking — breaking content into smaller chunks to help users understand and process it better. A checkout form is a perfect example. Display at most five to seven input fields at a time, and break down the checkout into pages, progressively disclosing fields as necessary.
    (Image credit: Witteia) (View large version)
    • Avoid jargon and industry-specific terms.Each unknown term or phrase that appears on the page will increase the cognitive load on users. A safe bet is to write for all levels of readers, and pick words that are clearly and easily understandable to all groups of users.
    • Minimize long content sections with a lot of detail.In line with the point about information overload, try to avoid long blocks of text if the website isn’t geared to major information consumption. For example, if you need to provide details about a service or product, try to reveal details step by step. Write in small, scannable segments to facilitate discovery. According to Robert Gunning’s book “How to Take the Fog Out of Business Writing”, for comfortable reading, most sentences should be 20 words or less.
    (Image credit: The Daily Rind)
    • Avoid capitalizing all letters.All-caps text — that is, text with all letters cap­i­tal­ized — is fine in tiny doses, such as for acronyms and logos. However, avoid all caps for anything longer (such as paragraphs, form labels, errors, notifications). As mentioned by Miles Tinker in his book Legibility of Print, all caps dramatically reduces the speed of reading. Also, most readers find all capitals to be less legible.
    Text in all caps is hard for users to read.

    Page Structure

    A properly structured page makes it clear where each user interface element is located in the layout. While there are no one-size-fits-all rules, there are a few guidelines that will help you create a solid structure:

    • Make the structure predictable.Align your design to user expectations. Consider websites from a similar category to find out which elements to use on the page and where. Use patterns that your target audience is familiar with.
    • Use a layout grid.A layout grid divides a page into major regions, and defines the relationships between elements in terms of size and position. With the help of a grid, combining different parts of a page together in a cohesive layout becomes much easier.
    Grids and layout systems are part of the heritage of design and are still relevant in a multi-screen world. Adobe XD’s layout grids enable designers to achieve consistent, organized designs for different screen sizes and to manage the proportions between elements with customized grids.
    • Use a low-fidelity wireframe to cut out clutter.Clutter overloads an interface and reduces comprehension. Every added button, image and line of text makes the screen more complicated. Before building the page with real elements, create a wireframe, analyze it, and get rid of anything that isn’t absolutely necessary.
    A low-fidelity wireframe created in Adobe XD (Image credit: Tim Hykes) (View large version)

    Visual Hierarchy

    People are more likely to quickly scan a web page than to read everything there. Therefore, if a visitor wants to find content or complete a task, they are going to scan until they find where they need to go. You, as a designer, can help them with that by designing good visual hierarchy. Visual hierarchy refers to the arrangement or presentation of elements in a way that indicates importance (that is, where their eyes should focus first, second, etc.). A proper visual hierarchy makes it easy to scan the page.

    • Use natural scanning patterns.As designers, we have a lot of control over where people look when they’re viewing a page. To set the right path for the visitor’s eyes to follow, we can use two natural scanning patterns: the F-shaped pattern and the Z-shaped pattern. For text-heavy pages, such as articles and search results, the F pattern is better, whereas the Z pattern is good for pages that aren’t text-oriented.
    An F-shaped pattern is used by CNN. (View large version)
    A Z-scanning pattern is used by Basecamp. (View large version)
    • Visually prioritize important elements.Make screen titles, log-in forms, navigation options and other important content focal points, so that visitors see them right away.
    The “Learn More About Brains” call to action stands out. (View large version)
    • Create mockups to clarify the visual hierarchy.Mockups enable designers to see what a layout will look like when it’ll have a real data. Rearranging elements in a mockup is much easier than doing it when the developer is building the web page.
    A mockup created using Adobe XD. (Image credit: Coursetro) (View large version)

    Scrolling Behavior

    A persistent myth among web designers is that people don’t scroll. To be clear: Today, everybody scrolls!

    Improving scrolling behavior is possible with a few tips:

    • Encourage users to scroll.Despite the fact that people usually start scrolling as soon as the page loads, content at the top of the page is still very important. What appears at the top sets the impression and expectation of quality for visitors. People do scroll, but only if what’s above the fold is promising enough. Thus, put your most compelling content at the top of the page:
      • Offer a good introduction.An excellent introduction sets the context for the content and answers the user’s question, “What’s this page about?”
      • Use engaging imagery.Users pay close attention to images that contain relevant information.
    • Persist navigation options.When you create lengthy pages, keep in mind that users still require a sense of orientation (of their current location) and a sense of navigation (other possible paths). Long pages can make navigation problematic for users; if the top navigation bar loses visibility when the user scrolls down, they will have to scroll all the way back up when they’re deep within the page. The obvious solution to this is a sticky menu that shows the current location and that remains on screen in a consistent area at all times.
    Scroll-activated sticky navigation (Image: Zenman)
    • Provide visual feedback when loading new content.This is especially important for web pages where content loads dynamically (such as news feeds). Because content-loading during scrolling is supposed to be fast (it shouldn’t take longer than 2 to 10 seconds), you can use looped animation to indicate that the system is working.
    Subtle animation (such as Tumblr’s loading indicator) tells the user that more content is being loaded.
    • Don’t hijack scrolling.Hijacked scrolling is one of the most annoying things because it takes control away from the user and makes the scrolling behavior completely unpredictable. When you design a website, let the user control their browsing and movement through the website.
    Tumbler’s signup page uses scroll hijacking.
    Tumbler’s signup page uses scroll hijacking. (View large version)

    Content Loading

    Content loading is worth additional clarification. While an instant response is best, there are occasions when your website will need more time to deliver content to visitors. A bad Internet connection could cause a slow reaction, or an operation could take a bit more time to complete. But no matter the cause of such behavior, your website should appear fast and responsive.

    • Make sure regular loading doesn’t take long.The attention span and patience of web users is very low. According to Nielsen Norman Group research, 10 seconds is about the limit for keeping the user’s attention on a task. When visitors have to wait for a website to load, they will become frustrated and likely leave if the website doesn’t load quickly enough for them. Even with the most beautifully designed loading indicator, users will still leave if loading takes too long.
    • Use skeleton screens during loading.Many websites use progress indicators to show that data is loading. While the intention behind a progress indicator is good (providing visual feedback), the result can be negative. As Luke Wroblewski mentions, “Progress indicators by definition call attention to the fact that someone needs to wait. It’s like watching the clock tick down — when you do, time seems to go slower.” There is an excellent alternative to progress indicators: skeleton screens. These containers are essentially a temporarily blank version of the page, into which information is gradually loaded. Rather than showing a loading indicator, designers can use a skeleton screen to focus users’ attention on actual progress and create anticipation for what’s to come. This creates a sense that things are happening immediately, as information is incrementally displayed on the screen and people see that the website is acting while they wait.
    Facebook uses skeleton screens to fill out the UI as content is loaded incrementally. (View large version)

    Buttons

    Buttons are vital to creating a smooth conversational flow. It’s worth paying attention to these basic best practices for buttons:

    • Ensure that clickable elements look like ones.With buttons and other interactive elements, think about how the design communicates affordance. How do users understand the element as a button? Form should follow the function: the way an object looks tells users how to use it. Visual elements that look like links or buttons but aren’t clickable (such as underlined words that aren’t links or elements that have a rectangular background but aren’t buttons) can easily confuse users.
    Is the orange box in the top-left corner of the screen a button? No, but the shape and label make the element look like one. (View large version)
    • Label buttons according to what they do.The label on any actionable interface element should always tie back to what it will do for the user. Users will feel more comfortable if they understand what action a button does. Vague labels such as “Submit” and abstract labels like in the example below don’t provide enough information about the action.
    Don’t make people wonder what an interface element does. (Image credit: UX Matters)
    • Design buttons consistently.Users remember details, whether consciously or not. When browsing a website, they’ll associate a particular element’s shape with button functionality. Therefore, consistency will not only contribute to a great-looking design, but will also make the experience more familiar to users. The image below illustrates this point perfectly. Using three different shapes in one part of an app (such as the system toolbar) is not only confusing, but sloppy.
    Strive for consistency.

    Imagery

    As the saying goes, a picture is worth a thousand words. Human beings are highly visual creatures, able to process visual information almost instantly; 90% of all information that we perceive and that gets transmitted to our brains is visual. Images are a powerful way to capture the user’s attention and to differentiate a product. A single image can convey more to the viewer than an elaborately designed block of text. Furthermore, images cross language barriers in a way that text simply can’t.

    The following principles will help you integrate imagery in your web design:

    • Make sure images are relevant.One of the biggest dangers in design is imagery that conveys the wrong message. Select images that strongly support your product goals, and ensure that they are relevant to the context.
    Images that aren’t related to the topic will cause confusion. (View large version)
    • Avoid generic photos of people.Using human faces in design is an effective way to engage users. Seeing faces of other humans makes viewers feel like they are connecting with them, and not just being sold a product. However, many corporate websites are notorious for using generic stock photos to build a sense of trust. Usability tests show that such photos rarely add value to the design and more often impair rather than improve the user experience.
    Inauthentic images leave the user with a sense of shallow, false pretence. (View large version)
    • Use high-quality assets with no distortion.The quality of assets of your website will have a tremendous impact on the user’s impression and expectations of your service. Make sure images are appropriately sized for displays across all platforms. Images shouldn’t appear pixelated, so test resolution sizes for various ratios and devices. Display photos and graphics in their original aspect ratio.
    A degraded image versus a properly sized image (Image credit: Adobe) (View large version)

    Video

    With increasing Internet speeds, videos are becoming more popular, especially considering that they extend time spent on site. Today, video is everywhere. We’re watching it on our desktops, tablets and phones. When used effectively, video is one of the most powerful tools available for engaging an audience — it conveys more emotion and really gives people a feel for a product or service.

    • Set audio to off by default, with the option to turn it on.When users arrive on a page, they don’t expect that it will play any sound. Most users don’t use headphones and will be stressed because they’ll need to figure out how to turn the sound off. In most cases, users will leave the website as soon as it plays.
    Facebook videos play automatically as soon as the user reaches them, but no sound plays unless the user enables it. (View large version)
    • Keep promo video as short as possible.According to the research by D-Mak Productions, short videos are more appealing to the majority of users. Thus, keep business videos in the range of two to three minutes.
    (Image credit: Dmakproductions)
    • Provide an alternative way to access content.If a video is the only way to consume content, this can limit access to the information for anyone who cannot see or hear the content. For accessibility, include captions and a full transcript of the video.
    Subtitles and transcript will make video content more accessible. (Image credit: TED) (View large version)

    Call-to-Action Buttons

    Calls to action (CTA) are buttons that guide users towards your conversion goal. The whole point of a CTA is to direct visitors to a desired course of action. Some common examples of CTAs are:

    • “Start a trial”
    • “Download the book”
    • “Sign up for updates”
    • “Get a consultation”

    Take a few things into account when designing CTA buttons:

    • SizeThe CTA should be large enough to see from a distance, but not so large as to detract attention from other content on the page. To confirm that your CTA is the most prominent element on the page, try the five-second test: View a web page for five seconds and then write down what you remember. If the CTA is on your list, then congrats! It’s sized appropriately.
    • Visual prominenceThe color you choose for CTAs has a tremendous impact on whether it will be noticeable. With color, you can make certain buttons stand out more than others by giving them more visual prominence. Contrasting colors work best for CTAs and make for striking buttons.
    The green of the CTA on Firefox’s page jumps off the page and immediately gets the user’s attention. (View large version)
    • Negative spaceThe amount of space around a CTA is important, too. White (or negative) space creates essential breathing room and separates a button from other elements in the interface.
    The previous version of Dropbox’s home page has a good example of using negative space to make the primary CTA pop. The blue “Sign up for free” CTA stands out against the light blue of the background. (View large version)
    • Action-oriented textWrite text for the button that will compel visitors to take action. Begin with a verb like “Start,” “Get” or “Join.”
    Evernote has one of the most common yet still effective action-oriented texts for its CTA. (View large version)

    Tip: You can quickly test a CTA using a blur effect. A blur test is a quick technique to determine whether the user’s eye will go where you want it to go. Take a screenshot of your page and apply a blur effect in Adobe XD (see the example on Charity Water below). Looking at the blurred version of your page, which elements stand out? If you don’t like what’s being projected, revise.

    A blur test is a technique to reveal a design’s focal point and visual hierarchy. (View large version)

    Web Forms

    Filling a form remains one of the most important types of interaction for users on the web. In fact, a form is often considered the final step in the completion of a goal. Users should be able to complete forms quickly and without confusion. A form is like a conversation, and like any conversation, there should be logical communication between two parties: the user and the website.

    • Ask only what’s required.Ask for only what you really need. Every extra field you add to a form will affect its conversion rate. Always think about why you’re requesting certain information from users and how you will be using it.
    • Order the form logically.Questions should be asked logically from the user’s perspective, not from the application or database’s perspective. For example, asking for someone’s address before their name would be incorrect.
    • Group related fields together.Group related information into logical blocks or sets. The flow from one set of questions to the next will better resemble a conversation. Grouping related fields together also helps the user make sense of the information.
    Group related fields together. (Image: Nielsen Norman Group)

    Animation

    More and more designers are incorporating animation as a functional element to enhance the user experience. Animation is no longer just for delight; it is one of the most important tools for effective interaction. However, animation in design can enhance the user experience only if it’s incorporated at the right time and place. Good UI animation has a purpose; it is meaningful and functional.

    Here are a few cases in which animation can enhance the experience:

    • Visual feedback on user actionGood interaction design provides feedback. Visual feedback is helpful when you need to inform users about the result of an operation. In case an operation isn’t performed successfully, functional animation can provide information about the problem in a fast and easy way. For example, a shake animation can be used when a wrong password is entered. It’s easy to understand why the shake is a fairly universal gesture to communicate “no,” because a simple head shake is so prevalent in interpersonal communication.
    Users will see this animation and immediately understand the problem. (Image credit: The Kinetic UI)
    • Visibility of system statusOne of Jakob Nielsen’s 10 heuristics for usability, visibility of system status remains among the most important principles in user interface design. Users want to know their current context in a system at any given time, and an app shouldn’t keep them guessing — it should tell the user what’s happening via appropriate visual feedback. Data uploading and downloading operations are great opportunities for functional animation. For example, an animated loading bar shows how fast a process is going and sets an expectation for how fast the action will be processed.
    (Image credit: xjw)
    • Navigational transitionsNavigational transitions are movements between states on a website — for example, from a high-level view to a detailed view. State changes often involve hard cuts by default, which can make them difficult to follow. Functional animation eases users through these moments of change, smoothly transporting users between navigational contexts and explaining changes on the screen by creating visual connections between states.
    (Image credit: Ramotion)
    • BrandingSuppose you have dozens of websites that have the same exact features and help users to accomplish the same tasks. They might all offer a good user experience, but the one that people really love offers something more than just a good user experience. It establishes an emotional connection with users. Branding animation plays a key role in engaging users. It can support a company’s brand values, highlight a product’s strengths and make the user experience truly delightful and memorable.
    (Image credit: Heco)

    Mobile Considerations

    Today, almost 50% of users access the web from mobile devices. What does this mean for us web designers? It means that we must have a mobile strategy for every website we design.

    Practice Responsive Web Design

    It’s essential to optimize your website for the vast landscape of desktop and mobile browsers, each of which has a different screen resolution, supported technologies and user base.

    • Aim for a single-column layout.Single-column layouts usually work best on mobile screens. Not only does a single column help with managing the limited space on a small screen, but it also easily scales between different device resolutions and between portrait and landscape mode.
    • Use the Priority+ pattern to prioritize navigation across breakpoints.Priority+ is a term coined by Michael Scharnagl to describe navigation that exposes what’s deemed to be the most important elements and hides away less important items behind a “more” button. It makes use of available screen space. As space increases, the number of exposed navigation options increases as well, which can result in better visibility and more engagement. This pattern is especially good for content-heavy websites with a lot of different sections and pages (such as a news website or a large retailer’s store). The Guardian makes use of the Priority+ pattern for its section navigation. Less important items are revealed when the user hits the “All” button.
    The Guardian employs the Priority+ pattern for its section navigation. (Image credit: Brad Frost)
    • Make sure images are sized appropriately for displays and platforms.A website must adapt to look perfect on all of the different devices and in all of the various resolutions, pixel densities and orientations. Managing, manipulating and delivering images is one of the main challenges web designers face when building responsive websites. To simplify this task, you can use tools such as Responsive Image Breakpoints Generator to generate breakpoints for images interactively.
    Responsive Image Breakpoints Generator helps you to manage multiple sizes of images, enabling you to generate responsive image breakpoints interactively. (View large version)

    Going From Clickable to Tappable

    On the mobile web, interaction is done via finger taps, not mouse clicks. This means that different rules apply when you’re designing touch targets and interactions.

    • Properly sized touch targets.All interactive element (such as links, buttons and menus) should be tappable. While the desktop web lends itself well to links whose active (i.e. clickable) area is small and precise, the mobile web requires larger, chunkier buttons that can be easily pressed with a thumb. When a tap is used as a primary input method for your website, refer to the MIT Touch Lab’s study to choose a proper size for your buttons. The study found that the average size of finger pads are between 10 and 14 millimeters and that fingertips range from 8 to 10, making 10 × 10 millimeters a good minimum touch target size.
    Smaller touch targets are harder for users to tap than larger ones. (Image credit: Apple)
    • Stronger visual signifiers of interactivity.On the mobile web, there is no hover state. While on a desktop, it’s possible to provide additional visual feedback when a user hovers the mouse over an element (for example, revealing a dropdown menu), a mobile user would have to tap to see that response. Thus, users should be able to correctly predict how an interface element will behave just by looking at it.

    Accessibility

    Today’s products must be accessible to everyone, regardless of a person’s abilities. Designing for users with impairments is one way that designers can practice empathy and learn to experience the world from someone else’s perspective.

    Users With Poor Eyesight

    A lot of websites use low contrast for text copy. While low-contrast text may be trendy, it’s also illegible and inaccessible. Low contrast is especially problematic for users with low vision and who struggle with contrast sensitivity.

    Gray text on a light-gray background is hard to read. The experience will be far from good, and the design simply won’t work. (View large version)

    Low-contrast text is hard to read on a desktop, but it becomes even more difficult on mobile. Imagine trying to read low-contrast text on a mobile device while walking in bright sunlight. This is a good reminder that accessible visual design is better visual design for all users.

    Never sacrifice usability for beauty. The most important characteristic of text and other vital elements on a website is readability. Readability requires sufficient contrast between text and background. To ensure that text is readable by people with visual impairments, the W3C’s Web Content Accessibility Guidelines (WCAG) has a contrast-ratio recommendation. The following contrast ratios are recommended for body text and image text:

    • Small text should have a contrast ratio of at least 4.5:1 against its background. A ratio of 7:1 is preferable.
    • Large text (at 14-point bold and 18-point regular and up) should have a contrast ratio of at least 3:1 against its background.
    Bad: These lines of text do not meet the color-contrast ratio recommendations and are difficult to read against their background.
    Good: These lines of text follow the color-contrast ratio recommendations and are legible against their background.

    You can use WebAIM’s Color Contrast Checker to quickly find out whether you’re within the optimal range.

    (View large version)

    Color Blind Users

    It’s estimated that 4.5% of the global population experience color blindness (that’s 1 in 12 men and 1 in 200 women), 4% suffer from low vision (1 in 30 people), and 0.6% are blind (1 in 188 people). It’s easy to forget that we design for this group of users because most designers don’t experience such problems.

    To make design accessible for these users, avoid using color alone to convey meaning. As the W3C states, color shouldn’t be used “as the only visual means of conveying information, indicating an action, prompting a response, or distinguishing a visual element.”

    One common example where color is used as the sole means of conveying information is alerts in forms. Success and error messages are often colored green and red, respectively. But red and green are the colors most affected by color-vision deficiency — these colors can be difficult to distinguish for people with deuteranopia or protanopia. Most probably, you’ve seen error messages like, “The fields marked in red are required.” While it might not seem like a big deal, this error message appearing in a form like the one below can be extremely frustrating for people with a color-vision deficiency. Designers should use color to highlight or complement what is already visible.

    Bad: This form relies only on red and green to indicate fields with and without errors. Color-blind users wouldn’t be able to identify the fields in red.

    In the form above, the designer should give more specific instruction, like, “The email address you entered is not valid.” Or at least display an icon near the field that requires attention.

    Good: Icons and labels show which fields are invalid, better communicating the information to a color-blind user.

    Blind Users

    Images and illustrations are a significant part of the web experience. Blind people use assistive technologies such as screen readers to interpret websites. Screen readers “read” images by relying on alternative text attributed to the image. If that text is not present or is not descriptive enough, they won’t be able to get the information as intended.

    Consider two examples — first, Threadless, a popular t-shirt store. This page doesn’t say much about the item being sold. The only text information available is a combination of price and size.

    (View large version)

    The second example is from ASOS. This page, selling a similar shirt, provides accurate alternative text for the item. This helps people who use screen readers to envision what the item looks like.

    When creating text alternatives for images, follow this guideline:

    • All “meaningful” images require descriptive alternative text. (A “meaningful” photo adds context to the information being conveyed.)
    • A text alternative isn’t needed if an image is purely decorative and provides no useful information to the user to aid them in understanding the content of the page.

    Keyboard-Friendly Experience

    Certain users navigate the Internet using their keyboard, rather than a mouse. For example, people with motor impairments have difficulty with the fine motor movements required for using a mouse. Make interactive and navigation elements easily accessible to this group of users by enabling interactive elements to be focused with the Tab key and by displaying a keyboard-focus indicator.

    Here are the most basic rules for keyboard navigation:

    • Check that keyboard focus is visible and obvious.Some web designers remove the keyboard focus indicator because they think it’s an eyesore. This hinders keyboard users from properly interacting with the website. If you don’t like the default indicator provided by the browser, don’t remove it altogether; instead, design it to satisfy your taste.
    • All interactive elements should be accessible.Keyboard users must be able to access all interactive elements, not just the main navigation options or primary calls to action.

    You can find detailed requirements for keyboard interaction in the “Design Patterns and Widgets” section of the W3C’s “WAI-ARIA Authoring Practices” document.

    Testing

    Iterative Testing

    Testing is an essential part of the UX design process. And like any other part of the design cycle, it is an iterative process. Gather feedback early on in the design process, and iterate throughout.

    (Image credit: Extreme Uncertainty) (View large version)

    Test Page-Loading Time

    Users hate slow-loading web pages. That’s why response time is a critical factor on modern websites. According to Nielsen Norman Group, there are three response-time limits:

    • 0.1 secondThis feels instant for users.
    • 1 secondThis keeps the user’s flow of thought seamless, but the user will sense a slight delay.
    • 10 secondsThis is about the limit for keeping the user’s attention focused on the operation. A 10-second delay will often make users leave the website immediately.

    Obviously, we shouldn’t make users wait 10 seconds for anything on our websites. But even a few seconds of delay, which happens regularly, makes an experience unpleasant. Users will be annoyed with having to wait for the operation.

    What usually causes slow loading time?

    • Heavy content objects (such as embedded video and slideshow widgets),
    • Unoptimized back-end code,
    • Hardware-related issues (infrastructure that doesn’t allow for fast operations).

    Tools like PageSpeed Insights will help you to find the causes of slow times.

    A/B Testing

    An A/B test is ideal when you’re struggling to choose between two versions of a design (such as an existing version and a redesigned version of a page). This testing method consists of showing one of two versions randomly to an equal number of users and then reviewing analytics to see which version accomplished your goal more effectively.

    (Image credit: VWO)

    Developer Handoff

    A UX design process has two important steps: prototyping the design and developing a working solution. The step that connects the two is called a handoff. As soon as the design is finalized and ready to be moved to development, designers prepare a specification, which is a document that describes how the design should be coded. A specification ensures that the design will be implemented according to the original intention.

    Precision in the specification is critical because, with an inaccurate specification, the developers will have to either rely on guesswork when building the website or go back to the designer to get answers to their questions. But assembling a specification manually can be a headache and usually takes significant time, depending on the complexity of the design.

    With Adobe XD’s design specs feature (in beta), designers can publish a public URL for developers to inspect flows, grab measurements and copy styles. Designers no longer have to spend time authoring specifications to communicate positioning, text styles or fonts to the developer.

    Adobe XD’s design specs feature (in beta)

    Conclusion

    As with any aspect of design, the tips shared here are just a start. Mix and match these ideas with your own for best results. Treat your website as a continually evolving project, and use analytics and user feedback to constantly improve the experience. And remember that design isn’t just for designers — it’s for users.

    This article is part of the UX design series sponsored by Adobe. Adobe XD tool is made for a fast and fluid UX design process, as it lets you go from idea to prototype faster. Design, prototype and share — all in one app.You can check out more inspiring projects created with Adobe XD on Behance, and also sign up for the Adobe experience design newsletter to stay updated and informed on the latest trends and insights for UX/UI design.

    Smashing Editorial(ra, ms, al, il)

    Monthly Web Development Update 11/2017: Browser News, KRACK and Vary Header Caching

    Editor’s Note: Our dear friend Anselm Hannemann summarizes what happened in the web community in the past few weeks in one handy list, so that you can catch up on everything new and important. Enjoy!

    Welcome back to our monthly reading list. Before we dive right into all the amazing content I stumbled upon — admittedly, this one is going to be quite a long update — I want to make a personal announcement. This week I launched a personal project called Colloq, a new conference and event service for users and organizers. If you’re going to events or are organizing one or if you’re interested in the recorded content of conferences, this could be for you. So if you like, go ahead and check it out.

    In this issue, we’ll focus on some usually rather underaddressed things, such as numerals in web typography, variable fonts, or the image async attribute that’s coming to Chrome soon. So without further ado, let’s get started.

    News

    • WebKit just got support for the Touch Bar Web API that will make use of the menuitem. It’s still in WebKit trunk currently and likely to land in Safari next year at the earliest.
    • Chrome 62 was released this week with some important updates to the Network Information API that now reflects the actual connection type even when tethering. Support for OpenType Variable Fonts and Media Capture from DOM elements also landed in the new version. Notably, Chrome 62 on iOS got support for the Payment Request API which is interesting because the iOS WebKit doesn’t support it yet in stable channel. It seems that they used a custom extension to support this feature. Might get interesting to see what else could be supported this way.
    • This week’s Safari Technology Preview 42 brings along font-display loading behaviors and <link rel=preconnect> support.
    • With the new Windows 10 fall update, Edge 16 is pushed to customers — with full CSS Grid support, object-fit and object-position, the Payment Request API, Service Worker preview behind flags, and Motion Controllers in WebVR.
    Motion controllers in Edge
    WebVR for Edge has added support for motion controllers that allow for fine grained interaction with digital objects in virtual reality. (Image credit)

    General

    UI/UX

    • Right-to-left development is quite hard already but designing for mobile design is a challenge.
    • Inter UI is a nice, completely free to use open-source font family optimized for screen readability.
    • Adobe announced the first stable version of their screen design tool XD at this year’s MAX conference. Besides a lot of smaller improvements, XD now supports sharing, as well as first-class integrations of third-party tools like Zeplin and Sympli. Apart from that, Adobe provided major updates for nearly all their software products during the event.
    • InVision had a big announcement to make this week: They are going to bring a new screen design tool called “Studio” to the market in January and now invite beta testers to preview it.
    Studio
    InVision announced Studio, a new screen design tool that will be released publicly in January. (Image credit)

    Web Performance

    • Vlad Krasnov got the chance to compare the newest server processors at Cloudflare. The results are pretty interesting: Qualcomm achieves a similar performance as the fastest Intel processors, but it needs about 30% less power, sometimes even less. So while newer Qualcomm chips might have some issues with software incompatibilities, it’s going to be interesting what will happen on the server market. Especially with large data centers in mind where saving energy is quite important — not only because our planet benefits from less power consumption but also because it’s cheaper.
    • David Jonathan Ross compared the file sizes of normal web fonts to a variable font file. Depending on how many font styles are used on a website, you can save 44% with a variable font.
    • Nikita Prokopov shares how one single option that Chrome promoted ruined the performance of his web application.
    • Andrew Betts summed up his knowledge about a great HTTP feature in the article “Understanding The Vary Header”.
    • Chrome is implementing an async attribute for HTMLImageElement and SVGImageElement. It’ll have two states: “On” will indicate that the developer prefers responsiveness and performance over the atomic presentation of image and non-image content, while “off” will indicate that the developer prefers atomic presentation of content over responsiveness.
    • Alexey Ivanov shares how to optimize web servers for high throughput and low latency. But please note: These are small, fine-tuning methods that can be very useful but we should apply them one after another, measure them and then decide if they are useful for the project or not. A thoughtful post that gives us insights into how the Dropbox team improves their edge network servers.

    Tooling

    • Webpack Monitor is a nice dashboard for your JavaScript toolchain. It gives insights into bundle size, the individual parts of the bundle and how the bundle and its size change over time. With tips for optimizing the output, the dashboard is quite useful if you care about reducing the payload for users on your website.
    Webpack Monitor
    Webpack Monitor displays your bundle so you can make informed decisions about your optimizations. (Image credit)

    Security

    • This week, the “KRACK”-attack was widely discussed. It’s effectively breaking WPA2 encryption on most WiFi hardware. But vendors aren’t sleeping, some already updated their systems and offer software updates for the devices which you should patch as soon as possible. One thing to note here is that websites that use HSTS preloading aren’t affected by the issue, which reminds us that we should consider adding this header to our websites.

    Privacy

    Accessibility

    CSS

    • Vincent De Oliveira wrote about the amazing CSS element() function which is only available in Firefox currently (but that might change). Actually, it’s not even a new function, but it allows us to use images from the HTML DOM in our CSS, e.g. for a background-image.
    • Richard Rutter wrote a guide about how to use old-style numerals on the web with the font-variant-numeric CSS property, if available. Proper sub- and superscripts are explained, too, and we can learn when to use which feature for a specific purpose.
    Web typography
    Medieval scribes and Renaissance printers placed notes in the margins rather than at the bottom — no need for superscripts. But how should we handle sub- and superscripts on the web? (Image credit: Einsiedeln, Stiftsbibliothek, Codex 172(1128), via Richard Rutter)

    JavaScript

    Work & Life

    • 200 universities just launched 560 free online courses. Here’s the full list.

    Going Beyond…

    • The Guardian recently published an interesting article called “Ashamed to work in Silicon Valley: how techies became the new bankers”. Seeing that working at tech giants like Facebook is considered negatively by a growing number of people is something I didn’t expect. The article also shares that employees at such companies are even ashamed of their jobs — an interesting change when you remember how most people craved to land a job at one of these companies only until this year.
    • It’s a common question that I’ve asked myself quite often in the past that now has been answered: Electric cars emit significantly fewer greenhouse gases over their lifetimes as diesel engines, as a new study found out. Even when they are powered by the most carbon-intensive energy.
    • A chatbot called DoNotPay has saved motorists millions in parking fines — without charging a cent. Its next target: divorce law. And airlines, landlords, and telemarketers will follow, too, in the future.

    We hope you enjoyed this Web Development Update. The next one is scheduled for December 15th. Stay tuned!

    Using CSS Grid: Supporting Browsers Without Grid

    When using any new CSS, the question of browser support has to be addressed. This is even more of a consideration when new CSS is used for layout as with Flexbox and CSS Grid, rather than things we might consider an enhancement.

    In this article, I explore approaches to dealing with browser support today. What are the practical things we can do to allow us to use new CSS now and still give a great experience to the browsers that don’t support it?

    What Do We Mean By Support?

    Before deciding how you are going to support browsers without grid support, it is worth working out what you mean by support. Support might mean that the site has to look absolutely identical in all the browsers on your list. It might mean that you are happy for some finishing touches not to be available in all browsers. It might mean that you are testing these browsers but are completely happy for them to receive a much simplified experience.

    A linked question is how do you come up with your list of supported browsers? Even for a brand new website, this shouldn’t need to be a guess. For most businesses today, a new website won’t be the first site they have ever built. You probably have some analytics you can look at to see the browsers in use, although you need to take care that they are not skewed by a site that is entirely mobile unfriendly for example. People won’t be visiting the site on mobile if it is impossible to use on a small screen!

    If you don’t have any relevant analytics you can look at data on Can I Use, where you can import the data for your location.

    On the Can I Use website you can import usage data for your location
    On the Can I Use website, you can import usage data for your location. (Large preview)

    It is also worth keeping the site goals in mind here too. For example, a site hoping to attract visitors who live in emerging markets such as India will want to ensure the site works well in browsers used in those countries.

    Is It Just Old Browsers I Should Worry About?

    A the time of writing Edge, Chrome, Firefox, Opera, Safari, iOS Safari all support Grid Layout.

    IE10 and IE11 have support for the original spec with an -ms prefix. In terms of old browsers you are looking at:

    • Internet Explorer 9 (or IE 11 and below if only considering the new spec)
    • Edge 15 and below
    • Firefox older than version 52
    • Safari and iOS Safari older than version 10.1
    • Chrome older than version 57
    • Samsung Internet older than version 6.2

    However, as mentioned in the last section, these popular desktops and mobile browsers are joined by browsers more commonly used in emerging markets. These browsers haven’t yet adopted grid. For example, if we take a worldwide view UC Browser comes in at 8.1% of traffic — the third most popular browser in the world. If you happen to live in the USA or Europe, it’s possible that you may have never heard of it.

    (Image source) (Large preview)

    UC Browser does not support Grid Layout. It is also a browser optimized for lower powered devices, but also for users in areas with expensive, often metered data. This is an important thing to consider as we begin to plan a strategy for support.

    Is There A CSS Grid Polyfill?

    When first encountering CSS Grid, an obvious question is, “Can I use a polyfill?” Unfortunately, a magic polyfill for your entire layout is unlikely to be forthcoming or a great idea to use even if there were such a thing.

    Grid does things that are pretty much impossible with older layout methods. So, in order to replicate Grid in browsers that don’t have support, you would need to do a lot of work in JavaScript. Even on a well-resourced computer, with a fast rendering engine that is likely to give you something of a janky experience as heights are calculated and items positioned. As we already know, the browsers that don’t support grid are older, slower browsers or browsers most often found on lower powered devices in emerging markets. Why would you force a bunch of JavaScript onto those devices?

    Instead of searching for a polyfill, consider how using Grid Layout can actually provide a better experience to those browsers that don’t support it. Grid will allow you to create complex layout experiences for supporting browsers with minimal CSS, while still offering a good experience to those browsers without support. Yes, it will be a little more work than just throwing a polyfill at the problem, but by doing so, you are ensuring that support means providing a good experience, rather than making the site looking the same the most important goal.

    Providing Support For Browsers That Don’t Understand Grid Layout

    So, how do we provide support that is tailored to the device and browser in use? It turns out that CSS has the answers for you.

    Browsers Ignore CSS They Don’t understand

    The first part of the picture is the fact that browsers ignore CSS they don’t understand. If a browser that doesn’t support CSS Grid, comes across the grid-template-columns property, it doesn’t know what it is and so throws that line away and continues.

    This means that you can use some old CSS, for example, floats or display: table-cell to provide a grid type layout for older browsers, just as you would in the past. The browsers that do not support Grid Layout will use this layout and ignore all the grid instructions. Browsers that do support Grid Layout will continue and discover the grid instructions and apply those. At which point we need to consider what happens if an item using another layout method becomes a grid item.

    New Layout Knows About Old Layout

    Defined in the specification is exactly how Grid behaves if you have elements in your page positioned by other layout methods.

    Items that are floated or that use the clear property, which then become a grid item, no longer exhibit any floating or clearing behavior. As if this was never applied. Remove all of the properties applied to the class .grid in this next CodePen, and you can see how we have floated all of the items and cleared the third one. However, once we are in Grid Layout this is ignored.

    See the Pen display: grid overrides float and clear by rachelandrew (@rachelandrew) on CodePen.

    The same is true for inline-block. The value inline-block can be applied to the child item, but as soon as the parent has display: grid the inline-block behaviour will no longer be applied.

    I often use CSS display: table-cell when I need to create a column layout and also align items in non-supporting browsers, as the vertical-align property works when you use display: table-cell.

    If this is new to you, read The Anti-hero of CSS Layout — “display:table”. I wouldn’t suggest you use this today as your main layout method, but it can be very helpful as a fallback.

    When you use display: table-cell to create columns, CSS will create what is known as anonymous boxes. These are the missing parts of the table — a table cell in a real HTML table will be inside a tr element, and that will be inside a table element. The anonymous boxes essentially fix up these missing parents. If your table-cell item becomes a Grid Item however, this happens before the boxes are generated and so once again the item will act as if the CSS tables display had never happened.

    The vertical-align property does not apply once in Grid Layout either and so if you use it in a CSS tables layout or with inline-block you can safely ignore that and use Box Alignment for Grid Layout. You can see a layout that uses display: table-cell and vertical-align overwritten by Grid Layout in this next CodePen.

    See the Pen display: grid overrides display: table-cell, and vertical-align by rachelandrew (@rachelandrew) on CodePen.

    You can also use Flexbox as a fallback, if you have used the flex property or individual flex-grow, flex-shrink or flex-basis properties on the item these will be ignored once it becomes a Grid Item.

    Finally, don’t forget that Multi-column layout can be used in some cases as a fallback. For example, when laying out a list of card components or images. It will display items in columns rather than across the row but in some circumstances can be useful. You apply column-count or column-width on the container to make it a multicolumn container, if you then apply display:grid the column-* behaviour will be ignored.

    Feature Queries

    In the majority of other layout methods, we target the individual items rather than their container. For example in a floated layout, we have a set of items that we have given a percentage width and then set to float: left. This causes them to line up next to each other. As long as we don’t end up with more than a total of 100%, we can make something that looks like a grid.

    .grid > * { float: left; width: 33%;}
    Floating items and giving them a width gives us the appearance of a grid
    Floating items and giving them a width gives us the appearance of a grid. (Large preview)

    If we then turn that layout into a CSS Grid Layout, we create a grid on the parent. The only thing we apply to the items is an instruction as to how many columns to span.

    .grid { display: grid; grid-template-columns: 1fr 1fr 1fr; grid-auto-rows: 100px; grid-gap: 20px;}

    In our old layout we have floated items with a size applied, in our new layout those items become Grid Items, and typically we don’t want to give those items a size, as they will get that information from the grid tracks that they span.

    It is here that we come to an issue with simply being able to override one layout method with another. In the example of a floated layout where the items have been given a percentage size, once that item becomes a Grid Item the size becomes a percentage of the Grid Area it is in and not a percentage of the overall container width. You can see this by using the Firefox Grid Inspector to highlight the lines — the items are now squashed to one side of the Grid Cell.

    In a Grid Layout the width becomes a percentage of the track
    In a Grid Layout, the width becomes a percentage of the track. (Large preview)

    This is where Feature Queries can help. Feature Queries act much like a Media Query, instead of checking for the width or orientation of a device, we check to see if the browser supports a CSS feature.

    In our example of a floated layout that we want to turn into a grid layout, we only need to override one thing inside the Feature Query — we want to set the width back to auto.

    See the Pen display: feature queries demo by rachelandrew (@rachelandrew) on CodePen.

    How much overwriting of CSS used for nonsupporting browsers you need to do depends on how much you have decided to create a different layout for those older browsers.

    The IE10 And 11 Version Of Grid Layout

    While Edge has now updated to the modern grid layout, IE10 and 11 only have support for the early version first shipped with a -ms prefix in those browsers. The Grid specification that we know of today came originally from Microsoft. So far from being unhappy about this old implementation, we should be glad they kickstarted the process and gave us Grid in the first place. You can read more about the story in the article The Story of CSS Grid, from Its Creators.

    You might decide to offer IE10 and 11 a fallback experience based on a floated or other layout type as described above. This will work well, as will using Feature Queries, which are not supported in IE10 and 11. As long as you use these to overwrite your older methods checking for support, then creating the version for supporting browsers, IE10 and 11 will continue to use the older method.

    You could however make use of the -ms-grid version to create a fallback method. However this prefixed version is not the same as modern Grid Layout, it was the first version and experimental version. Things have changed in the five years or so since it shipped. This means you can’t just use autoprefixer to add the prefixes, that approach will probably leave IE10 and 11 users with a worse experience than if you do nothing at all. Instead, you need to create a layout using this different and more limited spec.

    The key points to note are as follows:

    1. There is no auto-placement. You need to place each item on the grid using line-based positioning.
    2. The grid-template-areas ascii-art method of positioning is not part of the implementation.
    3. There are no grid gap properties.
    4. Instead of specifying start and end lines, you specify a start line and the number of tracks to span.

    You can find a full breakdown of all of these properties in my blog post, Should I try to use the IE implementation of Grid Layout?

    If you have a large number of users with these browsers then you may find that this old spec is helpful. It is definitely worth knowing it exists even if you only use it to solve a couple of small issues that are real showstoppers for you.

    Why Bother Using Grid If I Have To Support These Browsers?

    If you have non-supporting browsers in your list, and you have to offer them an identical experience to supporting browsers then I would indeed question whether to use Grid Layout, or any new CSS. Use the methods that work. That approach is still perfectly valid.

    You might still consider using Grid Layout with a high level of fallback if you know that within the short-term it is likely that you will be dropping a bunch of those browsers from the “must be identical” list. Especially if you know the development you are doing now will have a long shelf-life. You could then lose the fallbacks at a later date and only use the Grid version.

    However, support for you may mean that it is possible for non-supporting browsers to get some level of simplified experience, and there are things you want to do with Grid Layout that are essentially impossible without it. That’s the time to use Grid Layout and design a good non-grid experience for those browsers.

    Testing Fallbacks

    A final note on testing these fallbacks. The only real way to test your fallbacks is to have access to browsers that do not support CSS Grid. One way to do this, without buying a stack of extra computers, is to download the Virtual Machines offered by Microsoft. You could then test using a version of Internet Explorer without support.

    You could download UC Browser onto a phone, or use the desktop version on Windows or in a Virtual Machine.

    There are also tools such as BrowserStack which give you access to remote Virtual Machines running a whole range of browsers. These services aren’t free, but they can save you a lot of time setting up VMs for testing.

    BrowserStack gives access to many different browsers and operating systems
    BrowserStack gives access to many different browsers and operating systems. (Large preview)

    I have seen people recommend switching your Feature Query to test for something that doesn’t exist — such as testing for support of display: gridx. This will work reasonably well. However, you do then need to put all of your Grid code inside the Feature Query Block, rather than relying on the fact it is ignored by browsers that don’t support it. You could easily end up with a false positive result by not realizing that some Grid code had wound up outside of a Feature Query. Even if you are using this method for quick checks, I would highly recommend doing some testing on actual browsers too.

    Further Reading

    I’ve rounded up the URLs referenced in this article and also some additional resources to help you navigate your own path to supporting browsers while still taking advantage of new layout. If you have come across any good resources, or particularly tricky issues, add them to the questions. Grid Layout is still new to all of us as something we can use in production, so there are bound to be some unanswered questions we can take a look at.

    Smashing Editorial(il)

    Mobile Interface Myths You Should Throw Out The Window

    If anything’s clear in 2017, it’s that lying is back in fashion (if it ever left us at all). From the heated fake news debate to the false data provided by Facebook, lying is all the rage these days. A white lie here and there is no big deal. We’re all guilty of it. The problem arises when lies turn into full-grown myths, then become accepted as truths.

    In an era of digital chaos, we understandably gravitate to our trusted sources of information. For us designers, this usually means guidelines as defined by juggernauts such as Google and Apple.

    With the impending switch to a mobile-first search engine world, myths about mobile interfaces are on the rapid rise. As we transition to a mobile-first world, I’d like to remind designers to see guidelines for what they are: guidelines. Somehow, many mobile concepts have evolved into biblical truths, when their intent might rather be case by case.

    Having white-labeled design and marketing work for ad agencies for a few years, I’ve heard the following statements boldly proclaimed as unquestionable truths more times than I can count. From my experience with ad teams and client meetings, these are the most frequent myths I think we need to put to bed, or at least remember to evaluate case by case.

    Let’s take some time to cover five mobile interface myths you’ve probably been sold on (and why that might be a bad thing).

    To Use Or Not To Use

    Many criticize gestural controls as being unintuitive and unnecessary. Despite this, widespread adoption is underway already. Read a related article →

    Myth 1: Mobile Users Are Always In A Hurry

    The prevailing wisdom about mobile users is that they’re always in a rush.

    They’re easily distracted, they hate tapping, they have bad taste, and they’re overwhelmingly suspicious of anything laid out in front of them.

    While these ideas are rooted deep and might have pieces of truth, they’re not the full picture. Furthermore, one-size-fits-all statements don’t make much sense in an increasingly niche-audience Internet. What works for some webmasters doesn’t necessarily hold true for others.

    The Truth: Get to Know Your Real Users

    There’s no question that mobile speed is key, and Google’s AMP project serves as a strong reminder of the importance of website-loading time.

    What’s less discussed is that you’ll never know which (if any) of these stereotypes apply to your website unless you get to know your target audience.

    Take the following company. We could argue over this screenshot all day, but let’s not dive too deep into the analytics. Just compare the website’s “Device Category” column with the “Average Session Duration” column on the far right:

    Google Analytics
    Client acquisition as recorded by Google Analytics (Image: X3 Digital) (View large version)

    You’ll notice almost no difference in time spent on site when comparing desktop and mobile session durations. In this company’s case, most website visitors come from organic search, so this screenshot is fairly representative of the website’s overall traffic.

    In this case, mobile users don’t seem to be in a hurry. Should we assume that all websites have analytics like these? Of course not. Should we assume that session duration is the perfect and only indicator of conversions? No.

    Take a longer look at this screenshot and you could accurately find that the bounce rate is higher on mobile and that the percentage of sessions skews heavily towards desktop, as well as a number of other interesting discrepancies. My point is not that session duration means everything, but that each website’s audience behaves differently and that you need to understand your unique audience. Then, optimize accordingly.

    Here’s what you should do to better understand your audience:

    • Know the goals of your website. Do you plan on using the website or app as a new revenue stream? Do you want to outdo your competitors by showing how innovative you are?
    • Find out who your target audience is. A buyer persona might come in handy for this. Get inside their heads. What do they need? What are they looking for? What problems are they trying to solve? Are they ready to sit and read long posts? Do they prefer a quick video?
    • Test your ideas. Before rolling out any changes, make it a point to gain customer feedback. Do not hesitate to test. Knowing what works and what doesn’t ahead of time will facilitate your design and development process.

    Spend time reviewing your own website’s analytics, and work to understand your audience’s intent, which is hiding behind the raw numbers.

    Myth 2: Mobile Websites Require Fewer Features

    I’m sure we all remember how we typically used the Internet nearly 10 years ago — we were primarily looking for time-sensitive content. Back then, our needs were rather immediate and specific.

    People on mobile websites had little to no intent to explore or purchase anything. Data connections were slow and expensive. It made sense to design mobile websites for pared-down tasks, offering the bare minimum. Publishers adopted an “if in doubt, leave it out” mentality, and if users wanted to view the full website, they’d need to hop onto their PC or Macintosh.

    This just isn’t the case anymore.

    The Truth: Prioritize and Maximize Mobile Capabilities

    According to Pew Internet, smartphone dependency has increased. In fact, 1 in 10 US adults use their smartphones as their primary means to connect to the Internet, and that number is growing rapidly. While overall Internet usage has risen, broadband service at home has plateaued in recent years.

    Nowadays, when someone visits a website on their mobile device, they expect to see everything that the desktop version offers. The practical way to accomplish this is to prioritize and maximize the capabilities of mobile features, including:

    • taking advantage of mobile sensors’ superpowers, something that desktops don’t have;
    • adding more content and features to a mobile website — depending on your user’s goals, this could mean adding share buttons pinned to the bottom of the screen or quick-tap functionality to return to the top of the page;
    • building your website or blog to adapt to the particular needs of each device type.

    The idea is to get rid of the thought that a smaller screen indicates less intent among users to explore. Instead of eliminating features on mobile, prioritize them.

    Layout

    Prioritize features
    Prioritizing calls to action (Image: Think With Google) (View large version)

    Offer users the same useful features that you would on your desktop website, while keeping in mind the screen-size limitations.

    Interstitials

    Intrusive interstitials
    Rethinking interstitials (Image: Think With Google) (View large version)

    Common wisdom (and probably your experience) tells you that popups are annoying and that you should delete them immediately. Here’s the problem with this advice: You still need to encourage signups, downloads and so on for mobile visitors.

    The key is to prioritize this content, not eliminate its purpose.

    Myth 3: Simplicity Is Good, Complexity Is Bad

    Closely related to myth 2, the next myth is one of the most widely held beliefs in the industry. When it comes to websites and apps, “less is more,” right?

    This myth states that mobile applications should be the “light version” of a desktop website. This comes from the principle that the organic interface has to be as close to zero as possible.

    Marissa Mayer famously discussed the two-tap rule: The fewer the clicks needed to achieve a goal, the better.

    Three-click rule of UX in action
    Three-click rule of UX in action (Image: Prototypr.io)

    A ton of designers tend to treat mobile and desktop as two different creatures, with opposing needs. Yes, there are significant limitations to a mobile device’s capabilities (namely, screen size). However, the intent of a user doesn’t drastically change, whether they’re using their mobile device or a desktop computer.

    So, why should the mobile interface be simpler?

    The Truth: Embrace Complexity

    Depending on your website or app’s users, this myth could ring true.

    Could you imagine needing eight taps to send snaps on Snapchat? Me neither.

    #NotMyNails
    #NotMyNails (Image: Mashable)

    The point is more that mobile users don’t want a dumbed-down version of a website. People simply need complexity presented in a way that’s uncomplicated. It all boils down to giving a good user experience. Consider the following:

    • Have one big idea per screen.
    • Instead of sending elements to secondary pages, you could put more content under properly labeled display elements.
    • Requiring more taps on a screen isn’t necessarily a bad thing. The idea is to make the website’s screen clear and easily digestible, rather than cluttered and dense. If a click has a goal to it, it can stay.

    Take Circlebox Creative:

    Circlebox Creative
    Circlebox Creative (Image: Design Your Way)

    A lot is involved in creating a profile. Is this a personal user? Is it a business profile? Will you choose social login? Email login? This signup process incorporates a lot of information but doesn’t feel overwhelming because it’s easily digestible.

    Complexity is not the bane of mobile design. When you build your website, you just need to make it enticing and user-friendly.

    Myth 4: Guidelines Cannot Be Broken

    Apple versus Android
    Apple versus Android (Image: iPhone Life)

    Most designers treat guidelines as gospel, and for a decent reason.

    Many times, guidelines are incredible resources, to be followed as instructed. Google’s material design is a great resource for understanding how to craft digital experiences using a consistent set of principles.

    Designers often hold that applications created for iOS should follow Apple’s guidelines and that apps made for Android should follow Google’s guidelines, and that if an app needs to be accessible on both operating systems, then the designs should be entirely different from each other.

    The problem arises when designers find themselves stuck between a rock and a hard place, where they envision a design that conflicts with the guidelines.

    Should they follow guidelines? Or can they trust their design instincts for each unique case?

    The Truth: Treat Guidelines as Recommendations

    The dictionary defines a guideline as a “general rule, principle, or piece of advice.” A guideline is intended to serve as a loose guide or as helpful suggestions, not a strict mandate to obey.

    Design is an exploration to discover what works best.

    – Google Design

    If your intended design severely clashes with conventional guidelines, you’ll need to weigh whether this is an indicator to rethink your layout approach or whether you’re simply designing with your unique users’ needs and intentions in mind.

    To put this myth to bed, Google even ignores its own material design guidelines (on occasion). Take its icons:

    Google Play icons
    Google Play icons (Image: The Verge)

    To paraphrase Android Authority, Google’s icons fly in the face of product-icon anatomy. The guideline states that you shouldn’t crop elevated material elements within another shape, meaning that the uppermost layer shouldn’t have its boundaries defined by the lower layer.

    The icons for Movies, Music, Games, Books and Newsstand all are beautifully designed, while defying this straightforward guideline. These icons have also done away with the 45-degree light source that is commonly encouraged for all icons.

    On the whole, Apple and Android guidelines are a tremendous gift. However, don’t treat them as hard and fast rules. Always design with your users in mind, even if that means bending some of the guidelines.

    Myth 5: The Designer And The User Think The Same

    This myth is more of a commonly held belief carried out in practice, rather than an actual myth. Of course, the first rule of user-centered design is that you are not the user. But, so often, clients and designers fall for the “we know what’s best” approach.

    It’s tempting to think that everybody thinks just like you.

    Often, designers fall into the trap of thinking like their client or thinking of themselves when approaching design. “Would I like this feature if I implemented it?” or “Would my client tap on this button if I placed it here?” are questions that fall under this umbrella.

    The problem with this is that you lose sight of who you’re designing for: the user.

    The Truth: Users Have Experiences Unique From Yours

    It’s possible that the demographics of your users include yours or your client’s. However, you’ll need to look at design from the perspective of your visitors, not of your client.

    This is true for a couple of reasons:

    • Users only want what’s beneficial for them. You, as a designer, are able to come up with ideas to present a product in a way that you think would engage the user. However, these ideas will only matter as long as they are beneficial to the user. If the user doesn’t find value in it, they won’t enjoy engaging with the content you produce.
    • Users only want their problems to be solved. The client knows more about the business than the user. They immerse themselves in the industry, studying it, learning its ins and outs. This data isn’t of interest to the user, who only wants their problems to be solved. The client is all about gaining profit; the user is all about finding solutions. Sometimes these interests overlap, but keep your eye on user needs first and foremost.

    If you’re struggling to see things from your users’ point of view, read up on and start employing mobile usability testing (Lyndon Cerejo offers a summary).

    I’m hardly a usability testing expert, but I’ve been thinking about how my team could use a significantly simplified version of user testing for an upcoming website redesign. Here’s the basic outline of user testing I have in mind:

    1. Gather an unbiased group of individuals.
    2. Do not disclose which website is being tested, to avoid bias. Instead, show several websites sequentially, including our website and competitor websites.
    3. For each website, walk individuals through each page, discussing the intended user flow, mission, etc.
    4. Let each individual test how they would achieve the tasks, while providing no indication of how you think the goals should be completed.
    5. Test on various devices and connections, to compare between devices.
    6. Ask each individual to write down any issues they run up against, while trying to achieve the stated purpose for each page.
    7. Ask each participant to grade each website, asking for their feedback on accessibility, speed, UX, navigation, readability, the overall score, etc.
    8. Repeat these observations over time to identify new recommendations.

    This is not a perfect scenario, but it enables us to define a preliminary report of usability issues and observations, and to pinpoint key recommendations for our work moving forward.

    Summary

    If I had to encapsulate the sections above, along with what I’ve learned at my web design and marketing agency, it would be this: Test, test, test. And then test again.

    Takeaways

    • Understand your audience and purpose. Determine the goals of your website, find out who your target audience is, and test your ideas to gain useful data about your visitors.
    • Maximize mobile capabilities. Take advantage of the superpowers of mobile sensors, add mobile-specific features, and adapt to the specific needs of each device and mobile operating system.
    • Embrace complexity. Have one big idea per screen. Put content under properly labeled display elements, instead of on secondary pages. And make sure the screen is clear and easily digestible, rather than cluttered and dense.
    • Treat guidelines as useful recommendations, not mandates. Guidelines can serve as helpful suggestions. But, ultimately, design is an exploration to discover what works best.
    • Work to understand your audience’s unique points of view. Try employing mobile usability testing to better understand your visitors’ needs.

    Make time to track and analyze the analytics for how your audience responds to your company’s split-testing efforts. Don’t take anybody’s word for it (including mine).

    Observe what your visitors are doing, anticipate their needs, and design for their approval and convenience. Over time, you’ll gain a deeper understanding of your unique audience and will naturally attract a growing number of visitors eager to engage with you and your business.

    Additional Insights

    (da, yk, ra, al, il)

    Creating Secure Password Resets With JSON Web Tokens

    When a user of your application has forgotten their password, it can and should be reset securely. To accomplish a secure password reset, I will demonstrate how to use JSON Web Tokens (JWT) to generate a URL-safe token. The JWT contains encoded information about the user and a signature that, when decoded, is validated to ensure that the token has not been tampered with.

    Once the JWT is validated, your application can securely allow the user to generate a new password, instead of sending them their forgotten one.

    “Why Can’t I Just Send The User Their Password?”

    There was a time when your password was stored in your favorite website’s database just as you typed it. In fact, it still seems to occur far too often. An entire website is dedicated to telling people whether their email address or username has been exposed.

    In those days (and I use the past tense loosely), when a user forgot their password, they would arrive on a page that asked for their username or email address. The website would then send them an email “reminding” them of their password. This should be a red flag to you, as both a user of the website and as a developer. Either your password is stored in plain text or it can be decrypted, instead of having the much stronger, more secure one-way encryption.

    Because (secure) passwords cannot be decrypted, that leaves us with one of two common choices when a user forgets their password:

    1. Generate a new, temporary password and send it via email.
    2. Generate an email that contains a one-time-use link within the contents of the email, which will take the user to a page where they can enter a new secure password.

    Both options send out an email, which in the long term should not be considered a secure storage medium. With the first option, the password is shown in plain text. If the user were to leave this email in their inbox as their method of remembering their password (especially because they didn’t choose it), it would be almost as insecure as writing down their password on a sticky note and leaving it beside their computer. OK, not that bad, but you get the idea.

    Another concern with option one is that a malicious user who knows their email address could easily lock out a user from the website by resetting their password. If the malicious user repeated this over and over again, it would make it almost impossible for the user to ever log in again because their password would never remain the same.

    Password-Reset Process Overview

    The goal of this tutorial isn’t to learn how to secure your users’ passwords in your database; you’ve already done that! This tutorial will show you how to reset the password of a user who has forgotten theirs by generating a special link that enables them to securely reset their password. The link will look similar to the following example:

    http://localhost:3000/resetpassword/1/eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VySWQiOjF9.uKe3CzH_g6oHxlFstQ1BL_Q8_zJKPyJ0dUvZkJsRKBg

    Contained within this link is a special JWT that is used to securely validate the user who is trying to reset their password.

    By the end of this tutorial, I will have walked you through creating an application that contains the following functionality:

    • We’ll have a form that accepts the email address of a user who has forgotten their password.
    • We’ll create a link with a JWT token embedded in the URL. The user will click this link and be allowed to reset their password.
    • We’ll create a page for resetting the password. This page will require the token and will decode it to ensure it is valid.
    • When the token has been successfully validated, a form will be displayed allowing the user to reset their password.

    The following is an application diagram that demonstrates what the user does and how the server processes and responds to each action initiated by the user.

    Password-reset workflow
    Application diagram of password-reset workflow

    I mentioned earlier that email should not be considered secure for long-term storage. To help prevent this issue with option two, the link contained in the email is to be used once. Once the user has clicked the link and changed their password, if they (or a malicious person) were to click the link again, it would not be valid and the user would be unable to change their password. The user would, thus, be forced through option two again: generating a new email with a new one-time-use link.

    This solution also prevents the secondary negative side effect of option one. If a malicious user were to attempt to constantly reset the user’s password, the original password would be unaffected and the user would never be locked out.

    Before creating the application, let’s better understand what JWTs are and learn how to create, encode and decode them.

    What Are JSON Web Tokens?

    A JSON Web Token (JWT), in its simplest form, is a URL-safe string that contains an encoded JSON object. JWTs are an open industry standard that are fully described in RFC 7519, which contains an immense amount of detail, specifically regarding how JWT claims function to ensure the security of a generated token. Feel free to peruse the full RFC specifications at your leisure.

    Let’s look at an example token:

    eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VySWQiOjF9.uKe3CzH_g6oHxlFstQ1BL_Q8_zJKPyJ0dUvZkJsRKBg

    Notice that the token contains two periods (.) separating the three pieces of the outputted token, those three pieces being the following:

    • header

      The header contains information that identifies what the hashing algorithm is, so that it can be used to properly decrypt and validate the signature.
    • payload

      This contains the information you wish to send with your JWT. Note that the payload is not secure and can be decoded without a secret key. JWTs are not meant to send sensitive information, such as passwords or credit card numbers.
    • signature

      The signature combines the encoded header and the payload with a secret key and securely encodes it using the hashing algorithm defined in the header — for example, HMAC with SHA-256.

    To summarize, each time you generate a token:

    • the header will remain constant (assuming you do not change the hashing algorithm);
    • the payload will remain constant when the payload to encode is the same;
    • the signature will encrypt these two pieces of information based on the hashing algorithm with a secret key. This means that if you do not generate a unique secret key or change the payload, then the signature will also remain the same.

    Encoding And Decoding JWTs

    We are going to create a new application to demonstrate the basics of encoding and decoding tokens. Once we have a solid understanding of JWTs, we are going to recreate the application and I’ll demonstrate how to securely reset a user’s password.

    To begin, please ensure you have Node.js installed. If you do not have it installed, I suggest visiting the download page and selecting the appropriate installer for you.

    Our new application will be named “passwordreset.” In a command prompt, I ran the following commands to create a basic application. Ensure that you start in the current working directory of where you wish to host your Node.js application.

    mkdir passwordresetcd passwordresetnpm init

    The npm init process asks a lot of questions to help you customize your final package.json file. In my case, I have left everything as their defaults.

    Creating Our First JWT

    To make generating JWTs easy, we are going to use an existing npm package named JWT Simple, which will obfuscate a lot of the complexities of encrypting and decrypting a token.

    To install the package, in your command prompt where your application resides, enter the following command:

    npm install jwt-simple --save

    In this first code example, I have created a new index.js file, which creates a JavaScript object that I encrypted into a JWT:

    var jwt = require('jwt-simple');var payload = { userId: 1 };var secret = 'fe1a1915a379f3be5394b64d14794932';var token = jwt.encode(payload, secret);console.log(token);

    Let’s look at what is happening. The application begins by including the JWT Simple module. We then create a payload object. This object is what we will be encoding inside the token. We have created an object that contains a single property, named userId. I’ve used a hardcoded value of 1.

    A token needs to be encrypted (and decrypted) with a secret key. I’ve generated a random string that will be used each time (in this sample application).

    With the prerequisites set, we are finally able to create our token. This is done by calling the encode function from the JWT Simple module. This function accepts our payload and the secret key. The result of this function is our URL-friendly token, which contains our encoded header, payload and signature. The final line outputs our token to the console.

    Running our application will output the following:

    node index.jseyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VySWQiOjF9.uKe3CzH_g6oHxlFstQ1BL_Q8_zJKPyJ0dUvZkJsRKBg

    As you might have observed, this is the same token from earlier that I broke apart and whose three parts I described (header, payload and signature). Let’s now update our index.js file to decode the token and log it to the console:

    var decode = jwt.decode(token, secret);console.log(decode);

    Now, when we run the application, we receive the following output:

    node index.jseyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VySWQiOjF9.uKe3CzH_g6oHxlFstQ1BL_Q8_zJKPyJ0dUvZkJsRKBg{ userId: 1 }

    Yep, our token was successfully decoded and contains our userId property, with the correct value of 1!

    If the token was tampered with and any of the three parts were not able to be decoded and decrypted, then the JWT Simple module would throw exceptions.

    Resetting The User’s Password

    Let’s put our JWT knowledge to good use and create the final application, allowing the user to reset their password. To focus on the one-time-use password-reset link, we will not implement a database or an email. Nevertheless, our application will contain the following functionality, with several comments about where the application could be enhanced to integrate those features:

    • The application will display a form that accepts the user’s email address.
    • It will handle the form’s POST with the user’s email address.
    • This will create a link, with a JWT token embedded in the URL. The user will click this link and be allowed to reset their password.
    • The application will create a password-reset page. This page will require the token and will decode it to ensure it is valid.
    • If successful, a form will be displayed allowing the user to reset their password.
    • The application will handle the form’s POST with the user’s new password.
    • This page will also decode and validate the token before saving the new password.

    It’s now time to create the application to reset the user’s password, leveraging JWTs to validate the user throughout the process.

    To handle the HTTP communication, we are going to use the Express module. We will also be using the BodyParser module to parse the content from our form’s POSTs.

    These can be installed by running the following commands in your project’s working directory:

    npm install express --savenpm install body-parser --save

    We will be pseudo-coding the spots where we would be leveraging a database and sending emails, in order to keep this article focused on how JWTs are used throughout the password-reset process. I am going to repurpose my previously created index.js file for the final application.

    The following code examples will all be subsets of my full index.js file, allowing me to incrementally demonstrate the process that I am building.

    The first thing we need to do is include the required modules and create a web server that allows the user to reset their password:

    const express = require('express');const bodyParser = require('body-parser');const jwt = require('jwt-simple');const app = express();app.use(bodyParser.urlencoded({ extended: false }));app.listen(3000, function () { console.log('Node started on port 3000!')});

    The first three lines include the modules required to serve the web pages, parse our forms and encode and decode our JWTs.

    The next set of lines set up Express to listen on port 3000 for HTTP requests, and they initialize the BodyParser module to decode standard form data.

    With our web server set up, the next set of code will display a form that asks the user for their email address. This will begin the password-reset process:

    app.get('/forgotpassword', function (req, res) { res.send('<form action="/passwordreset" method="POST">' + '<input type="email" name="email" value="" placeholder="Enter your email address..." />' + '<input type="submit" value="Reset Password" />' + '</form>');});

    This page can be accessed via http://localhost:3000/forgotpassword. The form it creates will POST to passwordreset with the user’s email address. Our basic form looks as follows. Once the user has entered their email address and submitted the form, our application needs to handle it:

    app.post('/passwordreset', function (req, res) { if (req.body.email !== undefined) { var emailAddress = req.body.email; // TODO: Using email, find user from your database. var payload = { id: 1, // User ID from database email: emailAddress }; // TODO: Make this a one-time-use token by using the user's // current password hash from the database, and combine it // with the user's created date to make a very unique secret key! // For example: // var secret = user.password + ‘-' + user.created.getTime(); var secret = 'fe1a1915a379f3be5394b64d14794932-1506868106675'; var token = jwt.encode(payload, secret); // TODO: Send email containing link to reset password. // In our case, will just return a link to click. res.send('<a href="http://www.smashingmagazine.com/resetpassword/' + payload.id + '/' + token + '">Reset password</a>'); } else { res.send('Email address is missing.'); }});

    Quite a bit is going on here, so let’s break it down:

    1. We ensure that the POST’s body contains the email property. If it doesn’t, then a basic error message is returned to the user.
    2. Store the email from the POST’s body in a local variable, emailAddress.
    3. Now our first pseudo-code occurs. I’ve placed a TODO message that says you should search your user database for a valid user with the email address supplied.
    4. Next, we generate the payload for the token. My payload consists of the user’s ID and email address.
    5. To make this token a one-time-use token, I encourage you to use the user’s current password hash in conjunction with the user’s created date (in ticks) as the secret key to generate the JWT. This helps to ensure that if the user’s password was the target of a previous attack (on an unrelated website), then the user’s created date will make the secret key unique from the potentially leaked password.
    6. With the combination of the user’s password hash and created date, the JWT will become a one-time-use token, because once the user has changed their password, it will generate a new password hash invalidating the secret key that references the old password.
    7. Because we don’t have a database, we are simply using a static string.
    8. The token is then generated using our payload and secret key.
    9. The final bit of pseudo-code occurs, to send the password-reset link to the user’s email address in an email.
    10. To continue focusing on how tokens are being used, let’s return the link to the browser. This can be clicked to finish the password-reset process. This link would be the same link that the user clicks in the email they received.

    In all cases where you send an email to the user, the response should indicate that an email has been sent to the user and instruct them to click the link in the email.

    When the user receives the email, they will click the link that takes them to the password-reset page. This page accepts the user’s ID and token as URL parameters (which were set in the link generated in the previous code example). The following code will handle this page. Upon successful decoding and validation of the token, a form is displayed allowing the user to set their new password:

    app.get('/resetpassword/:id/:token', function(req, res) { // TODO: Fetch user from database using // req.params.id // TODO: Decrypt one-time-use token using the user's // current password hash from the database and combine it // with the user's created date to make a very unique secret key! // For example, // var secret = user.password + ‘-' + user.created.getTime(); var secret = 'fe1a1915a379f3be5394b64d14794932-1506868106675'; var payload = jwt.decode(req.params.token, secret); // TODO: Gracefully handle decoding issues. // Create form to reset password. res.send('<form action="/resetpassword" method="POST">' + '<input type="hidden" name="id" value="' + payload.id + '" />' + '<input type="hidden" name="token" value="' + req.params.token + '" />' + '<input type="password" name="password" value="" placeholder="Enter your new password..." />' + '<input type="submit" value="Reset Password" />' + '</form>');});

    Similar pseudo-code from the previous example has been included in this example to help secure the application:

    1. Using the ID from the URL parameters, we fetch and validate that the user exists in our database.
    2. We decode the token from the URL parameters. To ensure it is a one-time-use token, I encouraged you in the previous example to encode it with the user’s current password hash in combination with the user’s created date (represented in ticks); thus, it should be decoded with that same hash.
    3. This is how it becomes a one-time-use token. Once the user has successfully changed their password, if they attempt to use the same token again, the token would not decode properly because the password hash would be different for that user.
    4. It would be a good idea to gracefully handle any errors that occur while decoding the token.
    5. Finally, a new form is returned that places the ID and token as hidden form fields and that includes a form field to accept the new password.

    This is an example of our basic form for the user to reset their password.

    The final part now is to handle the form’s POST with the user’s new password:

    app.post('/resetpassword', function(req, res) { // TODO: Fetch user from database using // req.body.id // TODO: Decrypt one-time-use token using the user's // current password hash from the database and combining it // with the user's created date to make a very unique secret key! // For example, // var secret = user.password + ‘-' + user.created.getTime(); var secret = 'fe1a1915a379f3be5394b64d14794932-1506868106675'; var payload = jwt.decode(req.body.token, secret); // TODO: Gracefully handle decoding issues. // TODO: Hash password from // req.body.password res.send('Your password has been successfully changed.');});

    The first part of this code is nearly identical to the previous example where the pseudo-code fetches the user and decodes the token with their current password hash, and the user’s created date is converted to ticks.

    Notice the minor change in accessing the user’s ID and token. In the previous example, we used req.params. In this example, we are using req.body. The difference is that the first example was a GET request with the variables in the URL. This example is a POST request in which the variables are in the form.

    The final TODO is for you to hash the user’s new password once the token has been validated.

    This completes our sample application, which uses a single JWT to allow the user to change their password if they have forgotten it.

    Additional Password-Reset Security Measures

    Our application focuses specifically on securing the password-reset form by generating and validating a special link embedded with a JWT.

    This is just the tip of the iceberg to ensure that the entire password process is more secure. Below is a list of several other enhancements that could further secure your website:

    • Limit the number of password-reset attempts to prevent a malicious user from giving your end user a negative experience of flooding their inbox with password-reset emails.
    • Always indicate success when the user enters their email address in the forgotten-password page.
    • Ensure that your website uses HTTPS to prevent any plain-text communication between the user and server when they are entering or resetting their password.
    • Ensure that the user’s new password is secure and is not the same as their last password.
    • Implement a CAPTCHA — the “Are you a human?” test — on both the forgotten-password and password-reset pages. Some websites even implement the CAPTCHA test on the log-in screen.
    • Implement forgotten-password security questions, where the user must answer a security question (that they’ve previously created) before an email is ever sent to reset their password.

    “How Else Can I Use JWTs?”

    By now, I’ll bet you are addicted to creating and consuming JWTs! Now you want to use them more. Here are a few examples of how else I have used them:

    • Single sign-on

      A friendly third-party website would generate a JWT with information that your website would require to authenticate the user in your application. You and the friendly website would privately share the secret key used to encode and decode the token.
    • Information exchange

      Similar to single sign-on, you or the friendly website would generate a token with a privately shared secret key that contains the information you wish to send or receive. Be sure not to share sensitive data!
    • Tokens required for the “OAuth dance

      Note that, because a generated JWT is a string, it can be decoded by a server other than the one that generated it. For example, you might generate a token with your Node.js server, and I could consume it with my PHP application as long as we use the same secret key and hashing algorithm!

    Conclusion

    Almost every day, we hear about a new security leak. And, let’s be honest, locks only keep out honest people. This means that, as developers, we need to try harder to make better locks. A JWT provides a URL-safe token that, when generated securely, makes for a more secure password-reset process by ensuring that a malicious user cannot easily generate their own token.

    This article focused on the password-reset process by securing the password-reset flow with a URL-safe token that is validated with a signature. If you haven’t already done so, I suggest enhancing your processes further by reviewing the additional password-reset security measures and adding the ones that work for you.

    If you have any further security processes, be sure to leave a comment below to help your fellow developers ensure that their password policies are more secure.

    Smashing Editorial(al)

    10 Simple Tips To Improve User Testing

    (This is a sponsored post). Testing is a fundamental part of the UX designer’s job and a core part of the overall UX design process. Testing provides the inspiration, guidance and validation that product teams need in order to design great products. That’s why the most effective teams make testing a habit.

    Usability testing involves observing users as they use a product. It helps you find where users struggle and what they like. There are two ways to run a usability test:

    • Moderated, in which a moderator works with a test participant.
    • Unmoderated, in which the test participant completes the test alone.

    We’ll focus on the first, but some of the tips mentioned can be applied to both types of testing.

    1. Test As Early As Possible

    The earlier you test, the easier it is to make changes and, thus, the greater impact the testing will have on the quality of the product. A lot of design teams use the excuse, “The product isn’t done yet. We’ll test it later,” to postpone testing. Of course, we all want our work to be perfect, which is why we try to avoid showing a half-baked design. But if you work too long without a feedback loop, the chances are higher that you’ll need to make a significant change after releasing the product to the market. It’s the classic mistake: thinking you’re the user and designing for yourself. If you can invest energy to learn early and prevent problems from happening in the first place, you will save a tremendous amount of time later.

    The good news is that you don’t need to wait for a high-fidelity prototype or fully formed product to start testing. In fact, you should start testing ideas as soon as possible. You can test design mockups and low-fidelity prototypes. You’ll need to set the context for the test and explain to test participants what’s required of them.

    An example of a low-fidelity prototype made in Adobe XD.
    An example of a low-fidelity prototype made in Adobe XD.)

    2. Outline Your Objectives

    Before starting usability testing, be crystal clear on your goals. Think of the reason you want to test the product. What are you trying to learn? Ask yourself, “What do I need to know from this session?” Then, once you understand that, identify exactly which features and areas you want feedback on.

    Here are a few common objectives:

    • Find out whether users are able to complete specified tasks successfully (e.g. purchase a product, find information),
    • Identify how long it takes to complete specific tasks,
    • Find out whether users are satisfied with a product and identify changes required to improve satisfaction.

    3. Carefully Prepare Questions And Tasks

    Once you have an objective, you can define which tasks you’ll need to test in order to answer your questions or validate your hypothesis and assumptions. The objective is not to test the functionality itself (that should be a goal of the quality assurance team), but to test the experience with that functionality.

    Actionable Tasks

    When designing tasks, make them realistic and actionable. These could be specific parts of the product or prototype that you want users to test — for example:

    • Getting started with the product,
    • Completing a checkout,
    • Configuring the product.

    Prioritize Tasks

    Don’t squeeze in many subjects in your usability testing checklist. Conducting the tests and analyzing the results will take a lot of time. Instead, list the important tasks in your product, and order them by priority.

    Clearly Describe Tasks

    Testers need to know what to do. Make it easy. Users tend to become discouraged when tasks are unclear.

    Have a Goal For Each Task

    As a moderator, you should be very clear about the goal of a task (for example, “I expect that users will be able to complete the checkout within two minutes”). However, you don’t need to share that goal with participants.

    Limit The Number Of Tasks

    Patrick Neeman of Usability Counts recommends assigning five tasks per participant. Considering the time of the session (usually 60 minutes), leave time for your questions, too.

    Provide a Scenario, Not Instruction

    People tend to perform more naturally if you provide them with a scenario, rather than dry instruction. Instead of asking them something like, “Download a book with recipes,” you could phrase it as a scenario, like, “You’re looking for some new ways to cook beans. Download an ebook with recipes.” A scenario provides some context and makes the task more natural for the user. The more naturally participants perform the task, the better the data you will get as a result.

    Test The Set Of Tasks Yourself

    Go through the task several times yourself, and work out appropriate questions to ask. It’s hard work but will definitely pay off.

    4. Recruit Representative Users

    Finding the questions you want to ask is important, but also, the people who participate in your test should be representative of your target audience (user persona). There’s no point in watching people use your product if they don’t match your target audience. Therefore, as soon as you have some idea of what to test, start recruiting. Carefully recruit people based on your goals. Be advised: Finding people for usability tests is not easy. In fact, recruiting is one of the biggest reasons why many companies don’t regularly talk to their users. Thus, put in the extra effort to find people who represent your target audience.

    Analyze Existing User Data

    If your product already has a customer base, then a quick analysis of available information (for example, analytics data, customer support tickets, surveys, previous usability sessions) will help you assess what you already know or don’t know about your users.

    Numbers provided by an analytic tool on how the user interacts with a product (clicks, user session time, search queries, conversion, etc.) will help UX designers to prepare for usability tests. (Image: Ramotion) (Large preview)

    Test With Users Who Aren’t Only Friends or Family

    Of course, feedback from friends and family is better than nothing, but for better results, you’ll need independent and unbiased users, ones who haven’t used your product before. Your friends and family are too close to the product to know how real people would perceive it for the first time.

    Define Your Criteria

    Before recruiting users, you’ll need to decide on the type of people to test your product. Define criteria and select testers according to it. For example, if you are testing a mobile app for ordering food, most probably you’ll need feedback from people who order food regularly. Translate this requirement into precise, measurable criteria, so that you can use it to screen prospective participants: people who order food at least once a week from different delivery services (participants should have experience with at least three services).

    In addition to specifying the users you want to talk to, think about people you don’t want to see in any of your sessions. As a rule of thumb, avoid testing with tech-savvy users and early adopters, because such testing might not be as revealing as you’d like. Also, avoid participants who have conflicts of interest (such as ones who work for competitors).

    Create Screener Questions

    Next, create a screener questionnaire to identify people for your testing sessions. As with any good survey or questionnaire, avoid leading questions. An example of a question that would reveal the “right” answer is, “Do you like ordering food using a smartphone?” Most people who want to join a testing session would surely answer yes to that question.

    You can prepare a list of questions in the format of a survey and ask potential testers to fill it out. Google Forms is a great tool for creating screeners and collecting the responses in a spreadsheet. Because responses go right into a Google spreadsheet, you can sort and filter them.

    Get People to Fill Out the Screener

    Next, you’ll need to get people to fill out the screener. One way to achieve this is to create a job description with a link to your survey. In the description, explain your expectations, and offer an incentive to motivate people to show up (such as a $100 Amazon gift card for a 60-minute interview).

    Craigslist, Twitter and Facebook are the most obvious places to post the job description.

    Things will be a bit harder when you need to recruit very specific and hard-to-find types of users. But even in this case, it’s totally solvable:

    • Talk with your sales or marketing team to see if they have lists of contacts they can share.
    • Find contacts in relevant community groups and professional associations.

    Tip: If your product is on the market, you could show a message — “Want to give us more feedback?” — somewhere in the user flow, which leads to your screener form. Also, if you use a service such as Intercom, you could automatically email new users after they have used the product five times, inviting participation in testing.

    Think Quality, Not Quantity

    Some product teams think they need a lot of participants for usability testing. In fact, testing with five users generally unveils 85% of core usability problems. The most important problems are easy to spot for people who are new to your product, and difficult for you to spot because you no longer have fresh eyes. It turns out that you’ll learn a lot from the first person you talk to, a little less from the next, and so forth.

    Once you collect the responses and filter the list of potential participants based on your criteria, select the five candidates who fit your criteria the best.

    user tests
    (Image: Nielsen Norman Group) (View large version)

    Clearly Instruct on How to Join the Session

    When you schedule a test session, provide all details in a confirmation email to participants:

    • The time (if you do remote testing, provide the time in the relevant time zone),
    • The location (including building, parking information, etc.),
    • What test participants need to bring with them (for example, personal ID, a mobile device with iOS or Android, etc.),
    • Your phone number (in case they have questions or need to reschedule).

    To minimize frustrating no-shows, you could ask users to reply to confirm. For example, your subject line in the confirmation email could be something like, “Usability session scheduled on May 14 at 3 pm. (Please reply to confirm).” You could also call participants to remind them about their appointment on the day before the session.

    5. Get The Most Out Of In-Person Testing

    Hearing directly from users is one of the fastest ways to learn about and improve your product. By watching someone use your product, you can quickly identify areas where the product isn’t clear enough.

    Building a Good Rapport

    When a session begins, the participant might be nervous and unsure about what to expect. The quality of a usability session is directly related to the rapport you build with the participant. The deeper the participant’s trust in the moderator, the more frank their feedback will be. Conduct the test in a way that participants will feel comfortable giving you honest feedback.

    A few things to remember:

    • In case of failure, people tend to blame themselves, rather than a flaw in the design. Thus, make sure they don’t feel like they’re being tested. (For example, “We’re not testing you; we’re testing our design. So, nothing you say or do is wrong.”)
    • You want participants to be as candid as possible. If they don’t like something or they think it’s silly, make sure they say so. Some participants don’t like to share such thoughts because they are afraid of hurting your feelings. Just tell them something such as, “You won’t be hurting our feelings. We haven’t been involved in designing these screens at all.”
    • Start with easy tasks or questions. They won’t yield any juicy insights, but they will get people talking and will help relax them. Learn a bit about the person. Try to find out what the person likes or doesn’t like, their hobbies, as well as tech habits. This information will help you better evaluate the results of the test.

    Listen, Don’t Lead

    Once you have presented the task, everything should be led by the participant. Your goal in this session is to understand how users will use the product. For example, if the participant takes an unplanned route through your app, don’t correct them! Wait to see what happens. This is valuable learning.

    Don’t Judge Participants

    Your participants are there to teach you something, not the other way around! Judging users or trying to educate them during the test would be counterproductive. Your goal is to get as much information as possible in the time available and to understand it all from their perspective.

    Thus, avoid phrases like, “That was obvious, right?” and “Do you really think so?” while raising your eyebrows, even if something seems obvious. Instead, ask something like, “How easy or difficult was it for you to complete this task?” or “Why do you think that?” There should never be any judgement or surprise in either your tone or body language.

    Don’t Explain

    When you explain how the product you’re testing functions, you’ll almost certainly be introducing bias to the test. In the real world, your product will live on its own. You won’t be there to guide users along and tell them exactly what to do and how to use it. Participants should have to figure things out based on the task’s description and what they see in the interface.

    Don’t Interrupt

    When participants start a task, try your best not to interrupt them. The more you interrupt, the less likely they’ll have the confidence to complete the task. They’ll lose their flow, and you won’t see anything resembling natural behavior.

    Don’t Draw Attention to Specific Issues

    Drawing attention to specific issues that you care about could cause people to change their behavior and focus their answers on the issues you’re emphasizing. This problem is particularly common in discussions on user interface design: If you were to ask people about a particular design element (such as the color of the primary call-to-action button), they’ll notice it thereafter much more than they would have otherwise. This could lead participants to change their behavior and focus on something that doesn’t matter.

    Use the Think-Aloud Technique

    The think-aloud method is critical to getting inside the participant’s head. In fact, Jakob Nielsen argues that it’s the best usability tool. Using the think-aloud technique, the moderator asks test participants to use the product while continuously thinking out loud — simply verbalizing their thoughts as they move through the user interface. Using this technique for the food-ordering app, most probably you’d get responses like, “Hm, this looks like a food-ordering app. I’m wondering how to order food. Maybe if I tap here, I’ll see a form to request a meal.” The technique enables you to discover what users really think about your design and will help you turn the usability session into actionable redesign recommendations. Responses like, “Oh, it loads too slowly”, “Why am I seeing this?” and “I expected to see B after A” can be translated into actionable design changes.

    Tip: Because most users don’t talk while using a product, the test facilitator will have to prompt them to keep talking. Ask something like, “What’s going on here?” when test participants interact with the product.

    Observe Behavior

    Mind the distinction between listening and observing. While both methods will provide UX designers with valuable information, many UX designers focus too heavily on listening. Observing users can uncover a lot more in a lot less time. You can learn a lot by listening to people, but you can learn way more by seeing how they react to a product.

    Most people want to look smart, which is why during testing sessions, you’ll notice participants struggle through a task but then tell you that it was easy for them. Thus, focus on their behavior, not their opinion.

    When in Doubt, Clarify

    When you’re not quite sure what a participant is talking about, ask for clarification. A simple question like “When you said… did you mean…?” will make things clear. Don’t leave it to the end of the session. The end of a session is too late to go back and figure out what someone was talking about.

    Follow Up With Questions

    Be eager and curious to learn as much as you can about the user’s experiences and perspectives. Don’t settle for the first answer you get. Always dig deeper by asking follow-up questions. Follow-up questions will give you a lot of insight into what has really happened. People often can’t clearly state their motivations without being prompted. A simple well-timed follow-up question will usually yield a more thorough explanation or valuable example.

    Answer Questions With Questions

    During the session, participants will certainly ask you some questions. Here are some of the most common ones:

    • “Should I use it?”
    • “What do you think?”
    • “What did others think about this?”

    Resist the temptation to tell them all about it! Ask them a question right back. It’ll reveal a lot.

    6. Treat Design As An Iterative Process

    A lot of product teams think about the design process as a linear process that starts with user research, has a phase for prototyping and ends with testing. However, treat it as an iterative process.

    Testing, as much as coding, designing and gathering requirements, has a place in the iterative loop of product design and development. It’s important to test at each interval of this process, if resources are available.

    Feedback Loop

    The best way to avoid having to rework a product is to inject feedback into the process. Regular user feedback (not necessarily in the form of usability testing, but also in online surveys or analysis of customer support tickets) should be at the heart of the UX design process.

    Learn, build, measure
    (Image: Extreme Uncertainty) (View large version)

    7. Don’t Limit Yourself To In-Person Sessions

    Testing in-person is a great way to understand user behavior; unfortunately, it’s not always possible. What if you need to test only one small feature, or your test participants are dispersed (for example, if your product targets international customers), or you need results fast (ideally, today)? In this case, focus on remote testing. But how do you handle remote sessions?

    Use Tools for Unmoderated Tests

    Nowadays, a ton of tools are available for you to run remote unmoderated tests. Here are some:

    • Lookback

      This tool allows for both remote live moderated testing and unmoderated testing. Live sessions are automatically recorded in the cloud — no uploading, waiting or managing files.
    • UserTesting

      UserTesting allows for easy remote usability testing. You can run an unmoderated test on your website with a predefined user base.
    • Validately

      With Validately, choose either unmoderated or moderated testing. To test a product, add a link to your website or prototype. Testers will receive a URL to take the test or join an moderated session. After the session, you’ll receive a qualitative report and sharable videos. Pricing starts from $49 per month.
    • Usabilla

      Collect both qualitative and quantitative insights from users to make the right design decisions. Among testing deliverables, you’ll receive nice heat maps.

    Conduct Moderated Remote Testing

    You could conduct remote moderated sessions using Google Hangouts or Skype. Simply ask users to share their screen, and then see how they interact with your product. Don’t forget to record the session for further analysis. (Record both video and audio; without audio, it might be hard to tell why certain behavior occurred.)

    Avoid “Professional” Testers

    The downside of remote testing is that many participants get tested so frequently that they’ve learned to focus on certain aspects of a design. To compensate for possible “professional” testers, you’ll need to analyze the test sessions (for example, by watching the video recordings), and exclude results from people who don’t seem to provide genuine feedback.

    8. Engage The Whole Team In The Process

    Involve the whole product team in the testing process. Having an opportunity to observe users will help the whole team understand the problems with usability and to empathize with users. Testing enables you to build shared understanding, even before the team starts designing.

    Discuss the Testing Strategy With the Team

    Product design is a team sport. And because testing is an essential part of the design process, it should be discussed with all team players. Direct involvement in preparing the test will make team members more interested in the activity. As the person responsible for UX research, you should make it clear how your team will use the findings from the usability tests.

    team process
    (Image: General Assembly) (View large version)

    Ask Everyone to Watch the Sessions

    You can’t expect the entire team to join the testing sessions. In most cases, it isn’t necessary for everyone to observe all usability testing first-hand (although it might be desirable). But you can record the testing sessions on video and share it with colleagues. Video can be extremely helpful during design discussions.

    Ask Team to Help With Analysis

    One thing that slows down many forms of usability testing is analysis. Extracting findings from the data collected during testing sessions could take days or even weeks. But if the entire team watches the sessions and takes notes, they will be better able to summarize the findings and decide on next steps.

    9. Test Before, During And After The Redesign

    A common question among many product teams is, “When should we test?” The answer is simple: Test before a design or redesign, test during the design, and then test afterwards, too.

    • Before a design or redesign

      Testing would be conducted during the discovery phase of the UX design process. If you plan to redesign an existing product, usability testing could help you identify the biggest pain points in the current version. Consider testing competitors’ products, to compare results.
    • During a redesign

      If resources exist, do this at every milestone of the project. In the time it takes to build and launch a new product or feature, you could run several testing sessions and improve the prototype after each one.
    • After a redesign

      Knowledge of how real users use the product will help you make it better.

    10. Don’t Try To Solve Everything At Once

    Trying to solve everything at once is simply impossible. Instead, prioritize your findings. Fix the most important problems first, and then test again. However, if that’s impossible (for example, if the problems are too big to tackle), then prioritize problems according to their impact on revenue.

    Conclusion

    You can’t afford to skip testing, because even a simple round of testing could make or break your product. Investment in user testing is just about the only way to consistently generate a rich stream of data on user behavior. Thus, test early, test often.

    This article is part of the UX design series sponsored by Adobe. Adobe XD tool is made for a fast and fluid UX design process, as it lets you go from idea to prototype faster. Design, prototype and share — all in one app. You can check out more inspiring projects created with Adobe XD on Behance, and also sign up for the Adobe experience design newsletter to stay updated and informed on the latest trends and insights for UX/UI design.

    Smashing Editorial(vf, yk, al, il)

    Maximizing The Design Sprint

    Following a summer of Wonder Woman, Spiderman, and other superhero blockbusters, it’s natural to fantasize about having a superpower of your own. Luckily for designers, innovators, and customer-centric thinkers, a design sprint allows you to see into the future to learn in just five days what customers think about your finished product.

    As a UX consultant and in-house design strategist, I have facilitated dozens upon dozens of design workshops (ranging from rapid prototyping sessions to, of course, sprints). The sprint is by far the most effective process I’ve seen to drive customer-first decision making in a design thinky way.

    What Is A Sprint?

    Because ‘sprint’ is used to refer to a variety of processes, I’ve given a brief description of a few different types of sprints to clarify:

    • Development sprint: a set period of time for software development work and review. (This is not what I’m writing about.)
    • (Regular) design sprint: set period of time for the design team to create functional designs ahead of the development sprint. (This is still not what I’m writing about, but check out a previous Smashing article, Getting Started with Design Sprints.)
    • (Google) design sprints: a 5-day process to understand if an idea maps to a customer need or opportunity without having to launch a minimal product. (Finally, this is what I’m writing about.)
    Learn from meaningful customer feedback without having to build and launch a product. (Image: Google Ventures)

    Now that we are all on the same page about different kinds of sprints, let’s take a look at an example:

    Recently, I participated in a sprint that had the big goal to use our pre-built kit to build an app (coincidentally) in five days or less. Given that this process normally takes months, we assumed the faster, the better, right? We wanted to make sure this assumption was correct and sprinted this idea.

    We more or less followed the process suggested on the Google Venture’s website. If you are completely unfamiliar with the design sprint, here’s a handy 90 second intro.

    (We are aware that there’s a call to action to buy the book at the end of this video, but if you are not at all familiar with the design sprint, it will provide you with a quick introduction. We are not in any way affiliated with Google Ventures nor are trying to promote the book.)

    This is what our process looked like:

    1. Monday, we set our goals, targets, and learning about potential users from customer experts.
    2. Tuesday consisted of drawing from inspirations and sketching a solution.
    3. Wednesday involved choosing a winning sketch and turning it into a storyboard.
    4. Thursday, we prototyped.
    5. Friday, we tested the prototype with customers.
    Example of a winning sprint sketch that was turned into a storyboard and prototype.
    Example of a winning sprint sketch that was turned into a storyboard and prototype. (Large preview)

    By Friday, our prototype reflected the flow of a customer learning about our kit, viewing examples of the types of apps they could build, and launching their own app in a short span of time. We thought we did a great job, as the prototype illustrated our main value propositions:

    • The features that would be available through our kit.
    • The speed with which they could have a fully functional app of their own using our kit.

    However, we tested our prototype with customers and learned that our value proposition didn’t really resonate. While it would be great to have speedy deployment, our kit did not allow for the level of customization developers required to meet the needs of their own customers.

    Was it a waste of time? Of course, not. If we hadn’t explored and validated the idea with a design sprint, can you imagine the time and effort that would have gone into implementing the wrong thing? Avoiding wrong turns is the superpower of the sprint.

    This superpower allows us to make major decisions and sidestep business paralysis. But with so much to pack into so little time, every minute — from prep to during to after — is critical. I’ll share what I’ve learned to maximize the sprint experience and help us flex our new superpower.

    • Before the sprint: setting yourself up for success.
    • During the sprint: maximizing your sprint week.
    • After the sprint: how to keep the momentum.

    Before The Sprint: Setting Yourself Up For Success

    Successful sprints start with good preparation. First, know that it’s a lot of logistical work. Even with the Sprint book’s explicit guidance, securing the right space, time, and people is a big undertaking, so give yourself 3 weeks. Consider a schedule that looks something like this:

    • Week 1: Confirm the sprint with stakeholders and send out an email getting people to book travel if necessary. Tell them now about the NO DEVICES rule — one of the design sprint’s key ideas, which basically says that the electronic devices shouldn’t be used during the sprint activities. Start scheduling users and customer experts to interview. Book your meeting space. If you can’t get a room for the full week at an office space, consider meeting at a hotel or nearby rental facility. If you haven’t already, start customer research (more on that later).
    • Week 2: Continue to follow up on your interviews.
    • Week 3: Gather supplies (recommend buying sprint kit), schedule interviews, and send a reminder email to participants (remind them about the NO DEVICES rule).
    Give yourself three weeks only to prepare the design sprint properly. Note how every week have a strong focus on involving customers. Large preview

    Notice that all three weeks involve scheduling participants. This is worth emphasizing because securing quality customer interviews can take time.

    Quality interviews are with people who match your target customer. Getting the right people ensures that your feedback at the end of the week will be meaningful and adequate to drive decisions and next steps.

    In the sprint example above (the development kit), we were testing an idea aimed at developers. The prototype we created wouldn’t make sense to non-developers, so we would have had difficulty recruiting the right testers on Craigslist or at a local Starbucks (unless we got really lucky!). Instead, we took weeks tracking down the right participants and finding interview times that worked for them. In this particular sprint, we drew from a pool of existing customers.

    Other ways to find good participants is to leverage people in your network, or use sites like usertesting.com to screen potential participants. If your value proposition applies to a more general audience, you will not need as much lead time to secure the right people, but making sure you have the right testers is essential for a successful sprint.

    If there’s opportunity to do so, I recommend conducting at least some kind of customer research. Get a sense of the day-to-day tasks and goals of your customers through actives such as interviews and ethnographic studies (you will most likely need to start these activities more than 3 weeks in advance). Waiting until the end of the week to hear from customers in your sprint makes you less likely to have a value proposition that meets actual needs or opportunities. Without customer research, you are still relying on your best guess to understand what customers want or what would add value. Even though the sprint process takes into consideration input from customer experts, this is never as effective as hearing from customers directly. Instead, infuse the voice of the customer into your sprint from the start.

    Now that you’ve set yourself up for success, let’s look at how you can maximize your sprint week.

    During The Sprint: Maximizing Your Sprint Week

    Like any good design thinking process, start with your customer. Right after you introduce the sprint and set expectations for the week, present the findings of the customer research. Do this at the very beginning on Monday so that your knowledge of the customer will influence the goal, target, and types of questions you ask your customer experts.

    Start with empathy. Who is your customer and what is important to them? (Image: Nielsen Norman Group) (Large preview)

    The discussion does not have to be exhaustive, but make sure the team knows enough to begin the sprint by building empathy for your customer. This will be the foundation for the rest of the week’s activities, including sketching on Tuesday and prototyping on Thursday.

    When creating a prototype, consider the appropriate scope and fidelity. The Sprint book recommends a high-fidelity prototype for a more realistic testing experience but only allows for prototyping to occur from 10am–3pm on one day.

    We’ve found it quite difficult to build a high-fidelity prototype within the suggested five hours. For example, I’ve participated in a sprint that had three makers (makers in a design sprint are participants who create the prototype). Even with three makers, the prototype was not completed until well into the night. This prevented the team from doing a test run through prior to customer interviews, and the output of the sprint suffered.

    Is there any way we can avoid this kind of stress and optimize the process? Allow me to share a few tips for maximizing the possibility of producing a viable prototype, as well as how to get the most out of the customer interview on Friday.

    The Prototype Maker Should Be Comfortable With The Scope

    The maker (again, the person who will build the prototype) has the most realistic view on how long it will take to create the prototype — since they only have one day (Thursday) to do so. The maker should firmly remind the decider (the term the Sprint book uses for the person who will make the major decisions during the design sprint) to focus on validating the value proposition.

    People, myself included, get excited about the opportunity to get real feedback from potential customers and try to include non-essential things to test.

    For example, we once prototyped a chat feature that was unrelated to our value proposition because our decider wanted to know if people would use it for support. That kind of insight would be interesting, but creating and testing these nice-to-haves can happen later.

    When these situations happen, the (prototype) maker should be able to overrule the decider.

    Be Realistic About The Level Of Fidelity

    The correct level of fidelity is the one you can create in the given time that illustrates your value proposition.

    • Use realistic content and data.
    • Illustrate the essential components of your value proposition in a way that is functional (i.e. for a website, critical path for a task is clickable).
    • Do not build out features that do not illustrate the value proposition (unless you have the time!).

    Consider Plant Stops, a fictitious company that sells trees and planting services. Plant Stops has always been a brick and mortar business but wants to expand. They want to sprint to see if customers would be interested in buying trees online. Let’s look at an example page from their prototype in varying levels of fidelity from too low to too much to just about right.

    Large preview

    Too low. The fidelity of this page is too low. It is not clear what task the customer is trying to accomplish and does not illustrate the idea that Plant Stops is testing.

    Large preview

    Too much. This example illustrates the idea at a high fidelity level. In order to be realistic, it contains features that are not necessary to validate the value proposition and should only be designed once all other critical components are created.

    Large preview

    Just about right. While not realistic, this example also conveys the idea and is sufficient to test with customers. Omitting additional features will free up time for more effective flow design.

    More Than A Usability Test

    After you’ve created a prototype on Thursday, it is time to test your value proposition on Friday. In my experience it is easy to turn customer interviews into usability tests (you don’t want to do that). This is especially easy if your tester is a UX person with experience giving usability tests (do I sound guilty yet?)

    It took me a few sprints to un-train myself from asking only usability questions. For example, instead of asking, “where would you expect so and so to be?” I should have been asking, “what did you like or dislike about so and so?” Even more so, the best approach is to avoid specific questions and encourage the customer to think out loud.

    Similarly, you might also need to walk users through the concept more than would be needed for a usability test. For instance, rather than watching customers fumble around trying to navigate the menu you created in 3 minutes the day before, get them to the key features as soon as possible to start getting feedback on your value proposition.

    Usability feedback is definitely a plus, but you really want to make sure you are getting customer input on your idea. At the end of your interview, ask meaningful wrap-up questions. The answers that you receive will inform your decision whether or not to move forward with the project. For example, ask questions like:

    • What were your overall impressions of X?
    • On a scale from 1-10 (1 being the least useful and 10 being the most useful), how useful is X?
    • Use five adjectives to describe X.

    Next steps

    At the end of the sprint week, your team needs to decide if you will move forward with your value proposition. If not, you’ll need to discuss if there’s anything that can be salvaged from the project or if it’s better just to cut your losses and move on. The latter rarely happens, though.

    Assuming you are moving forward with the validated concept, it’s important to stay focused. After such a successful and insightful sprint week, you wouldn’t want to lose the momentum, would you?

    After The Sprint: How To Keep The Momentum

    You’ve just had a week jam-packed with making decisions and progressing an idea. At the end of the week, people part ways and return to their day jobs. How do you keep the momentum? Here are some practical next steps and tips:

    1. Someone needs to be in charge. This could be the decider or someone the decider assigns to the role, such as a product owner or project manager. Ideally, this person was also a participant in the sprint.
    2. Decide what’s the minimum marketable product (MMP). What are the essential features and functions needed to deliver your value proposition? The customer feedback gathered during the sprint should drive this decision. All non-critical features (the nice-to-haves) should be saved for later.
    3. Make sure the prototype reflects the critical features of the MMP with UX design best practices applied.
    4. Test your prototype for usability. Now is the time to ask, “where would you expect so and so to be?”
    5. Get to work! Development can start using the customer-validated prototype. Your design team can start incorporating those nice-to-haves into the prototype, starting with the features that the product owner has prioritized based on customer feedback.
    6. Run more sprints. The design team would ideally conduct a few sprints ahead of the development team’s sprints. For example, if the development team is working in two-week sprints, then designers should schedule their sprints accordingly every two weeks, regardless of what type of design sprint they use. At the very least, the design sprints should consist of iterating on the prototype, testing with users, and passing off to the developers, ensuring that only customer-validated features are developed.

    Using this process, you have established a continuous customer feedback loop, starting with your sprint.

    Test Your New Superpower!

    Since embracing the sprint, I have seen ideas — that have had no traction for years — gain new momentum and interest. Months and months of meetings and discussions bypassed by one week of collaboration, design thinking, and customer-centric decision making.

    The tips gained from practical experience that I have outlined in the article will only make this effort more successful. So as you plan your next design sprint, remember how you can maximize your experience:

    1. Pre-sprint

    • Schedule early
    • Research your customers

    2. During-sprint

    • Start with the customer
    • Prototype at the right level
    • Conduct value proposition interview

    3. After-sprint

    • Put someone in charge
    • Iterate and validate
    • Get to work

    Now it’s time to test out your new superpower!

    Right-To-Left Development In Mobile Design

    The Middle Eastern market is growing at a rapid pace, and, as a result, demand for various IT products is also booming in the region. What is peculiar, though, is that Middle Eastern countries require design that is not only compatible with their needs and comfortable for their users, but that is also suitable to their language standards, making a serious adaptation process very important. Given that most languages spoken in the Middle East are written and read from right to left (such as Arabic, Hebrew and Urdu), developers often face a range of problems when creating products in those languages.

    Although this might seem like not that big of a deal, IT development for right-to-left (RTL) languages entails paying attention to a number of peculiarities. This is only further complicated by the fact that the RTL market is relatively new, and not many resources are available to help developers.

    Our experience with RTL development has enabled us to compile a thorough list of tips that are useful for anyone developing an RTL product (such as a website or mobile app). By following the tips closely, you should be able to navigate the challenging waters of RTL development and deliver a functional, user-friendly result.

    Flipping The Interface

    First and foremost, the interface must be flipped from right to left. You might think this is rather “D’uh” advice, but we simply could not disregard it, because it is in fact the very first thing to do.

    Here’s an example of Facebook’s left-to-right (LTR) design:

    Facebook’s log-in page in LTR design. (Image source: Facebook) (View large version)

    And here is the RTL version of Facebook:

    Facebook’s log-in page in RTL design. (Image source: Facebook) (View large version)

    There are several ways to achieve this.

    1. Using the dir Attribute or CSS

    If the basic markup is built with floating blocks, it will look something like the example below.

    For LTR design, pay attention to the styles. In this case, the link with logo will be fixed to the left, with the login-container to the right.

     <!doctype html> <html lang="en"> <head> <meta charset="utf-8"> <title>Example</title> <style> .float-left{ float: left; } .float-right{ float: right; } body[dir="rtl"] .float-left{ float: right; } body[dir="rtl"] .float-right{ float: left; } </style> </head> <body> <header> <a href="#"><img src="static/logo.png"></a> <nav></nav> </header> <main></main> <footer></footer> </body> </html> 
    Facebook’s top log-in bar in LTR design. (Image source: Facebook) (View large version)

    For RTL design, once you’ve assigned the body tag to the dir="rtl attribute, the whole markup will be mirrored, placing the logo to the right and login-container to the left. The opposite properties will be then applied to blocks with the float-left or float-right class.

    <body dir="ltr">

    The dir attribute specifies the text’s direction and display (either left to right or right to left). Normally, browsers recognize the direction because it’s assigned in the Unicode character set, but with the dir attribute, you can set whatever direction you want.

    The possible variants are dir="ltr", dir="rtl" and dir="auto". This attribute can also be rewritten with the CSS direction property.

    Because text direction is semantically tied to content and not to presentation, we recommend that, whenever possible, web developers use the dir attribute and not the CSS properties related to it. That way, the text will be displayed properly even in browsers that don’t support CSS (or in those where CSS support is turned off).

    Facebook’s top log-in bar in RTL design. (Image source: Facebook) (View large version)

    With this attribute, you can horizontally mirror images, reassign fonts, align text to either side of the page, etc. However, the manual way is fairly labor-intensive. There are tools to automate the assembly of RTL styles, which we’ll get to a bit later in this post. In the meantime, we’ll describe another way of dealing with markup directional changes.

    2. Using Flexbox

    Flexbox is popular among developers for a couple of good reasons. Not only does it provide flexibility when adjusting the alignment of page elements and other bits, but it also eliminates the need to reassign styles for RTL development. See the code snippets below for more details.

    For LTR:

     <div> <div>1</div> <div>2</div> <div>3</div> <div> 
    An example of flexbox layout in LTR design. (Image source: SteelKiwi) (View large version)

    For RTL:

     <div> <div>1</div> <div>2</div> <div>3</div> <div> 
    An example of flexbox layout in RTL design. (Image source: SteelKiwi) (View large version)

    The grid layout is also useful here. We set grid-template-areas in the containing block with {display: grid;} property (imagine it as a table with two columns and three rows). From the top: The header occupies the entire width of the screen, the sidebar is on the left, while the main content and the footer are on the right, one under another.

    For LTR:

     <divheader header"; "sidebar main" "sidebar footer";"> <div>header</div> <div>sidebar</div> <div>main</div> <div>footer</div> </div> 
    An example of basic direction of grid layout in LTR design. (Image source: SteelKiwi)

    For RTL, by changing the dir attribute, the horizontal axis with the grid class and the {display: grid;} property will adjust to the specified direction. The layout matrix is then inverted:

     <divheader header" "sidebar main" "sidebar footer"; dir="rtl"> <div>header</div> <div>sidebar</div> <div>main</div> <div>footer</div> </div> 
    An example of inverted grid layout matrix in RTL design. (Image source: SteelKiwi)

    Even though using tables to build layouts hasn’t been popular for a while now, they would still build flow direction as a component, just like in the previous examples, meaning that when you add the dir="rtl" tag, columns will start from the right and move from right to left. All table elements will follow this, unless the direction is clearly predefined beforehand.

    Character Encoding

    Save your file using a character encoding that includes the characters you need (UTF-8 is a good bet). Declare that you are going to use such characters in the head tag of your HTML page with:

    <meta charset="utf-8"/> 

    UTF-8 is a character encoding capable of encoding all possible Unicode code points, and it covers almost all languages, characters and punctuation symbols. Using UTF-8 also removes the need for server-side logic when individually determining each page’s character encoding or each incoming form submission. Coding helps to convert everything into binary numbers. For instance, “hello” in UTF-8 would be stored like this (in binary): 01101000 01100101 01101100 01101100 01101111.

    Formatted Text

    Try as hard as you can to avoid using bold and italics. Bold text would make readability extremely difficult in most RTL languages (especially Arabic), and italics is simply never used. As well, capital letters are almost always disregarded in RTL languages.

    An example of omitting capital letters in RTL languages. (Image source: SteelKiwi) (View large version)

    If you need to highlight a certain part of text in Arabic, overline it instead of underlining, interspacing or italicizing. Here is how we do it:

    <h1>مثال</h1> h1 { text-decoration: overline; } 
    An example of overlining Arabic text. (Image source: SteelKiwi)

    Make sure that all text is aligned to the right, and that font and font size are adjusted properly (better yet, customize them), because Latin fonts tend to affect Arabic readability rather poorly.

    Actually, the best way to deal with fonts is to speak to your client (assuming, of course, they speak the language). The thing is that languages such as Arabic tend to have a great number of spoken and written variations, and if you’re making a product catered specifically to some region, it should really display the language version used there. If you find this matter interesting, information about the history of Arabic writing systems is available here.

    In case your client isn’t a native speaker of the product’s language or isn’t able to help you, there is always the simple option of using one of the Google Noto fonts (there is one for every language, and all of them are free). Alternatively, Arabnet recommends 10 Arabic fonts (the list is from 2014, but things haven’t changed much in this area over the last three years). However, do keep in mind that your client always knows best which language variant is used most in their particular region, and if you have a chance to consult with them about it, do so right away.

    Also, remember that words in RTL languages are often much shorter than words in English. So, adjust to keep a balance in how text is displayed on the page.

    Icons

    Using icons in RTL development can be tricky. Keep in mind that some of them might have to be mirrored, and some could be considered offensive to people of some nationalities, so double-check that the icons you’re using make sense.

    Icons that are symmetrical and that don’t point in a particular direction should not be flipped.

    There is no need to mirror symmetrical icons. (Image source: SteelKiwi)

    On the other hand, icons that clearly point in a particular direction should be mirrored.

    Mirror icons that point to a side. (Image source: SteelKiwi)
    <span></span> body[dir="rtl"] { transform: scale(-1, 1); } 

    The scale (x, y) CSS function used in the example above modifies the size of an element. If set to 1, it does nothing, but when negative, it performs as a “point reflection” and can modify size.

    Icons that have characters or words from non-RTL languages don’t need to be mirrored. You should, however, localize them if necessary.

    Icons containing words or characters from non-RTL languages don’t need be translated, but should be localized if necessary. (Image source: SteelKiwi)

    Ensure that the icons you’re using are appropriate. For example, using a wine glass as a symbol for a restaurant or bar could be misunderstood because alcohol consumption is prohibited in Islam. Cultural peculiarities need to be taken into account, and developers should double-check that the symbols and icons they’re using are appropriate for the target market.

    Avoid culturally inappropriate icons. (Image source: SteelKiwi)

    Navigation Menus

    Logos, navigation buttons and menus should be located in the upper-right corner for RTL design. The two latter elements also need to be displayed in reverse order. You don’t, however, need to mirror all of the stuff related to controlling media content (such as play and pause buttons).

    Example of YouTube’s usage of media-content-management buttons in RTL design. (Image source: YouTube) (View large version)

    Digit Ordering

    The order of digits in numbers should not be changed for RTL. Note the phone number below. The digits are displayed in the same order in both LTR and RTL, but the telephone icon changes position. The same rule applies to other digits (such as addresses and other numeric strings).

    The order of digits shouldn’t change for RTL design. (Image source: SteelKiwi) (View large version)

    Position Of Control Buttons

    Even though people speaking RTL languages perceive and process information from right to left, many of them are right-handed. Thus, it would be a good idea not to mirror control buttons, so that users can interact with them comfortably. Instead, center them to resolve any issues. For instance, if the orange button shown below was located to the left, it’d be extremely difficult for people to reach it with their right thumb while holding their device in one hand:

    Placing the orange button to the left would be uncomfortable for users. (Image source: SteelKiwi) (View large version)

    In this case, it would be much more convenient for users if such important elements of interaction were large and located in the middle of the screen.

    Placing the orange button in the middle of the page would solve all convenience-related problems. (Image source: SteelKiwi) (View large version)

    The elements in the bottom tab bar below should be positioned from right to left. RTL also exists in the Persian language — see example below:

    In RTL design, the elements in the bottom tab bar should be positioned from right to left. (Image source: SteelKiwi)

    Navigation drawers should appear from the right side.

    In RTL design, drawers should appear from the right side. (Image source: SteelKiwi)

    Position Of Other Symbols

    The position of symbols that can be used for both RTL and LTR (such as punctuation marks) will depend on the direction of the text as a whole. This is because browsers process RTL words in the RTL direction, even though the data format starts from the beginning. Punctuation is converted only towards the specified direction.

    The following example should illustrate the issue better:

    You need to convert RTL and LTR strings into separate elements in order to have punctuation symbols appear in the right direction. (Image source: SteelKiwi) (View large version)

    To fix this problem, you can convert RTL and LTR strings (or text fragments) into separate elements. Then, specify their direction with either the dir attribute or the CSS direction property. In the first case, you would do this:

     <p dir="rtl">?سوف أعطي مثالا على ذلك. لا تمانع</p> <p dir="ltr">I will give an example. Don’t you mind?</p> 

    And in the second, this:

    .rtl-text { direction: rtl;}.ltr-text { direction: ltr;}

    Alternatively, you could also use the bdi tag to avoid this type of issue. However, it is only supported in Chrome (16) and Firefox (10).

    Separate RTL CSS File

    For basic CSS styles, you should create a separate RTL file and set the horizontal properties there (floating left and right, padding left and right, margins and so on), while also redefining them appropriately:

    div.class { width: 150px; height: 100px; float: left; padding: 0 15px 0 10px;}

    And in the rtl.css file:

    html[dir="rtl"] div.class { float: right; padding: 0 10px 0 15px;}

    If you need to eliminate some other LTR-directed features, you can always create and attach another separate rtl.css file.

    In case this approach doesn’t meet your needs well enough, you can create two separate style files for LTR and RTL. Various utilities can be applied to automate their assembly. One such program is css-flip (created by Twitter). With its help, you can easily compile a file with properties redefined for RTL from an existing source file.

    In input.css:

    p { padding-left: 1em;}

    And in output.rtl.css:

    p { padding-right: 1em;}

    You can also use replacements and exceptions, based on directives in the source file. For example, in input.css:

    p { /@replace: -32px -32px/ background-position: -32px 0; /@replace: ">"/ content: "<"; /@noflip/ float: left;}

    And in output.rtl.css:

    p { background-position: -32px -32px; content: ">"; float: left;}

    RTLCSS is another tool that supports replacements (exceptions) and makes it possible for developers to rename selectors, add local configurations of exception, and delete or add properties.

    You could also use plugins for assembly instruments, including for Gulp, Grunt and Webpack.

    For example, in input.css:

    .example { transform: translateY(10px) /*rtl:append:scaleX(-1)*/; font-family: "Helvetica Neue", Arial/*rtl:prepend:"Arabic fonts", */; font-size:1.3em/*rtl:1.2em*/; /*rtl:remove*/ text-decoration:underline; /*rtl:begin:ignore*/ margin-left:15px; padding-left:20px; /*rtl:end:ignore*/}

    And in output.rtl.css:

    .example { transform: translateY(10px) scaleX(-1); font-family: "Arabic fonts","Helvetica Neue", Arial; font-size:1.2em; margin-left:15px; padding-left:20px;}

    You can also make configurations for renaming selectors. Again, in input.css:

    /*rtl:begin:options: { "autoRename": true, "stringMap":[ { "name" : "prev-next", "search" : ["prev", "previous"], "replace" : ["next", "next"], "options" : {"ignoreCase":false} } ]} */slide-prev, .card-previous { content: ‘<’;}/*rtl:end:options*/

    And in output.rtl.css:

    .slide-prev, .card-previous { content: ‘>’;}

    Calendars

    Calendars are probably one of the most important and complicated aspects of RTL design, because calendar years are different between LTR and RTL geographic regions.

    Hijri

    Hijri, the Islamic calendar, is lunar-based, which means that a year in the Gregorian calendar is longer than in the Islamic calendar. As a result, Hijri always has to shift according to the Gregorian calendar.

    Hebrew Calendar

    The Hebrew calendar, which has 12 lunar months, with an extra month added every few years, also differs from the Gregorian calendar. These differences make it hard to find an adequate tool for working with both Gregorian calendars in LTR scripts and non-Gregorian calendars in RTL scripts.

    Tools for Displaying Calendars

    One popular tool is FullCalendar, because it calculates time based on Moment.js. However, it cannot convert between different types of calendars and is only useful for localizing dates and displaying RTL content.

    dijit/Calendar is able to display non-Gregorian calendars but has a rather limited range of tasks.

    The DateTimeFormat constructor is an invaluable property for international objects. It makes it possible to pass additional options to the argument string when specifying the exact formatting for time and date.

    Below, you can see how a date should be converted from the Gregorian calendar to the Islamic one:

    var sampleDate = new Intl.DateTimeFormat("ru-RU-u-ca-islamicc").format(new Date()); // => "26.03.2017" console.log(sampleDate); // => "27.06.1438 AH"

    Abbreviations (Days Of Week)

    Although abbreviating the names of the days of the week is standard in many languages, this isn’t possible in Arabic because all of them start with the same letter. Instead, simply display their whole names and reduce the font size.

    All names of weekdays start with the same letter in Arabic, meaning that you cannot abbreviate them like you would in English. (Image source: SteelKiwi) (View large version)

    Internationalization

    If your product requires internationalization, consider the ECMAScript Internationalization API. It comes with a language-sensitive string comparison and relevant formatting for numbers, dates and time.

    Another important point is that ECMAScript supports not only Arabic, but also a wide range of other combinations, such as Arabic-Arabic and Arabic-Tunisian.

    Also, keep in mind that the use of Eastern and Western Arabic numerals might depend on the language variant. Some regions might use Eastern Arabic numerals (123), while others use Western ones (١٢٣).

    Formatting Arabic-Egyptian Numerals

    var sampleNumber = new Intl.NumberFormat(‘ar-EG’).format(12345); console.log(sampleNumber); // => ١٢٬٣٤٥

    In Tunisia, for instance, Eastern Arabic numerals are usually used:

    var sampleNumber = new Intl.NumberFormat(‘ar-TN’).format(12345); console.log(sampleNumber); // => 12345

    Examples Of Native Arabic Websites

    Arageek is dedicated to all hip geek news around the world. (Image source: Arageek) (View large version)
    Hawaa Forum is an online community for women. (Image source: Hawaaworld.com) (View large version)
    Saudileague
    Saudi League is dedicated to football in Saudi Arabia, with news, tournament days, info about teams and more. (Image source: Saudileague.com) (View large version)

    Share Your Experience!

    Cultural and linguistic peculiarities can be a hassle when you’re developing for different regions and markets. When it comes to the RTL market, developers must use their knowledge to adhere to a completely different set of rules, making the whole process more challenging and potentially frustrating. Using the 12 tips above, we hope you’re able to overcome some of the most common problems with RTL development.

    If you have encountered any obstacles related to RTL development, please describe them (along with the solutions you’ve found) in the comments section below. The more that developers share their knowledge and experience, the easier it will be for all of us to deal with the peculiarities of RTL development.

    Smashing Editorial(da, vf, yk, al, il)

    Level-Up Email Campaigns With Customer Journey Mapping

    I became a huge fan of customer journey mapping (CJM) the first time I was introduced to it. And after a few years of mapping, tweaking and presenting maps, my team and I started looking for other more exotic uses of this technique. The law of the instrument at its best, I suppose. Well, seek and ye shall find.

    Customer journey mapping is a visualization technique that helps marketing specialists, user experience designers, and product and business owners see the journey people take when interacting with products and services. It is a great way to put on your customer’s shoes and see where your business fails to deliver a great user experience.

    The way CJM works is pretty straightforward: You collect user research data, break down the entire funnel into steps (i.e. stages) and describe each stage from multiple points of view, such as your business goal, the customer’s goals, touchpoints (the very moments of interaction), customers expectations and pain points, their thoughts and feelings, etc. In the end, you have a table that looks something like this:

    an example of customer journey map.
    A customer journey map example (Image: UXPressia) (View large version)

    From this table, you can tell at which points customers are not happy, and you can come up with some ideas to improve the situation.

    Сustomer journey mapping is mainly used to find flaws in the entire path of the user, but I was curious if there was some unconventional way to use this technique. Turns out there is, and here the story of how it found me.

    It’s Not A Journey Map… Or Is It?

    After reading Baremetrics CEO Josh Pigford’s brilliant article about an email campaign that Baremetrics created to reduce churn and convert customers, our team at UXPressia decided that we needed something similar for our app.

    Fast-forward a few weeks, and we had a sequence of emails ready to fly to our users’ mailboxes. They looked somewhat like this:

    A chain of printed emails that we hung on our board
    A chain of printed emails that we hung on our board (Image: UXPressia) (View large version)

    These printed emails stuck around on our whiteboard for a while. Then, one day, while we were having coffee after a long and tedious CJM workshop, one of the participants glanced at the emails still hanging on the board and asked, “What’s this journey map for, guys?”

    “Oh no, that’s not a journey…” — I was about to say that this was not a journey map, but I suddenly stopped. Our guys looked at each other. “Are you thinking what I am thinking?” Yes, our email campaign had stages and our business goals, so it could be. After all, we made a tool for mapping customer journeys, so it was a great opportunity for us to put it to the test. The question was: Is it OK to just cut out one channel from the entire user journey and focus on it solely?

    On the one hand, customer journey mapping is all about a holistic approach, so it isn’t entirely right to focus on just one channel. On the other hand, we want to follow the “individuals and interactions over processes and tools” principle from the agile manifesto.

    Besides, we tried our best to make our emails as personal as possible. Today, email campaigns are no longer carpet-bombing monologues. They are more of ongoing conversations in which we try to bond with our users. And customer journey mapping is all about finding a better and more personal approach.

    So, why not try?

    Everyone in the room started pitching ideas. Someone noticed that we had our goals linked to every email. “If we could add our user goals and see if both goals match…” he said.

    At this point, it was clear that this was going to become a map. But two CJM sessions on the same day? You have got to be kidding. We took a break and agreed to sleep on this idea.

    Doubts, The First Draft

    The next day, after rebooting our brains, we gathered in the same room and asked ourselves, “What is the problem we are trying to solve here?” And is there any problem in the first place?

    Well, have you ever seen how email campaigns are stored, organized and manipulated? We had a Google Doc with text and pictures, and it was kind of fine, although it was not easy to get a bird’s-eye view of the whole campaign all at once.

    Email campaign in Google Docs
    A screenshot from Google Docs, where we built the initial email campaign (Image: UXPressia) (View large version)

    Our campaign was not very long and complex. It was a sequence of about 12 emails in which we welcome our users, give them tips and do some upselling.

    Now, imagine if you had a longer campaign consisting of 50 emails triggered at different moments. I remembered my friend telling me how his company had an enormous spreadsheet file linking to different sources with multiple emails.

    And there is no way to evaluate each letter out of the context. Setting up your campaign in some tool like MailChimp or Intercom would make your campaign a lot less messy, but you would still have to open each email to see the details.

    Email campaign set up in Intercom
    This is how our campaign looked in Intercom (Image: UXPressia) (View large version)

    Turns out that hundreds of people working on email campaigns have terrible experiences themselves while crafting a better experience for others. Trying to unweave webs of interrelated email letters scattered over a spreadsheet would drive anyone crazy. This had to stop.

    So, we rolled up our sleeves and drafted the first map using emails from our campaign.

    The first draft of our email journey
    The first draft of our email journey (Image: UXPressia) (View large version)

    By mapping out the whole chain of emails on a single canvas, we could finally see everything in one place. Timing, email texts, business goals at each stage, as well as goals of each letter — it was all there. Having it all aligned in such a way instantly raised (and even answered) questions like:

    • “Are we bombarding our users with a number of emails from the same person? Would it be more appropriate to introduce someone new?”
    • “Is the timing correct and in line with the overall experience?”

    And these questions were way easier to answer once we saw the whole picture. This alone was valuable enough because this clarity turned out to be a huge time-saver.

    For example, shortly after the launch of our campaign, we noticed a pretty high unsubscribe rate from our emails. We tried to understand why this was happening and what we could do to fix it. Then, we looked at our email map and realized that the time gap between the first two emails was quite short, so we increased it. Guess what? The unsubscribe rate slowed down. This would have been more difficult to troubleshoot without the clear picture we had from customer journey mapping.

    But we decided to take it up a few notches.

    Leveraging Personas

    Persona example
    Persona example (Image: UXPressia) (View large version)

    Remember I said we were trying to find a better and more personal approach? That’s what personas are best at. And having a well-researched persona when creating this email campaign was a game-changer for us.

    By that time, we had already defined our customer personas, so it was no biggie to take each email and read it as if the reader was our persona.

    A Brief Example

    In one of our letters, we asked our users to tell us about themselves, so that we could make some suggestions and offer personalized help just in case. We expected them to drop us emails with some really short stories. So we “read” this email to our personas. Hey, picture a bunch of fellows reading to a poster on a wall. Bonkers!

    Our team reading email to personas
    Our team reading email to personas (Image: UXPressia) (View large version)

    We tried to understand why this or that persona wouldn’t answer, and we realized that what we had in mind was not the way to go. What if our business-owner persona didn’t have time to sit there and compose emails? What could we offer to eliminate this objection? A quick call? Meh. Maybe. An online poll with predefined answers? Better!

    So, using personas certainly had a great impact on our email campaign in the end.

    Campaigns For Different Personas And A/B Tests

    Example of a CJM for A/B tests or multiple personas
    Example of a CJM for A/B tests or multiple personas (Image: UXPressia) (View large version)

    By the way, what if you have multiple personas in your email campaign? That poor spreadsheet! Unless, again, you use customer journey mapping. In this case, we’d be able to easily map different letters to corresponding personas — and even find where these emails intersect!

    Example

    In her case study, one of our customers told us an interesting story. She was working on a complicated email campaign for multiple personas. The tricky part was to bring together all possible scenarios and see which email she should write for each specific case.

    And she was quite amazed by how customer journey mapping saved her a lot of time and effort. Once all emails had been mapped out, it became apparent which letters repeated, so she could merge them into one.

    This applies not only to scenarios like this one, but also to A/B tests. Imagine doing the same without customer journey mapping. Ugh! But wait, the best part is yet to come.

    Email Campaign On CJM Steroids

    And here is it. Once we started putting our campaign on CJM steroids, there was no going back. Customer journey mapping offers a ton of sections that we could use to take our email campaign to a whole new level. We tried some of them, and the results were quite surprising.

    User Expectations and Goals

    User goals on our email journey map
    User goals on our email journey map (Image: UXPressia) (View large version)

    Adding user goals and expectations to our map cocktail changed the way we saw our email campaign for the better. When sending an upsell email, is this what our user expects from us at that very moment? Does the goal of this letter match the goal of our customers?

    By that moment, we had already rolled out our campaign, so we had some stats on hand. And adding these sections and answering these questions made us realize why the unsubscribe rate for some of our emails was so high. Speaking of which…

    Key Performance Indicators and Other Metrics

    KPI section in our email journey campaign
    KPI section in our email journey campaign (Image: UXPressia) (View large version)

    Now, what if we had real statistics under each email? Seeing how this or that letter performed enabled us to instantly find where our campaign hit the dirt. It did require some maintenance, but in the end, it was totally worth all the effort.

    Quote or User Response

    Quote section in our email journey map
    Quote section in our email journey map (Image: UXPressia) (View large version)

    Because we believe that email campaigns are conversations rather than monologues, we expect our users to say something back. Why not add some of their responses to our map? They could be from a single quote or an entire response. And based on their reactions, we were able to draw an…

    Experience Graph

    Experience graph based on KPI and user responses
    Experience graph based on KPI and user responses (Image: UXPressia) (View large version)

    The experience graph made it so easy for us to see the whole flow of our email campaign. Tracking performance enabled us to see which emails failed most and which did the best job. For us, this was priceless.

    Problems and Ideas

    Finally, once we had identified problematic emails in our campaign, it was time to think about what caused fails and how we could improve their performance. We pitched some ideas and started testing them ASAP!

    Wrapping Up

    An email journey map we ended up with
    An email journey map we ended up with (Image: UXPressia) (View large version)

    When we finally called it a day (or, rather, a night), everyone was so inspired. Using customer journey mapping to map our email campaign turned out to be not just a huge timesaver, but a well of insights, too. Not to mention that we were able to achieve a 40% open rate! Not a bad result in today’s world, where users develop email-blindness syndrome.

    Of course, using CJM for mapping email campaigns will not work for all cases, but it was a lifesaver — and not just for us.

    One of our customers transformed their existing email campaign the same way shortly after our debut. What they did was compare the email journey they created with the customer journey map they already had. Once they saw all emails on a single CJM canvas right next to the customer journey map, they got quite a few insights, like:

    • The first email in the campaign promoted the web application heavily right after a user downloaded the mobile app. The business goal at this stage was to decrease the number of users leaving the mobile app, but they were encouraging people to do just that!
    • The second email was pushing people towards providing more personal data. But from looking at the CJM as a whole, it was obvious that the timing was completely wrong: It happened at the stage when the majority of users were not yet ready to share anything — they simply hadn’t yet perceived any value from using the app.
    • The third email promoted the blog, which indeed had some great content. But the content was focused on just two personas, whereas the email campaign was sent to everyone. The majority of users were obviously not interested, so they kept unsubscribing.

    These were not all of the insights they had, but even with these, it was pretty clear that the campaign needed some rethinking. Even more importantly, they already knew what had to be changed.

    Anyway, here are some ideas about when transforming an email campaign into an email journey map will work for you as well:

    • You are working on a massive email campaign that you want to be consistent and well crafted as much as sympathetic and humane.
    • You believe that your team should try CJM, but people hesitate to engage because of the time commitment and unclear value. Seeing how it works for one channel would be less time-consuming and might help to convince your team to try a full-blown customer journey map after all.
    • You want to present campaign content to clients or stakeholders (which would be way more attractive than the bunch of separate files mentioned before).

    The worst-case scenario here is that you would put your emails in order and save a lot of time in the long run.

    Plus, you can do the same thing not just with emails but with virtually anything, be it call scripts for support or sales, alongside postal or face-to-face interactions.

    Oh, and one more thing. We created a free template you can use to start mapping your email journey now! It has a predefined persona and all the sections we used in our own journey map.

    But what about you? Have you tried using CJM for email campaigns? What insights can you share? Do you know of any unusual uses of CJM? Share your ideas in comments!

    Links and Resources

    (al)

    Understanding The Vary Header

    The Vary HTTP header is sent in billions of HTTP responses every day. But its use has never fulfilled its original vision, and many developers misunderstand what it does or don’t even realize that their web server is sending it. With the coming of the Client Hints, Variants and Key specifications, varied responses are getting a fresh start.

    What’s Vary?

    The story of Vary starts with a beautiful idea of how the web should work. In principle, a URL represents not a web page, but a conceptual resource, like your bank statement. Imagine that you want to see your bank statement: You go to bank.com and send a GET request for /statement. So far so good, but you didn’t say what format you want the statement in. This is why your browser will also include something like Accept: text/html in your request. In theory, at least, this means you could say Accept: text/csv instead and get the same resource in a different format.

    Illustration of content-negotiated conversation between user and bank
    (View large version)

    Because the same URL now produces different responses based on the value of the Accept header, any cache that stores this response needs to know that that header is important. The server tells us that the Accept header is important like this:

    Vary: Accept

    You could read this as, “This response varies based on the value of the Accept header of your request.”

    This basically doesn’t work on today’s web. So-called “content negotiation” was a great idea, but it failed. This doesn’t mean that Vary is useless, though. A decent portion of the pages you visit on the web carry a Vary header in the response — maybe your websites have them, too, and you don’t know it. So, if the header doesn’t work for content negotiation, why is it still so popular, and how do browsers deal with it? Let’s take a look.

    I’ve previously written about Vary in relation to content delivery networks (CDNs), those intermediary caches (such as Fastly, CloudFront and Akamai) that you can put between your servers and the user. Browsers also need to understand and respond to Vary rules, and the way they do this is different from the way Vary is treated by CDNs. In this post, I’ll explore the murky world of cache variation in the browser.

    Today’s Use Cases For Varying In The Browser

    As we saw earlier, the traditional use of Vary is to perform content negotiation using the Accept, Accept-Language and Accept-Encoding headers, and, historically, the first two of these have failed miserably. Varying on Accept-Encoding to deliver Gzip- or Brotli-compressed responses, where supported, mostly works reasonably well, but all browsers support Gzip these days, so that isn’t very exciting.

    How about some of these scenarios?

    • We want to serve images that are the exact width of the user’s screen. If the user resizes their browser, we would download new images (varying on Client Hints).
    • If the user logs out, we want to avoid using any pages that were cached while they were logged in (using a cookie as a Key).
    • Users of browsers that support the WebP image format should get WebP images; otherwise, they should get JPEGs.
    • When using a browser on a high-density screen, the user should get 2x images. If they move the browser window onto a standard-density screen and refresh, they should get 1x images.

    Caches All The Way Down

    Unlike edge caches, which act as one gigantic cache shared by all users, the browser is just for one user, but it has a lot of different caches for distinct, specific uses:

    Illustration of caches in the browser
    (View large version)

    Some of these are quite new, and understanding exactly which cache the content is being loaded from is a complex calculation that is not well supported by developer tools. Here’s what these caches do:

    • image cache

      This is a page-scoped cache that stores decoded image data, so that, for example, if you include the same image on a page multiple times, the browser only needs to download and decode it once.
    • preload cache

      This is also page-scoped and stores anything that has been preloaded in a Link header or a <link rel="preload"> tag, even if the resource is ordinarily uncacheable. Like the image cache, the preload cache is destroyed when the user navigates away from the page.
    • service worker cache API

      This provides a cache back end with a programmable interface; so, nothing is stored here unless you specifically put it there via JavaScript code in a service worker. It will also only be checked if you explicitly do so in a service worker fetch handler. The service worker cache is origin-scoped, and, while not guaranteed to be persistent, it’s more persistent than the browser’s HTTP cache.
    • HTTP cache

      This is the main cache that people are most familiar with. It is the only cache that pays attention to HTTP-level cache headers such as Cache-Control, and it combines these with the browser’s own heuristic rules to determine whether to cache something and for how long. It has the broadest scope, being shared by all websites; so, if two unrelated websites load the same asset (for example, Google Analytics), they might share the same cache hit.
    • HTTP/2 push cache (or “H2 push cache”)

      This sits with the connection, and it stores objects that have been pushed from the server but have not yet been requested by any page that is using the connection. It is scoped to pages using a particular connection, which is essentially the same as being scoped to a single origin, but it is also destroyed when the connection closes.

    Of these, the HTTP cache and service worker cache are best defined. As for the image and preload caches, some browsers might implement them as a single “memory cache” tied to the render of a particular navigation, but the mental model I’m describing here is still the right way to think about the process. See the specification note on preload if you’re interested. In the case of the H2 server push, discussion over the fate of this cache remains active.

    The order in which a request checks these caches before venturing out onto the network is important, because requesting something might pull it from an outer layer of caching into an inner one. For example, if your HTTP/2 server pushes a style sheet along with a page that needs it, and that page also preloads the style sheet with a <link rel="preload"> tag, then the style sheet will end up touching three caches in the browser. First, it will sit in the H2 push cache, waiting to be requested. When the browser is rendering the page and gets to the preload tag, it will pull the style sheet out of the push cache, through the HTTP cache (which might store it, depending on the style sheet’s Cache-Control header), and will save it in the preload cache.

    HTTP/2 PUSH flow through browser caches
    (View large version)

    Introducing Vary As A Validator

    OK, so what happens when we take this situation and add Vary to the mix?

    Unlike intermediary caches (such as CDNs), browsers typically do not implement the capability to store multiple variations per URL. The rationale for this is that the things we typically use Vary for (mainly Accept-Encoding and Accept-Language) do not change frequently within the context of a single user. Accept-Encoding might (but probably doesn’t) change upon a browser upgrade, and Accept-Language would most likely only change if you edit your operating system’s language locale settings. It also happens to be a lot easier to implement Vary in this way, although some specification authors believe this was a mistake.

    It’s no great loss most of the time for a browser to store only one variation, but it is important that we don’t accidentally use a variation that isn’t valid anymore if the “varied on” data does happen to change.

    The compromise is to treat Vary as a validator, not a key. Browsers compute cache keys in the normal way (essentially, using the URL), and then if they score a hit, they check that the request satisfies any Vary rules that are baked into the cached response. If it doesn’t, then the browser treats the request as a miss on the cache, and it moves on to the next layer of cache or out to the network. When a fresh response is received, it will then overwrite the cached version, even though it’s technically a different variation.

    Demonstrating Vary Behavior

    To demonstrate the way Vary is handled, I’ve made a little test suite. The test loads a range of different URLs, varying on different headers, and detects whether the request has hit the cache or not. I was originally using ResourceTiming for this, but for greater compatibility, I ended up switching to just measuring how long the request takes to complete (and intentionally added a 1-second delay to server-side responses to make the difference really clear).

    Let’s look at each of the cache types and how Vary should work and whether it actually works like that. For each test, I show here whether we should expect to see a result from the cache (“HIT” versus “MISS”) and what actually happened.

    Preload

    Preload is currently supported only in Chrome, where preloaded responses are stored in a memory cache until they are needed by the page. The responses also populate the HTTP cache on their way to the preload cache, if they are HTTP-cacheable. Because specifying request headers with a preload is impossible, and the preload cache lasts only as long as the page, testing this is hard, but we can at least see that objects with a Vary header do get preloaded successfully:

    Test results for link rel=preload in Google Chrome
    (View large version)

    Service Worker Cache API

    Chrome and Firefox support service workers, and in developing the service worker specification, the authors wanted to fix what they saw as broken implementations in browsers, to make Vary in the browser work more like CDNs. This means that while the browser should store only one variation in the HTTP cache, it is supposed to hold onto multiple variations in the Cache API. Firefox (54) does this correctly, whereas Chrome uses the same vary-as-validator logic that it uses for the HTTP cache (the bug is being tracked).

    Test results for service worker cache in Google Chrome
    (View large version)

    HTTP Cache

    The main HTTP cache should observe Vary and does so consistently (as a validator) in all browsers. For much, much more on this, see Mark Nottingham’s post “State of Browser Caching, Revisited.”

    HTTP/2 Push Cache

    Vary should be observed, but in practice no browser actually respects it, and browsers will happily match and consume pushed responses with requests that carry random values in headers that the responses are varying on.

    Test results for H2 push cache in Google Chrome
    (View large version)

    The “304 (Not Modified)” Wrinkle

    The HTTP “304 (Not Modified)” response status is fascinating. Our “dear leader,” Artur Bergman, pointed out to me this gem in the HTTP caching specification (emphasis mine):

    The server generating a 304 response must generate any of the following header fields that would have been sent in a 200 (OK) response to the same request: Cache-Control, Content-Location, Date, ETag, Expires, and Vary.

    Why would a 304 response return a Vary header? The plot thickens when you read about what you’re supposed to do upon receiving a 304 response that contains those headers:

    If a stored response is selected for update, the cache must […] use other header fields provided in the 304 (Not Modified) response to replace all instances of the corresponding header fields in the stored response.

    Wait, what? So, if the 304’s Vary header is different from the one in the existing cached object, we’re supposed to update the cached object? But that might mean it no longer matches the request we made!

    In that scenario, at first glance, the 304 seems to be telling you simultaneously that you can and cannot use the cached version. Of course, if the server really didn’t want you to use the cached version, it would have sent a 200, not a 304; so, the cached version should definitely be used — but after applying the updates to it, it might not be used again for a future request identical to the one that actually populated the cache in the first place.

    (Side note: At Fastly, we do not respect this quirk of the specification. So, if we receive a 304 from your origin server, we will continue to use the cached object unmodified, other than resetting the TTL.)

    Browsers do seem to respect this, but with a quirk. They update not just the response headers but the request headers that pair with them, in order to guarantee that, post-update, the cached response is a match for the current request. This seems to make sense. The specification doesn’t mention this, so the browser vendors are free to do what they like; luckily, all browsers exhibit this same behavior.

    Client Hints

    Google’s Client Hints feature is one of the most significant new things to happen to Vary in the browser in a long time. Unlike Accept-Encoding and Accept-Language, Client Hints describe values that might well change regularly as a user moves around your website, specifically the following:

    • DPR

      Device pixel ratio, the pixel density of the screen (might vary if the user has multiple screens)
    • Save-Data

      Whether the user has enabled data-saving mode
    • Viewport-Width

      Pixel width of the current viewport
    • Width

      Desired resource width in physical pixels

    Not only might these values change for a single user, but the range of values for the width-related ones is large. So, we can totally use Vary with these headers, but we risk reducing our cache efficiency or even rendering caching ineffective.

    The Key Header Proposal

    Client Hints and other highly granular headers lend themselves to a proposal that Mark has been working on, named Key. Let’s look at a couple of examples:

    Key: Viewport-Width;div=50

    This says that the response varies based on the value of the Viewport-Width request header, but rounded down to the nearest multiple of 50 pixels!

    Key: cookie;param=sessionAuth;param=flags

    Adding this header into a response means that we’re varying on two specific cookies: sessionAuth and flags. If they haven’t changed, we can reuse this response for a future request.

    So, the main differences between Key and Vary are:

    • Key allows varying on subfields within headers, which suddenly makes it feasible to vary on cookies, because you can vary on just one cookie — this would be huge;
    • individual values can be bucketed into ranges, to increase the chance of a cache hit, particularly useful for varying on things such as viewport width.
    • all variations with the same URL must have the same key. So, if a cache receives a new response for a URL for which it already has some existing variants, and the new response’s Key header value doesn’t match the values on those existing variants, then all the variants must be evicted from the cache.

    At time of writing, no browser or CDN supports Key, although in some CDNs you might be able to get the same effect by splitting incoming headers into multiple private headers and varying on those (see our post, “Getting the Most Out of Vary With Fastly”), so browsers are the main area where Key can make an impact.

    The requirement for all variations to have the same key recipe is somewhat limiting, and I’d like to see some kind of “early exit” option in the specification. This would enable you to do things like, “Vary on authentication state, and if logged in, also vary on preferences.”

    The Variants Proposal

    Key is a nice generic mechanism, but some headers have more complex rules for their values, and understanding those values’ semantics can help us to find automated ways of reducing cache variation. For example, imagine that two requests come in with different Accept-Language values, en-gb and en-us, but although your website does have support for language variation, you only have one “English.” If we answer the request for US English and that response is cached on a CDN, then it can’t be reused for the UK English request, because the Accept-Language value would be different and the cache isn’t smart enough to know better.

    Enter, with considerable fanfare, the Variants proposal. This would enable servers to describe which variants they support, allowing caches to make smarter decisions about which variations are actually distinct and which are effectively the same.

    Right now, Variants is a very early draft, and because it is designed to help with Accept-Encoding and Accept-Language, its usefulness is rather limited to shared caches, such as CDNs, rather than browser caches. But it nicely pairs up with Key and completes the picture for better control of cache variation.

    Conclusion

    There’s a lot to take in here, and while it can be interesting to understand how the browser works under the hood, there are also some simple things you can distil from it:

    • Most browsers treat Vary as a validator. If you want multiple separate variations to be cached, find a way to use different URLs instead.
    • Browsers ignore Vary for resources pushed using HTTP/2 server push, so don’t vary on anything you push.
    • Browsers have a ton of caches, and they work in different ways. It’s worth trying to understand how your caching decisions impact performance in each one, especially in the context of Vary.
    • Vary is not as useful as it could be, and Key paired with Client Hints is starting to change that. Follow along with browser support to find out when you can start using them.

    Go forth and be variable.

    Smashing Editorial(al)

    SmashingConf 2018: Fetch Those Early-Bird Tickets!

    Great conferences are all about learning new skills and making new connections. That’s why we’ve set up a couple of new adventures for SmashingConf 2018 — just practical sessions, new formats, new lightning talks, evening sessions and genuine, interesting conversations — with a dash of friendly networking! Taking place in London, San Francisco, Toronto. Tickets? Glad you asked!

    SmashingConf London / #perfmatters / Feb 7–8

    Performance matters. Next year, we’re thrilled to venture to London for our brand new conference fully dedicated to everything front-end performance. Dealing with ads, third-party scripts, A/B testing, HTTP/2, debugging, JAM stack, PWA, web fonts loading, memory/CPU perf, service workers. Plus lightning community talks. Schedule and details.

    A queen cat welcoming you a Smashing Conference in London, February 7 to 8, 2018

    SmashingConf London: everything web performance. Feb 7–8.

    Speakers and Topics

    Over the two days, we’ll cover pretty much every aspect of front-end performance: from rendering to debugging. Two days, one track, 16 speakers and 7 hands-on workshops. 50 early-bird-tickets now on sale.

    £379 £459

    Conference TicketAll taxes included. Only 50 early-bird tickets.

    Save £76!

    Conference & WorkshopAll taxes included. Only 50 early-bird tickets.

    SmashingConf San Francisco / #breakout / Apr 17–18

    The classic. With our third annual conference in San Francisco, we want to explore ways and strategies for breaking out: leaving behind generic designs and understanding the new techniques and capabilities available today. We care about the solutions we come up with, and the approaches that failed along the way. In San Francisco, we want to find out the why, and how, and what we all — as designers and developers — need to know today to be more productive and make smarter decisions tomorrow. Schedule and details.

    A queen cat welcoming you a Smashing Conference in San Francisco, April 17 to 18, 2018

    SmashingConf SF: breaking out of the box. Apr 17–18.

    Speakers and Topics

    A wide range of everything web-related, covered in 2 days, with a single track, 16 speakers and 8 hands-on workshops. CSS Grid, Design systems, new frontiers of CSS and JavaScript, accessibility, performance, lettering, graphic design, UX, multi-cultural design, among other things. 100 super early-bird-tickets now on sale.

    US$499 $599

    Conference TicketAll taxes included. Only 100 early-bird tickets.

    Save US$100!

    Conference & WorkshopAll taxes included. Only 100 early-bird tickets.

    SmashingConf Toronto / #noslides / Jun 26–27

    What’s the best way to learn? By observing designers and developers working live. For our new conference in Toronto, all speakers aren’t allowed to use any slides at all. Welcome SmashingConf #noslides, a brand new conference, full of interactive live sessions, showing how web designers design and how web developers build — including setup, workflow, design thinking, naming conventions and everything in-between. Schedule and details.

    A queen cat welcoming you a Smashing Conference in Toronto, June 26 to 27, 2018

    SmashingConf Toronto: no slides, live sessions only. Jun 26–27.

    Speakers and Topics

    Interactive live sessions on everything from organizing layers in Photoshop to naming conventions in CSS. Live workflow in Sketch and Photoshop, design systems setup, lettering, new frontiers of CSS and JavaScript, CSS Grid Layout, live debugging, performance audits, accessibility audits, sketching, graphic design, data visualization and creative coding. 100 super early-bird-tickets now on sale.

    CAD$640 $705

    Conference TicketAll taxes included. Only 100 early-bird tickets.

    Save CAD$128!

    Conference & WorkshopAll taxes included. Only 100 early-bird tickets.

    Tickets!

    To give everybody a chance to buy ticket in time, we are releasing all tickets in batches this time. The first batch of super early-birds are available right away: fetch them before they fly out!

    Ah, and just in case you’re wondering: we’re planning on running a conference in our hometown Freiburg, Germany on September 10–11, and we will be coming back to New York, USA on October 23–24 — with a slightly different format, too. We can’t wait to see you there! 😉

    Smashing Editorial(vf ms)

    Inspiring Desktop Wallpapers To Make November Even More Colorful (2017 Edition)

    November is a rather gray month in many parts of the world, so what could be better as some colorful inspiration to start it off with the right foot? To tickle your creativity, artists and designers from across the globe once again challenged their artistic abilities and designed desktop wallpapers for you to indulge in. Wallpapers that are a bit more distinctive as the usual crowd, bound to breathe some fresh life into your routine.

    All artworks in this collection come in versions with and without a calendar for November 2017, so it’s up to you to decide if you want to have the month always in sight or just some distraction-free inspiration. A big thank-you to everyone who shared their wallpapers this time around! Enjoy!

    Please note that:

    • All images can be clicked on and lead to the preview of the wallpaper,
    • You can feature your work in our magazine by taking part in our Desktop Wallpaper Calendars series. We are regularly looking for creative designers and artists to be featured on Smashing Magazine. Are you one of them?

    Colorful Autumn

    “Autumn can be dreary, especially in November, when rain starts pouring every day. We wanted to summon better days, so that’s how this colourful November calendar was created. Open your umbrella and let’s roll!” — Designed by PopArt Studio from Serbia.

    Colorful Autumn

    The Kind Soul

    “Kindness drives humanity. Be kind. Be humble. Be humane. Be the best of yourself! Here is presenting to you an inspiration in form of a calendar for November.” — Designed by Color Mean Creative Studio from Dubai.

    The Kind Soul

    November Fun

    Designed by Xenia Latii from Germany.

    November Fun

    Autumn Darkness

    “‘When autumn darkness falls, what we will remember are the small acts of kindness: a cake, a hug, an invitation to talk, and every single rose. These are all expressions of a nation coming together and caring about its people.’ (Jens Stoltenberg)” — Designed by Dipanjan Karmakar from India.

    Autumn Darkness

    Tempestuous November

    “By the end of autumn, ferocious Poseidon will part from tinted clouds and timid breeze. After this uneven clash, the sky once more becomes pellucid just in time for imminent luminous snow.” — Designed by Ana Masnikosa from Belgrade, Serbia.

    Tempestuous November

    Fall Breeze

    “The colorful leaves and cool breeze that make you want to snuggle in your couch at home inspired me to create this fall design.” — Designed by Allison Coyle from the United States.

    Fall Breeze

    Music From Nature

    Designed by StarAdmin from India.

    Music From Nature

    No Shave Movember

    “The goal of Movember is to ‘change the face of men’s health.’” — Designed by Suman Sil from India.

    No Shave Movember

    Welcome November

    “Dear November, be awesome!” — Designed by PlusCharts from India.

    Welcome November

    Peanut Butter Jelly Time!

    “November is the Peanut Butter Month so I decided to make a wallpaper around that. As everyone knows peanut butter goes really well with some jelly so I made two sandwiches, one with peanut butter and one with jelly. Together they make the best combination. I also think peanut butter tastes pretty good so that’s why I chose this for my wallpaper.” — Designed by Senne Mommens from Belgium.

    Peanut Butter Jelly Time!

    Autumn In November

    Designed by Dielan Ophals from Belgium.

    Autumn In November

    Coco Chanel

    “Beauty begins the moment you decide to be yourself – Coco Chanel” — Designed by Tazi from Australia.

    Coco Chanel

    Movember

    “Movember is an annual event involving the growing of mustaches during the month of November to raise awareness of men’s health issues, such as prostate cancer, testicular cancer and men’s suicide. This wallpaper is to support men’s health.” — Designed by Hemangi Rane from Gainesville, FL.

    Movember

    Fantastic Dreams

    “No dream is too big. No challenge is too great. The whole universe is friendly to us and conspires only to give the best to those who dream and work.” — Designed by BootstrapDash from India.

    Fantastic dreams

    Curious Squirrel

    Designed by Saul Wauters from Belgium.

    Curious Squirrel

    Give Thanks

    “‘Feeling gratitude and not expressing it is like wrapping a present and not giving it.’ (William Arthur Ward)” — Designed by TemplateWatch from India.

    Give Thanks

    Happy Thanksgiving

    “This Thanksgiving, we wish that God showers you and your family with, peace, love, warmth, and joy.” — Designed by Mozilor from India.

    Happy Thanksgiving

    Happy Birthday C.S.Lewis!

    “It’s C.S. Lewis’s birthday on the 29th November, so I decided to create this ‘Chronicles of Narnia’ inspired wallpaper to honour this day.” — Designed by Safia Begum from the United Kingdom.

    Happy Birthday C.S.Lewis!

    Howling At The Moon

    “The short days of the autumn and the early nights of winter. The image gives you the feeling of a cold night in autumn.” — Designed by Lars Pauwels from Belgium.

    Howling At The Moon

    Maple Leaf Globe

    Designed by Hannah Joy Patterson from the USA.

    Maple Leaf Globe

    Autumn In The Park

    “November is great for having a walk in the park, being out of your house, watching the few colored leaves that are still hanging on the trees. Enjoy the fresh but cold air from a blue sky on a nice November day.” — Designed by Arne Ameye from Belgium.

    Autumn In The Park

    Melancholy

    “November brings us deeper into Autumn, when all leaves are brown and yellow, and Summer is just a distant memory to which we look back with a sweet melancholy.” — Designed by Pedro Vaz from Portugal.

    Melancholy

    Armistice Day

    “In Belgium we have Armistice Day on November the 11th. This is a Bank Holiday. We remember the end of the War and all the weapons were put down.” — Designed by Ruben Annaert from Belgium.

    Armistice Day

    Success Is A State Of Mind

    Designed by Metrovista from Orlando, FL.

    Success Is A State Of Mind

    Meteor Shower

    “Since I was a kid I’ve always been extremely inspired by astronomy. Starting this project I found out that many meteor showers occur during November. I had never made a proper space-related illustration before and I definitely took my chance now.” — Designed by Yannis Wellemans from Belgium.

    Meteor Shower

    Stop Being So Hammer-Headed

    “A single hammer headed person around can simply ruin your entire peace and pleasure when you are working on something great. As it’s an empty vessel, nothing much to expect but loud noise. It’s easy to identify those from outside and being hammer headed is a choice. So, consider people around, stop hitting yourself into others and let them do whatever they feel like.” — Designed by Sweans from London.

    Stop Being So Hammer-Headed

    Someone Sleeps More

    Designed by UrbanUI from India.

    Someone Sleeps More

    Welcome A Season Of Chilling Joy

    “The season of plenty of warmth and love has just stepped in… Enjoy the chill with the joy of sharing.” — Designed by Areva Digital from India.

    Welcome A Season Of Chilling Joy

    Welcome Winter

    “When it’s cold outside, bring out the warmth and love in your hearts; to enjoy what the season has kept in store for you. Let’s welcome the onset of winter this November with open arms.” — Designed by Acodez from India.

    Welcome Winter

    Join In Next Month!

    Please note that we respect and carefully consider the ideas and motivation behind each and every artist’s work. This is why we give all artists the full freedom to explore their creativity and express emotions and experience throughout their works. This is also why the themes of the wallpapers weren’t anyhow influenced by us, but rather designed from scratch by the artists themselves.

    A big thank you to all designers for their participation. Join in next month!

    What’s Your Favorite?

    What’s your favorite theme or wallpaper for this month? Please let us know in the comment section below.

    SmashingConf 2018: Fetch Those Early-Bird Tickets! ?? ?? ??

    SmashingConf 2018: Fetch Those Early-Bird Tickets! ?? ?? ??

    Great conferences are all about learning new skills and making new connections. That’s why we’ve set up a couple of new adventures for SmashingConf 2018 — just practical sessions, new formats, new lightning talks, evening sessions and genuine, interesting conversations — with a dash of friendly networking! Taking place in London, San Francisco, Toronto. Tickets? Glad you asked!1

    SmashingConf London52 / #perfmatters / Feb 7–8 Link

    Performance matters. Next year, we’re thrilled to venture to London for our brand new conference fully dedicated to everything front-end performance. Dealing with ads, third-party scripts, A/B testing, HTTP/2, debugging, JAM stack, PWA, web fonts loading, memory/CPU perf, service workers. Plus lightning community talks. Schedule and details.3

    4
    SmashingConf London52: everything web performance. Feb 7–8.

    Speakers and Topics Link

    Over the two days, we’ll cover pretty much every aspect of front-end performance: from rendering to debugging. Two days, one track, 16 speakers and 7 hands-on workshops. 50 early-bird-tickets now on sale.6

    £379 £459

    Conference Ticket15All taxes included. Only 50 early-bird tickets.

    Save £76!

    Conference & Workshop16All taxes included. Only 50 early-bird tickets.

    SmashingConf San Francisco17 / #breakout / Apr 17–18 Link

    The classic. With our third annual conference in San Francisco, we want to explore ways and strategies for breaking out: leaving behind generic designs and understanding the new techniques and capabilities available today. We care about the solutions we come up with, and the approaches that failed along the way. In San Francisco, we want to find out the why, and how, and what we all — as designers and developers — need to know today to be more productive and make smarter decisions tomorrow. Schedule and details.18

    A queen cat welcoming you a Smashing Conference in San Francisco, April 17 to 18, 201819
    SmashingConf SF20: breaking out of the box. Apr 17–18.

    Speakers and Topics Link

    A wide range of everything web-related, covered in 2 days, with a single track, 16 speakers and 8 hands-on workshops. CSS Grid, Design systems, new frontiers of CSS and JavaScript, accessibility, performance, lettering, graphic design, UX, multi-cultural design, among other things. 100 super early-bird-tickets now on sale.21

    US$499 $599

    Conference Ticket28All taxes included. Only 100 early-bird tickets.

    Save US$100!

    Conference & Workshop29All taxes included. Only 100 early-bird tickets.

    SmashingConf Toronto3330 / #noslides / Jun 26–27 Link

    What’s the best way to learn? By observing designers and developers working live. For our new conference in Toronto, all speakers aren’t allowed to use any slides at all. Welcome SmashingConf #noslides, a brand new conference, full of interactive live sessions, showing how web designers design and how web developers build — including setup, workflow, design thinking, naming conventions and everything in-between. Schedule and details.31

    A queen cat welcoming you a Smashing Conference in Toronto, June 26 to 27, 201832
    SmashingConf Toronto3330: no slides, live sessions only. Jun 26–27.

    Speakers and Topics Link

    Interactive live sessions on everything from organizing layers in Photoshop to naming conventions in CSS. Live workflow in Sketch and Photoshop, design systems setup, lettering, new frontiers of CSS and JavaScript, CSS Grid Layout, live debugging, performance audits, accessibility audits, sketching, graphic design, data visualization and creative coding. 100 super early-bird-tickets now on sale.34

    CAD$640 $705

    Conference Ticket45All taxes included. Only 100 early-bird tickets.

    Save CAD$128!

    Conference & Workshop46All taxes included. Only 100 early-bird tickets.

    Tickets! Link

    To give everybody a chance to buy ticket in time, we are releasing all tickets in batches this time. The first batch of super early-birds are available right away: fetch them before they fly out!

    Ah, and just in case you’re wondering: we’re planning on running a conference in our hometown Freiburg, Germany on September 10–11, and we will be coming back to New York, USA on October 23–24 — with a slightly different format, too. We can’t wait to see you there! 😉

    (vf ms)

    Footnotes Link

    1. 1 #tickets
    2. 2 https://smashingconf.com
    3. 3 https://smashingconf.com/
    4. 4 https://smashingconf.com
    5. 5 https://smashingconf.com
    6. 6 https://shop.smashingmagazine.com/products/smashingconf-london-2018?variant=990650269721
    7. 7 https://www.twitter.com/
    8. 8 https://www.twitter.com/
    9. 9 https://www.twitter.com/
    10. 10 https://www.twitter.com/
    11. 11 https://www.twitter.com/
    12. 12 https://www.twitter.com/
    13. 13 https://www.twitter.com/
    14. 14 https://www.twitter.com/
    15. 15 https://shop.smashingmagazine.com/products/smashingconf-london-2018
    16. 16 https://smashingconf.com/registration
    17. 17 https://smashingconf.com/sf-2018/
    18. 18 https://smashingconf.com/sf-2018/
    19. 19 https://smashingconf.com/sf-2018/
    20. 20 https://smashingconf.com/sf-2018/
    21. 21 https://shop.smashingmagazine.com/products/smashingconf-san-francisco-2018?variant=1012441088025on
    22. 22 https://smashingconf.com/sf-2018/speakers/jessica-hische
    23. 23 https://smashingconf.com/sf-2018/speakers/trent-walton
    24. 24 https://www.twitter.com/
    25. 25 https://smashingconf.com/sf-2018/speakers/yiying-lu
    26. 26 https://smashingconf.com/sf-2018/speakers/patrick-hamann
    27. 27 https://smashingconf.com/sf-2018/speakers/rachel-andrew
    28. 28 https://shop.smashingmagazine.com/products/smashingconf-san-francisco-2018
    29. 29 https://smashingconf.com/sf-2018/registration
    30. 30 https://smashingconf.com/toronto-2018/
    31. 31 https://smashingconf.com/toronto-2018/schedule
    32. 32 https://smashingconf.com/toronto-2018/
    33. 33 https://smashingconf.com/toronto-2018/
    34. 34 https://shop.smashingmagazine.com/products/smashingconf-toronto?variant=1012127203353
    35. 35 https://smashingconf.com/toronto-2018/speakers/lea-verou
    36. 36 https://smashingconf.com/toronto-2018/speakers/seb-lee-delisle
    37. 37 https://smashingconf.com/toronto-2018/speakers/sarah-drasner
    38. 38 https://smashingconf.com/toronto-2018/speakers/joe-leech
    39. 39 https://smashingconf.com/toronto-2018/speakers/gemma-obrien
    40. 40 https://smashingconf.com/toronto-2018/speakers/tim-kadlec
    41. 41 https://smashingconf.com/toronto-2018/speakers/dan-mall
    42. 42 https://smashingconf.com/toronto-2018/speakers/nadieh-bremer
    43. 43 https://smashingconf.com/toronto-2018/speakers/aaron-draplin
    44. 44 https://smashingconf.com/toronto-2018/speakers/yiying-lu
    45. 45 https://shop.smashingmagazine.com/products/smashingconf-toronto?variant=1012127203353
    46. 46 https://smashingconf.com/toronto-2018/registration
    47. 47 https://smashingconf.com/registration
    48. 48 https://smashingconf.com/sf-2018/registration
    49. 49 https://smashingconf.com/toronto-2018/registration

    ↑ Back to topTweet itShare on Facebook

    A Swift Transition From iOS To macOS Development

    Today started just like any other day. You sat down at your desk, took a sip of coffee and opened up Xcode to start a new project. But wait! The similarities stop there. Today, we will try to build for a different platform! Don’t be afraid. I know you are comfortable there on your iOS island, knocking out iOS applications, but today begins a brand new adventure. Today is the day we head on over to macOS development, a dark and scary place that you know nothing about.

    The good news is that developing for macOS using Swift has a lot more in common with iOS development than you realize. To prove this, I will walk you through building a simple screen-annotation application. Once we complete it, you will realize how easy it is to build applications for macOS.

    The Concept

    The idea comes from two unlikely sources. The first source is my boss, Doug Cook. He came over and asked if I knew how to make a circular floating app on macOS for prototyping purposes. Having never really done anything on macOS, I started to do some digging. After a little digging, I found Apple’s little gem of RoundTransparentWindow. Sure, it was in Objective-C, and it was pre-ARC to boot, but after reading through the code, I saw that figuring out how to do it in Swift wasn’t very difficult. The second source was pure laziness. I recently picked up a side project making tutorial videos on YouTube. I wanted to be able to describe what I was saying by drawing directly on the screen, without any post-production.

    I decided to build a macOS app to draw on the computer screen:

    Behold the app in all its glory!
    Behold the app in all its glory! (View large version)

    OK, it doesn’t look like much — and, honestly, it shouldn’t because I haven’t drawn anything. If you look closely at the image above, you will see a little pencil icon in the upper-right bar. This area of macOS contains items called “menu extras.” By clicking the pencil icon, you will enable drawing on screen, and then you can draw something like this below!

    Behold the app in all its glory, again!
    Behold the app in all its glory, again! (View large version)

    I wanted drawing on the screen to be enabled at all times, but not to take over the screen when not in use. I preferred that it not live in the dock, nor change the contents of macOS’ menu bar. I knew that it was possible because I’d seen it in other apps. So, over lunch one day, I decided to take a crack at building this drawing tool, and here we are! This is what we will build in this tutorial.

    The Soapbox

    At this point, you might be saying to yourself, “Why build this? It’s just a simple drawing app!” But that isn’t the point. If you are anything like me, you are a little intimidated by the thought of making a macOS app. Don’t be. If you program for your iPhone on your MacBook, shouldn’t you also be able to program for your MacBook on your MacBook? What if Apple actually does merge iOS and macOS? Should you be left behind because you were intimidated by macOS development? ChromeOS already supports Android builds. How long before macOS supports iOS builds? There are differences between Cocoa and UIKit, which will become apparent, but this tutorial will get your feet wet and (hopefully) challenge you to build something bigger and better.

    Caveats and Requirements

    There are some caveats to this project that I want to get out of the way before we start. We will be making an app that draws over the entire screen. This will work on only one screen (for now) and will not work as is over full-screen apps. For our purpose, this is enough, and it leaves open room for plenty of enhancements in future iterations of the project. In fact, if you have any ideas for enhancements of your own, please leave them in the comments at the bottom!

    For this tutorial, you’ll need a basic understanding of Swift development and familiarity with storyboards. We will also be doing this in Xcode 9 because that is the latest and greatest version at the time of writing.

    1. Begin A macOS Project

    Open Xcode and create a new macOS project. At this point, you are probably still in the “iOS” style project. We have to update this so that we are building for the correct system. Hit the “macOS” icon at the top, and then make sure that “Cocoa App” is selected. Hit “Next.”

    Create a new macOS project
    Create a new macOS project.

    Enter in the product name as you normally would. We will call this one ScreenAnnotation, and then do the normal dance with “organization name” and “team” that you’d normally do. Make sure to select Swift as the language, and again hit “Next.” After saving it in the directory of your choosing, you will have your very own macOS app. Congratulations!

    At first glance, you will see most everything you get in an iOS app. The only differences you might notice right now are the entitlements file, Cocoa in place of UIKit in each of the .swift files, and (naturally) the contents of the storyboard.

    2. Clean Up

    Our next step is to go into the storyboard and delete anything we don’t need. First, let’s get rid of the menu; because our app will live as a menu extra, instead of as a dock app, it is unnecessary. Beneath where the menu existed is the window. We need to subclass this and use it to determine whether we are drawing within our app or toying with windows beneath it. Looking below the window, we can also see the familiar view controller. We already have a subclass of this, provided by Xcode. It is aptly named ViewController because it is a subclass of NSViewController, but we still need a NSWindow subclass, so that we can decorate it as a clear window. Head over to the left pane, right-click, select “New file,” then select “Swift” file. When prompted, name this ClearWindow. Replace the one line with the following:

    import Cocoaclass ClearWindow : NSWindow { override init(contentRect: NSRect, styleMask style: NSWindow.StyleMask, backing backingStoreType: NSWindow.BackingStoreType, defer flag: Bool) { super.init(contentRect: contentRect, styleMask: StyleMask.borderless, backing: backingStoreType, defer: flag) level = NSWindow.Level.statusBar backgroundColor = NSColor.blue } override func mouseDown(with event: NSEvent) { print("Mouse down: (event.locationInWindow)") } override func mouseDragged(with event: NSEvent) { print("Mouse dragged: (event.locationInWindow)") } override func mouseUp(with event: NSEvent) { print("Mouse up: (event.locationInWindow)") }}

    In this code snippet, we are importing Cocoa, which is to macOS as UIKit is to iOS development. This is the main API we will use to control our app. After importing Cocoa, we subclass NSWindow, and then we update our super-call in the init method. In here, we keep the same contentRect but will modify this later. We change the styleMask to borderless, which removes the standard application options: close, minimize and maximize. It also removes the top bar on the window. You can also do this in the storyboard file, but we are doing it here to show what it would look like to do it programmatically. Next, we pass the other variables right on through to the constructor. Now that we have that out of the way, we need to tell our window where to draw. Looking at the NSWindow documentation, we see that we can set our window at different levels. We will set the window level to NSStatusWindowLevel because it will draw above all other normal windows.

    3. Our First Test

    We are using NSResponder methods in the same way that we’d use the UIResponder method to respond to touches on iOS. On macOS, we are interested in mouse events. Later on, we will be using these methods to draw in our ViewController.

    Finally, we’ll change the color of our view to blue, just to make sure things are running smoothly; if we went straight to a transparent view, we wouldn’t know where the window was drawn yet! Next, we need to set up the storyboard to use our new ClearWindow class, even though it isn’t living up to its name yet. Go back to the storyboard, click the window, and edit its subclass under the “Custom Class” area in the right pane. Type in ClearWindow here, and we can now run our app.

    Type in ClearWindow
    Type in ClearWindow

    Lo and behold, we have a blue rectangle on our screen! Nothing impressive, yet. We can click and drag around, and we can spam the console. Let’s stop running the app at this point because it will only get in the way.

    4. Let’s Start Drawing!

    Next, we can update our implementation of ViewController. The bulk of our work will now happen here and in Main.storyboard. Right now, the important part is to piggyback on the methods that we created in ClearWindow to capture mouse gestures. Replace the contents of ViewController with the following code:

    import Cocoaclass ViewController: NSViewController { override func viewDidLoad() { super.viewDidLoad() view.frame = CGRect(origin: CGPoint(), size: NSScreen.main!.visibleFrame.size) } func startDrawing(at point: NSPoint) { } func continueDrawing(at point: NSPoint) { } func endDrawing(at point: NSPoint) { }}

    This does not look like much yet, but it is the foundation of our drawing code. In our modified viewDidLoad() method, we’ve resized the view to equal our main screen’s dimension. We do this because we can only draw within our NSViewController. If our view covered everything, then we’d be able to draw over anything! Finally, we’ve created hooks that, for ClearWindow, will call for the ViewController to draw. More on that in a bit.

    The next thing we need to do is define how we will draw onto the screen. Add the following code above our viewDidLoad method.

    let lineWeight: CGFloat = 10let strokeColor: NSColor = .redvar currentPath: NSBezierPath?var currentShape: CAShapeLayer?

    These four variables define our drawing. Currently, our line thickness is 10 points, and we will be drawing in red — nothing revolutionary here, but that needs to be defined. Next, we have a NSBezierPath and a CAShapeLayer. These should look pretty familiar if you have ever played with UIBezierPath. Note that these two are optional (they will come up again later).

    Now for the fun part: We can start implementing our drawing methods.

    Start Drawing

    Update startDrawing with the following code:

    func startDrawing(at point: NSPoint) { currentPath = NSBezierPath() currentShape = CAShapeLayer() currentShape?.lineWidth = lineWeight currentShape?.strokeColor = strokeColor.cgColor currentShape?.fillColor = NSColor.clear.cgColor currentShape?.lineJoin = kCALineJoinRound currentShape?.lineCap = kCALineCapRound currentPath?.move(to: point) currentPath?.line(to: point) currentShape?.path = currentPath?.cgPath view.layer?.addSublayer(currentShape!)}

    This is the most complicated of the three drawing methods. The reason for this is that we need to set up a new NSBezierPath and CAShapeLayer each time we start drawing. This is important because we don’t want to have one continuous line all over our screen — that wouldn’t do at all. This way, we can have one layer per line, and we will be able to make any kind of drawing we want. Then, we set up the newly created CAShapeLayer’s properties. We send in our lineWeight and then the stroke color to our nice red color. We set the fill color to clear, which means we will only be drawing with lines, instead of solid shapes. Then, we set the lineJoin and lineCap to use rounded edges. I chose this because the rounded edges make the drawing look nicer in my opinion. Feel free to play with these properties to figure out what works best for you.

    Then, we move the point where we will start drawing to the NSPoint that will be sent to us. This will not draw anything, but it will give the UIBezierPath a reference point for when we actually give it instructions to draw. Think of it as if you had a pen in your hand and you decided to draw something in the middle of a sheet of paper. You move the pen to the location you want to draw, but you’re not doing anything yet, just hovering over the paper, waiting to put the ink down. Without this, nothing can be drawn because the next line requires two points to work. The next line, aptly named line(to: point), draws a line from the current position to wherever you specify. Currently, we’re telling our UIBezierPath to stay in the same position and touch down on our sheet of paper.

    The last two lines pull the path data out of our UIBezierPath in a usable format for CAShapeLayer. Note that currentPath?.cgPath will be marked as an error at the moment. Don’t fret: We will take care of that after we cover the next two methods. Just know that when it does work, this function will have our CAShapeLayer draw its path, even if it is currently a dot. Then, we add this layer to our view’s sublayer. At this point, the user will be able to see that they are now drawing.

    Continue Drawing

    Update continueDrawing with the following code:

    func continueDrawing(at point: NSPoint) { currentPath?.line(to: point) if let shape = currentShape { shape.path = currentPath?.cgPath }}

    Not much going on here, but we are adding another line to our currentPath. Because the CAShapeLayer is already in our view’s sublayer, the update will show on screen. Again, note that these are optional values; we are guarding ourselves just in case they are nil.

    End Drawing

    Update endDrawing with the following code:

    func endDrawing(at point: NSPoint) { currentPath?.line(to: point) if let shape = currentShape { shape.path = currentPath?.cgPath } currentPath = nil currentShape = nil}

    We update the path again, just the same way as we did in continueDrawing, but then we also nil out our currentPath and currentShape. We do this because we are done drawing and no longer need to talk to this shape and path. The next action we can take is startDrawing again, and we start this process all over again. We nil out these values so that we cannot update them again; the view’s sublayer will still hold a reference to the line, and it will stay on screen until we remove it.

    If we run the app with what we have, we’ll get errors! Almost forgot about that. One thing you will definitely notice when moving over to macOS development is that not every API between iOS and macOS are equivalent. One such issue here is that NSBezierPath doesn’t have the handy cgPath property that UIBezierPath has. We use this property to easily convert the NSBezierPath path to the CAShapeLayer path. This way, CAShapeLayer will do all the heavy lifting to display our line. We can sit back and reap the reward of a nice-looking line with none of the work! StackOverflow has a handy answer that I’ve used to handle this absence of cgPath by updating it to Swift 4 (see below). This code lets us create an extension to NSBezierPath and returns to us a handy CGPath to play with. Create a file named NSBezierPath+CGPath.swift and add the following code to it.

    import Cocoaextension NSBezierPath { public var cgPath: CGPath { let path = CGMutablePath() var points = [CGPoint](repeating: .zero, count: 3) for i in 0 ..< self.elementCount { let type = self.element(at: i, associatedPoints: &points) switch type { case .moveToBezierPathElement: path.move(to: points[0]) case .lineToBezierPathElement: path.addLine(to: points[0]) case .curveToBezierPathElement: path.addCurve(to: points[2], control1: points[0], control2: points[1]) case .closePathBezierPathElement: path.closeSubpath() } } return path }}

    At this point, everything will run, but we aren’t drawing anything quite yet. We still need to attach the drawing functions to actual mouse actions. In order to do this, we go back into our ClearWindow and update the NSResponder mouse methods to the following:

     override func mouseDown(with event: NSEvent) { (contentViewController as? ViewController)?.startDrawing(at: event.locationInWindow) } override func mouseDragged(with event: NSEvent) { (contentViewController as? ViewController)?.continueDrawing(at: event.locationInWindow) } override func mouseUp(with event: NSEvent) { (contentViewController as? ViewController)?.endDrawing(at: event.locationInWindow) }

    This basically checks to see whether the current view controller is our instance of ViewController, where we will handle the drawing logic. If you run the app now, you should see something like this:

    The app as it is now
    The app as it is now (View large version)

    This is not completely ideal, but we are currently able to draw on the blue portion of our screen. This means that our drawing logic is correct, but our layout is not. Before correcting our layout, let’s create a good way to quit, or disable, drawing on our app. If we make it full screen right now, we would either have to “force quit” or switch to another space to quit our app.

    5. Create A Menu

    Head back over to our Main.storyboard file, where we can add a new menu to our ViewController. In the right pane, drag “Menu” under the “View Controller Scene” in our storyboard’s hierarchy.

    Setting up the menu
    Setting up the menu (View large version)

    Edit these menu items to say “Clear,” “Toggle” and “Quit.” For extra panache, we can add a line separator above our “Exit” item, to deter accidental clicks:

    Creating menu options
    Creating menu options (View large version)

    Next, open up the “Assistant Editor” (the Venn diagram-looking button near the top right of Xcode), so that we can start hooking up our menu items. For both “Clear” and “Toggle,” we want to create a “Referencing Outlet” so that we can modify them. After this, we want to hook up “Sent Action” so that we can get a callback when the menu item is selected.

    Hooking up the code to the buttons
    Hooking up the code to the buttons (View large version)

    For “Exit,” we will drag our “Sent Action” to the first responder, and select “Terminate.” “Terminate” is a canned action that will quit the application. Finally, we need a reference to the menu itself; so, right-click on the menu under “View Controller Scene,” and create a reference named optionsMenu. The newly added code in ViewController should look like this:

    @IBOutlet weak var clearButton: NSMenuItem!@IBOutlet weak var toggleButton: NSMenuItem!@IBOutlet var optionsMenu: NSMenu!@IBAction func clearButtonClicked(_ sender: Any) {}@IBAction func toggleButtonClicked(_ sender: Any) {}

    We have the building blocks for the menu extras for our app; now we need to finish the process. Close out of “Assistant Editor” mode and head over to ViewController so that we can make use of these menu buttons. First, we will add the following strings to drive the text of the toggle button. Add the following two lines near the top of the file.

    private let offText = "Disable Drawing"private let onText = "Enable Drawing"

    We need to update what happens when the clear and toggle buttons are clicked. Add the following line to clear the drawing in clearButtonClicked(_ sender):

    view.window!.ignoresMouseEvents = !view.window!.ignoresMouseEventstoggleButton.title = view.window!.ignoresMouseEvents ? onText : offText

    This toggles the flag on our window to ignore mouse events, so that we will click “through” our window, in order to use our computer as intended. We’ll also update the toggleButton’s text to let the user know that drawing is either enabled or disabled.

    Now we need to finally put our menu to use. Let’s start by adding an icon to our project. You can find that in the repository. Then, we can override the awakeFromNib() method because, at this point, our view will be inflated from the storyboard. Add the following code to ViewController.

    let statusItem = NSStatusBar.system.statusItem(withLength: NSStatusItem.variableLength)override func awakeFromNib() { statusItem.menu = optionsMenu let icon = NSImage(named: NSImage.Name(rawValue: "pencil")) icon?.isTemplate = true // best for dark mode statusItem.image = icon toggleButton.title = offText}

    Make sure to put the statusItem near the top, next to the rest of the variables. statusItem grabs a spot for our app to use menu extras in the top toolbar. Then, in awakeFromNib, we set the menu as our optionsMenu, and, finally, we give it an icon, so that it is easily identifiable and clickable. If we run our app now, the “menu extra” icon will appear at the top! We aren’t quite finished yet. We need to ensure that the drawing space is placed correctly on screen; otherwise, it will be only partially useful.

    6. Positioning The Drawing App

    To get our view to draw where we want it, we must venture back into Main.storyboard. Click on the window itself, and then select the attributes inspector, the icon fourth from the left in the right-hand pane. Uncheck everything under the “Appearance,” “Controls” and “Behavior” headings, like so:

    Attributes inspector
    Attributes inspector

    We do this to remove all extra behaviors and appearances. We want a clear screen, with no bells and whistles. If we run the app again, we will be greeted by a familiar blue screen, only larger. To make things useful, we need to change the color from blue to transparent. Head back over to ClearWindow and update the blue color to this:

    backgroundColor = NSColor(calibratedRed: 1, green: 1, blue: 1, alpha: 0.001)

    This is pretty much the same as NSColor.clear. The reason why we are not using NSColor.clear is that if our entire app is transparent, then macOS won’t think our app is visible, and no clicks will be captured in the app. We’ll go with a mostly transparent app — something that, at least to me, is not noticeable, yet our clicks will be recorded correctly.

    The final thing to do is remove it from our dock. To do this, head over to Info.plist and add a new row, named “Application is agent (UIElement)” and set it to “Yes.” Once this is done, rerun the app, and it will no longer appear in the dock!

    Conclusion

    This app is pretty short and sweet, but we did learn a few things. First, we figured out some of the similarities and differences between UIKit and Cocoa. We also took a tour around what Cocoa has in store for us iOS developers. We also (hopefully) know that creating a Cocoa-based app is not difficult, nor should it be intimidating. We now have a small app that is presented in an atypical fashion, and it lives up in the menu bar, next to the menu extras. Finally, we can use all of this stuff to build bigger and better Cocoa apps! You started this article as an iOS developer and grew beyond that, becoming an Apple developer. Congratulations!

    I will be updating the public repository for this example to add extra options. Keep an eye on the repository, and feel free to add code, issues and comments.

    Good luck and happy programming!

    Attributes inspector
    Thank you!

    This does not look like much yet, but it is the foundation of our drawing code. In our modified viewDidLoad() method, we’ve resized the view to equal our main screen’s dimension. We do this because we can only draw within our NSViewController. If our view covered everything, then we’d be able to draw over anything! Finally, we’ve created hooks that, for ClearWindow, will call for the ViewController to draw. More on that in a bit.

    The next thing we need to do is define how we will draw onto the screen. Add the following code above our viewDidLoad method.

    let lineWeight: CGFloat = 10let strokeColor: NSColor = .redvar currentPath: NSBezierPath?var currentShape: CAShapeLayer?

    These four variables define our drawing. Currently, our line thickness is 10 points, and we will be drawing in red — nothing revolutionary here, but that needs to be defined. Next, we have a NSBezierPath and a CAShapeLayer. These should look pretty familiar if you have ever played with UIBezierPath. Note that these two are optional (they will come up again later).

    Now for the fun part: We can start implementing our drawing methods.

    Start Drawing

    Update startDrawing with the following code:

    func startDrawing(at point: NSPoint) { currentPath = NSBezierPath() currentShape = CAShapeLayer() currentShape?.lineWidth = lineWeight currentShape?.strokeColor = strokeColor.cgColor currentShape?.fillColor = NSColor.clear.cgColor currentShape?.lineJoin = kCALineJoinRound currentShape?.lineCap = kCALineCapRound currentPath?.move(to: point) currentPath?.line(to: point) currentShape?.path = currentPath?.cgPath view.layer?.addSublayer(currentShape!)}

    This is the most complicated of the three drawing methods. The reason for this is that we need to set up a new NSBezierPath and CAShapeLayer each time we start drawing. This is important because we don’t want to have one continuous line all over our screen — that wouldn’t do at all. This way, we can have one layer per line, and we will be able to make any kind of drawing we want. Then, we set up the newly created CAShapeLayer’s properties. We send in our lineWeight and then the stroke color to our nice red color. We set the fill color to clear, which means we will only be drawing with lines, instead of solid shapes. Then, we set the lineJoin and lineCap to use rounded edges. I chose this because the rounded edges make the drawing look nicer in my opinion. Feel free to play with these properties to figure out what works best for you.

    Then, we move the point where we will start drawing to the NSPoint that will be sent to us. This will not draw anything, but it will give the UIBezierPath a reference point for when we actually give it instructions to draw. Think of it as if you had a pen in your hand and you decided to draw something in the middle of a sheet of paper. You move the pen to the location you want to draw, but you’re not doing anything yet, just hovering over the paper, waiting to put the ink down. Without this, nothing can be drawn because the next line requires two points to work. The next line, aptly named line(to: point), draws a line from the current position to wherever you specify. Currently, we’re telling our UIBezierPath to stay in the same position and touch down on our sheet of paper.

    The last two lines pull the path data out of our UIBezierPath in a usable format for CAShapeLayer. Note that currentPath?.cgPath will be marked as an error at the moment. Don’t fret: We will take care of that after we cover the next two methods. Just know that when it does work, this function will have our CAShapeLayer draw its path, even if it is currently a dot. Then, we add this layer to our view’s sublayer. At this point, the user will be able to see that they are now drawing.

    Continue Drawing

    Update continueDrawing with the following code:

    func continueDrawing(at point: NSPoint) { currentPath?.line(to: point) if let shape = currentShape { shape.path = currentPath?.cgPath }}

    Not much going on here, but we are adding another line to our currentPath. Because the CAShapeLayer is already in our view’s sublayer, the update will show on screen. Again, note that these are optional values; we are guarding ourselves just in case they are nil.

    End Drawing

    Update endDrawing with the following code:

    func endDrawing(at point: NSPoint) { currentPath?.line(to: point) if let shape = currentShape { shape.path = currentPath?.cgPath } currentPath = nil currentShape = nil}

    We update the path again, just the same way as we did in continueDrawing, but then we also nil out our currentPath and currentShape. We do this because we are done drawing and no longer need to talk to this shape and path. The next action we can take is startDrawing again, and we start this process all over again. We nil out these values so that we cannot update them again; the view’s sublayer will still hold a reference to the line, and it will stay on screen until we remove it.

    If we run the app with what we have, we’ll get errors! Almost forgot about that. One thing you will definitely notice when moving over to macOS development is that not every API between iOS and macOS are equivalent. One such issue here is that NSBezierPath doesn’t have the handy cgPath property that UIBezierPath has. We use this property to easily convert the NSBezierPath path to the CAShapeLayer path. This way, CAShapeLayer will do all the heavy lifting to display our line. We can sit back and reap the reward of a nice-looking line with none of the work! StackOverflow has a handy answer that I’ve used to handle this absence of cgPath by updating it to Swift 4 (see below). This code lets us create an extension to NSBezierPath and returns to us a handy CGPath to play with. Create a file named NSBezierPath+CGPath.swift and add the following code to it.

    import Cocoaextension NSBezierPath { public var cgPath: CGPath { let path = CGMutablePath() var points = [CGPoint](repeating: .zero, count: 3) for i in 0 ..< self.elementCount { let type = self.element(at: i, associatedPoints: &points) switch type { case .moveToBezierPathElement: path.move(to: points[0]) case .lineToBezierPathElement: path.addLine(to: points[0]) case .curveToBezierPathElement: path.addCurve(to: points[2], control1: points[0], control2: points[1]) case .closePathBezierPathElement: path.closeSubpath() } } return path }}

    At this point, everything will run, but we aren’t drawing anything quite yet. We still need to attach the drawing functions to actual mouse actions. In order to do this, we go back into our ClearWindow and update the NSResponder mouse methods to the following:

     override func mouseDown(with event: NSEvent) { (contentViewController as? ViewController)?.startDrawing(at: event.locationInWindow) } override func mouseDragged(with event: NSEvent) { (contentViewController as? ViewController)?.continueDrawing(at: event.locationInWindow) } override func mouseUp(with event: NSEvent) { (contentViewController as? ViewController)?.endDrawing(at: event.locationInWindow) }

    This basically checks to see whether the current view controller is our instance of ViewController, where we will handle the drawing logic. If you run the app now, you should see something like this:

    The app as it is now
    The app as it is now (View large version)

    This is not completely ideal, but we are currently able to draw on the blue portion of our screen. This means that our drawing logic is correct, but our layout is not. Before correcting our layout, let’s create a good way to quit, or disable, drawing on our app. If we make it full screen right now, we would either have to “force quit” or switch to another space to quit our app.

    5. Create A Menu

    Head back over to our Main.storyboard file, where we can add a new menu to our ViewController. In the right pane, drag “Menu” under the “View Controller Scene” in our storyboard’s hierarchy.

    Setting up the menu
    Setting up the menu (View large version)

    Edit these menu items to say “Clear,” “Toggle” and “Quit.” For extra panache, we can add a line separator above our “Exit” item, to deter accidental clicks:

    Creating menu options
    Creating menu options (View large version)

    Next, open up the “Assistant Editor” (the Venn diagram-looking button near the top right of Xcode), so that we can start hooking up our menu items. For both “Clear” and “Toggle,” we want to create a “Referencing Outlet” so that we can modify them. After this, we want to hook up “Sent Action” so that we can get a callback when the menu item is selected.

    Hooking up the code to the buttons
    Hooking up the code to the buttons (View large version)

    For “Exit,” we will drag our “Sent Action” to the first responder, and select “Terminate.” “Terminate” is a canned action that will quit the application. Finally, we need a reference to the menu itself; so, right-click on the menu under “View Controller Scene,” and create a reference named optionsMenu. The newly added code in ViewController should look like this:

    @IBOutlet weak var clearButton: NSMenuItem!@IBOutlet weak var toggleButton: NSMenuItem!@IBOutlet var optionsMenu: NSMenu!@IBAction func clearButtonClicked(_ sender: Any) {}@IBAction func toggleButtonClicked(_ sender: Any) {}

    We have the building blocks for the menu extras for our app; now we need to finish the process. Close out of “Assistant Editor” mode and head over to ViewController so that we can make use of these menu buttons. First, we will add the following strings to drive the text of the toggle button. Add the following two lines near the top of the file.

    private let offText = "Disable Drawing"private let onText = "Enable Drawing"

    We need to update what happens when the clear and toggle buttons are clicked. Add the following line to clear the drawing in clearButtonClicked(_ sender):

    view.window!.ignoresMouseEvents = !view.window!.ignoresMouseEventstoggleButton.title = view.window!.ignoresMouseEvents ? onText : offText

    This toggles the flag on our window to ignore mouse events, so that we will click “through” our window, in order to use our computer as intended. We’ll also update the toggleButton’s text to let the user know that drawing is either enabled or disabled.

    Now we need to finally put our menu to use. Let’s start by adding an icon to our project. You can find that in the repository. Then, we can override the awakeFromNib() method because, at this point, our view will be inflated from the storyboard. Add the following code to ViewController.

    let statusItem = NSStatusBar.system.statusItem(withLength: NSStatusItem.variableLength)override func awakeFromNib() { statusItem.menu = optionsMenu let icon = NSImage(named: NSImage.Name(rawValue: "pencil")) icon?.isTemplate = true // best for dark mode statusItem.image = icon toggleButton.title = offText}

    Make sure to put the statusItem near the top, next to the rest of the variables. statusItem grabs a spot for our app to use menu extras in the top toolbar. Then, in awakeFromNib, we set the menu as our optionsMenu, and, finally, we give it an icon, so that it is easily identifiable and clickable. If we run our app now, the “menu extra” icon will appear at the top! We aren’t quite finished yet. We need to ensure that the drawing space is placed correctly on screen; otherwise, it will be only partially useful.

    6. Positioning The Drawing App

    To get our view to draw where we want it, we must venture back into Main.storyboard. Click on the window itself, and then select the attributes inspector, the icon fourth from the left in the right-hand pane. Uncheck everything under the “Appearance,” “Controls” and “Behavior” headings, like so:

    Attributes inspector
    Attributes inspector

    We do this to remove all extra behaviors and appearances. We want a clear screen, with no bells and whistles. If we run the app again, we will be greeted by a familiar blue screen, only larger. To make things useful, we need to change the color from blue to transparent. Head back over to ClearWindow and update the blue color to this:

    backgroundColor = NSColor(calibratedRed: 1, green: 1, blue: 1, alpha: 0.001)

    This is pretty much the same as NSColor.clear. The reason why we are not using NSColor.clear is that if our entire app is transparent, then macOS won’t think our app is visible, and no clicks will be captured in the app. We’ll go with a mostly transparent app — something that, at least to me, is not noticeable, yet our clicks will be recorded correctly.

    The final thing to do is remove it from our dock. To do this, head over to Info.plist and add a new row, named “Application is agent (UIElement)” and set it to “Yes.” Once this is done, rerun the app, and it will no longer appear in the dock!

    Conclusion

    This app is pretty short and sweet, but we did learn a few things. First, we figured out some of the similarities and differences between UIKit and Cocoa. We also took a tour around what Cocoa has in store for us iOS developers. We also (hopefully) know that creating a Cocoa-based app is not difficult, nor should it be intimidating. We now have a small app that is presented in an atypical fashion, and it lives up in the menu bar, next to the menu extras. Finally, we can use all of this stuff to build bigger and better Cocoa apps! You started this article as an iOS developer and grew beyond that, becoming an Apple developer. Congratulations!

    I will be updating the public repository for this example to add extra options. Keep an eye on the repository, and feel free to add code, issues and comments.

    Good luck and happy programming!

    Attributes inspector
    Thank you!

    (al)