Jump to Navigation

Around The Web

Dark Patterns And Other Design No-Nos For Mobile

Smashing Magazine - 1 hour 19 min ago
Dark Patterns And Other Design No-Nos For Mobile Dark Patterns And Other Design No-Nos For Mobile Suzanne Scacca 2018-09-24T14:00:18+02:00 2018-09-24T12:10:20+00:00

When it comes to making money, some companies will do whatever it takes to get people inside their establishment. But does that kind of business tactic even work?

In my opinion, if you have to lie or trick your consumers into a sale, well then, that won’t obviously work! You might be able to attract a good amount of foot traffic (and even make some sales from the deceitful strategy), but let’s look at the big picture. If traffic levels won’t sustain and you’re handling more refunds than sales, the approach was a total failure. I’d suspect that to happen with a lot of people who attempt to use trickery to boost business both in the real world and digital space.

That’s why, today, I’m dedicating this post to dark patterns. We’re going to talk about what a dark pattern is, look at some well-known examples and then talk about why they’re always a bad idea — even if your client tries to convince you otherwise.

Designing Friction For A Better User Experience

In experience design, friction is usually the opposite of being intuitive or effortless. However, that doesn’t mean that it’s always bad for the users. Read related article →

What Are Dark Patterns?

The phrase was coined by Harry Brignull, a UX research specialist. According to Brignull:

“Dark Patterns are tricks used in websites and apps that make you buy or sign up for things that you didn't mean to.”

He has since developed a website dedicated to the worst of the worst Dark Patterns:

An example of a ‘Bait and Switch’ dark pattern from Microsoft. (Source: Dark Patterns) (Large preview)

As you can see here, Brignull has defined one of the types of dark patterns used on the web. This specific example comes from Microsoft’s usage of a bait-and-switch pop-up that doesn’t behave as it should. I’m going to explain why this was such a huge problem for Microsoft’s users down below.

Our new book, in which Alla Kholmatova explores how to create effective and maintainable design systems to design great digital products. Meet Design Systems, with common traps, gotchas and the lessons Alla has learned over the years.

Table of Contents → How Are Dark Patterns Used In Web Design?

In total, Brignull classifies dark patterns into 12 categories. I’m going to include each of them — as well as some of my own — in the following guide:

1. Bait and Switch

This happens when a user assumes that a specific reaction will take place upon engagement with a website. Typically, this is based on expectations set by the rest of the web. In the case of a bait-and-switch, however, an undesired response is the result.

Microsoft used this tactic a couple years back when it was trying to get users to make the recommended update to Windows 10. (That’s the image above from Brignull’s website.) Users claimed that, when X’ing out of the pop-up, their systems automatically updated without consent. The “X” should have indicated that the user did not want to proceed, but it did the opposite.

Now, here’s the thing. Software does need to be updated in order to keep systems running quickly and securely. However, if you’re tricking users into initiating an update they don’t want or aren’t prepared for, you could face serious consequences if it goes wrong. For instance, this woman won $10,000 as a result of the damage the Windows update caused her system.

These kinds of dark patterns don’t always lead to destructive consequences though. Sometimes they’re just really disruptive to the user experience.

For example, I was looking at the join.me website as I researched solutions for screen sharing with my clients. While looking over the pricing options, the contact widget from the bottom of the screen opened into this pop-up:

Join.me asks if I want to talk to someone through live chat. (Source: join.me) (Large preview)

I wasn’t in need of assistance at the time, so I clicked the “X” in the right corner of the pop-up. However, upon doing so, this is what I saw:

Join.me initiates live chat when the “X” is clicked. (Source: join.me) (Large preview)

I was surprised to see this page as I most definitely had not asked to “Start Chat”. Then, once I realized what this full-page pop-up was attempting to do, I immediately wanted to exit out. But the way to do that is in the top-left corner, which threw me for a bit of a loop as the “X” from the original pop-up was in the top-right.

The entire experience with the live chat probably consumed no more than five seconds of my time, but it still was a jarring one. I tried to take an action that said, “No, thank you,” but I was forced to engage. It’s like being in a restaurant and having the server bring you a dessert menu or tray even though you explicitly told them you weren’t interested.

If you want to annoy your visitors and prove to them that you’re not listening, use this dark pattern.

Recommended reading: Are Mobile Pop-Ups Dying? Are They Even Worth Saving?

2. Confirmshaming

Confirmshaming was pretty popular in pop-ups about a year or two ago. Users would see the pop-up and have two options:

  • The positive option would encourage them to move towards conversion;
  • The negative option would shame them for making a seemingly bad choice by not doing so.

There are still a number of websites that you’ll see do this, though there’s far fewer of them these days what with many designers steering clear of pop-ups on mobile.

Social Media Examiner still uses this double-CTA pop-up on its mobile site though:

Social Media Examiner uses 2 CTAs to “shame” users into clicking through. (Source: Social Media Examiner) (Large preview)

Personally, I don’t think the shaming in this pop-up is that bad compared to others I’ve seen. You know the ones I’m talking about. The positive CTA says something like, “Yes, I want to double my revenue this year!” The other says something like, “No, I want my business to crash and burn!”

The intention in using confirmshaming CTAs is to use the consumers’ fears to talk some sense into them. But is that really what’s happening here? While I’m sure this strategy does work on some users, I don’t know if most people would fall for it.

My suggestion here would be to stay away from shaming visitors altogether. If you want to use the double-CTA method, however, opt for something like ghost buttons. This strategy aims to give you the same outcome: get visitors to click through and/or convert. However, it does it with subtle design persuasion. In other words:

  • This button that’s big and colorful is deserving of your attention;
  • This button that’s devoid of life is here (if you want it) but we’re happy if you want to ignore it altogether, too.
3. Disguised Ads

Generally, it’s pretty clear when an ad — even a native one placed mid-content — is there for promotional purposes. However, when an ad cannot clearly be distinguished as such, this can be an issue for visitors.

If you follow what happens in the world of influencer marketing on social media, you might recognize this problem with deception from Instagram. Basically, here’s what was (and still is) happening:

  • Users who promote products or content as a form of advertisement or sponsorship are supposed to explicitly declare the promotion as such. That’s because they’re getting paid for their efforts and it’s not a genuine recommendation on their part.
  • When influencers fail to announce that such endorsements are paid placements from brands, users may be deceived into buying something because they believed it to be a valid recommendation. And that’s a major problem.

According to the FTC:

“If there is a ‘material connection’ between an endorser and an advertiser — in other words, a connection that might affect the weight or credibility that consumers give the endorsement — that connection should be clearly and conspicuously disclosed, unless it is already clear from the context of the communication.”

The same should hold true when it comes to on-site advertisements, but there’s been no real regulation of this thus far. That said, we do recognize certain disguised advertisements for what they are: dark patterns.

One example I want to share comes from Travel & Leisure:

As I was reading an article about the best places to experience changing autumn colors in the United States, I became quite enraptured by the images included.

Travel & Leisure includes engaging graphics within this article. (Source: Travel & Leisure) (Large preview)

As I skimmed further down, I encountered this image — or what I thought was an image.

Travel & Leisure injects advertisement that looks just like article into the post (Source: Travel & Leisure) (Large preview)

Once the page fully loaded (which took more than a few seconds), I realized this was a video. At this point, a couple of thoughts ran through my mind:

  • Did I scroll too far? Were the rest of the fall foliage trip recommendations in a slider above?
  • Why is a Bermuda summer vacation included on a list about fall foliage?

I decided to keep scrolling through the identically-formatted text for Bermuda to see what came next, and then I noticed a note beneath it that read “From Bermuda Tourism Authority”:

Travel & Leisure mixes content with ads for confusing user experience. (Source: Travel & Leisure) (Large preview)

Once I got past the native video ad that looked exactly like the rest of the page, I was able to read the rest of the post. But it left a bad taste in my mouth.

I had set out to see some cool imagery and pick up some tips for fall travel, but was tricked. Albeit, the dark pattern only got me temporarily, but it still disrupted the experience and made me wonder what other deceptions would abound. What if all the ideas in this post or anywhere on the site solely came from sponsors and not from actual trips worth taking?

If you leave your visitors wondering whether or not they can trust your website, then you’ve gone down a bad path, m’friends.

4. Forced Continuity

This type of dark pattern occurs when someone signs up for a “free” trial, but is required to share credit card information during the intake process. Then, when the trial period ends, their credit card is charged without warning.

For users that don’t pay attention to these kinds of things and assume that brands won’t take advantage of them, this form of deception will definitely not go over well. In addition to losing the trust and business of these users, your business could be penalized if a credit card company or local business bureau gets involved.

Although this kind of dark pattern usually doesn’t have anything to do with design, it’s still one worth knowing about as a designer. That’s because you can use various design strategies and layouts to point potential customers to those revealing details about automated payments and what-not.

I’m going to use join.me once again for my next example.

Join.me offers three priced plans. (Source: join.me) (Large preview)

On join.me’s pricing page, you’ll encounter three plans — each with an associated cost. It’s actually not until you locate the much smaller and non-highlighted CTA that you can explore more about what comes with each plan:

Join.me hides details about its plans with a hard-to-find CTA. (Source: join.me) (Large preview)

For users that discover this CTA, they’ll be able to explore the features of each plan within this detailed pop-up:

Join.me only mentions the free plan once users ask for more information. (Source: join.me) (Large preview)

I was quite happy to discover that join.me has a free plan. However, in order to gain access to it, you have to sign up for the PRO plan. This is what’s included in the trial:

Join.me requires credit card information for a PRO plan trial. (Source: join.me) (Large preview)

Once you’ve submitted your user and purchase details, you’re then granted access to a free, 14-day trial. If you choose not to proceed with PRO, only then can you gain access to the free plan that join.me doesn’t readily advertise.

Now, this example deviates slightly from the above-mentioned point. Or at least I hope it does. Since I haven’t purchased a trial of join.me, I can’t tell you if this site auto-charges after the trial without warning. That said, the way in which the free plan is mentioned and the way in which users are able to get it, leads me to believe that it’ll be difficult to cancel the PRO plan before the trial ends.

5. Friend Spam

Logging into websites and apps with social media accounts or Google is a common thing nowadays. Nevertheless, the companies that are using your list of friends to spam your contacts, however, is (hopefully) not.

That said, one major brand was found guilty of this and is now having to pay $13 million as a result: LinkedIn.

It appears that LinkedIn used its users’ contact lists for personal gain. Basically, it offered an “add connection” feature on its website in the early 2010s. This enabled users to quickly connect with people they knew or, rather, to send them a message and ask them to connect on LinkedIn.

While the service seems fair enough (after all, it can be difficult to track down previous acquaintances and workers on your own), LinkedIn still took it too far.

What should have been a simple email that said, “Hey, so-and-so wants to connect with you on LinkedIn,” turned into a number of follow-up emails to those contacts. The unwarranted harassment wasn’t necessarily the problem. The biggest problem was that LinkedIn crafted these emails in a way that made it seem as though it was coming directly from the known acquaintance.

This just goes to show you that it doesn’t matter how popular or well-revered your platform is. If you abuse your users’ trust for your own personal gain, there’s going to be a major backlash. A $13 million lawsuit is definitely a severe consequence, but even just the loss of customers should be enough to deter you from this dark pattern.

6. Hidden Costs

This one is self-explanatory. You do some shopping online, you’re satisfied with the items you’ve added to your cart, and so you decide to finally go to checkout where you discover costs you were unaware of.

While you might not believe this is a matter that you as a designer have a hand in, I’d urge you to take a look at this dark pattern example from Southwest Airlines:

The total price from Southwest Airlines appears independent of the individual flight prices. (Source: Southwest Airlines) (Large preview)

As I looked for a roundtrip flight between Albany, NY and Atlanta, GA, I was presented with various pricing options. Time of day, number of layovers and so on affected how much I would have to pay on each leg of my journey. That’s to be expected.

However, what I hadn’t expected was that the total price displayed before checkout would be off from what I thought it to be. As you can see here, this final page doesn’t even show the prices of the individual legs of the trip anymore. It just shows the total cost and then asks me to continue on.

That’s when I realized there were tiny “Includes taxes and fees” and “Show fare breakdown” messages beneath the Total line. When I expanded them, I encountered this:

Hidden costs from Southwest Airlines can be revealed. (Source: Southwest Airlines) (Large preview)

When it comes to travel and hospitality, it’s normal to expect charges for things like carry-on bags, resort fees, and so on. Still, this wasn’t what I expected to show up and there was no real mention of it made as I selected my flights earlier on. What’s worse, many of these charges aren’t even explained.

Now, there are some travel sites that handle this sort of thing in a reputable manner. However, I assume that many of them prefer to go the Southwest Airlines route of manipulating design and typography in a way that keeps extra charges hidden from plain view.

Recommended reading: How Mobile Web Design Affects Local Search (And What To Do About It)

7. Misdirection

Misdirection on a website is really no different than a magician’s trick. The website draws your attention to one thing while doing something deceitful somewhere else.

A good example of this is subscription forms for online publications. You usually see this when a magazine belongs to a much larger brand. Other magazines from the publisher are then promoted during the sign-up process. And it’s typically nothing more than a pre-checked checkbox at the bottom of the form that asks if you also want to subscribe to their newsletters or subscriptions.

For example, here is the Eater newsletter subscription form:

A seemingly tradition newsletter subscription form from Eater. (Source: Eater) (Large preview)

It’s not all that strange that the form sits at the top of the page. Or, at least, it wouldn’t be if it were the only subscription offered.

But as you scroll down, you can see that the Today newsletter is automatically checked:

Eater automatically signs me up for a daily email. (Source: Eater) (Large preview)

That would be okay, except that I was on the Eater Philly website. I didn’t want generic Eater news. I wanted news related specifically to the area of the U.S. that I live in. I also don’t know if I was too crazy about a daily newsletter.

If I were to scroll down even further on the page, I’d discover more newsletter options:

More newsletters from Eater. (Source: Eater) (Large preview)

Thankfully, none of these were checked on my behalf, but it’s still strange that all these options are placed below the form, including the city selection:

Eater also includes city-specific newsletter subscriptions. (Source: Eater) (Large preview)

By “hiding” checkboxes and pre-selecting one for your users, you’re putting them in a position to receive messages that they’re not likely to be happy to receive. When they unsubscribe from those emails and state the reason such as “I never signed up for these communications.” That’s no good.

8. Price Comparison Prevention

For many users, mobile websites are visited for the purposes of doing research. Having access to multiple devices to simultaneously search with or having one device to take on the go to complement the on-site shopping experience, is a benefit many shoppers greatly enjoy.

However, if you prevent users from being able to easily compare prices within your website, it’s probably because you’re hiding something.

With the Southwest Airlines example I mentioned above, the website prevented me from tracking the individual prices of each leg of my trip. That was a pain since it required me to write them down somewhere so I could make sure I wasn’t exceeding my budget in the end.

Then, there’s this airline that just won’t reveal prices at all: British Airways.

British Airways forces you to compare flight times before showing prices. (Source: British Airways) (Large preview)

As you can see here, you can skim through flight times and stopover options on British Airways. While you can compare the times and number of stops against one another, prices aren’t actually revealed until you select a trip.

This makes the experience of booking a flight through British Airways incredibly annoying — to say the least. While prices can be compared, it requires a number of back-and-forths to gather that information. And, chances are good that if you hit the browser “Back” button, it’ll reset the data and you’ll have to re-enter all your trip information from the beginning.

While it’s nice that the designers of this mobile site inform visitors that prices aren’t revealed at this stage, the call to do so is a bad choice on British Airways’ part.

9. Privacy Zuckering

Here’s the basic premise of this dark pattern: When a design or piece of content does not make it clear that the sharing of data is optional or doesn’t present an easy way out of it, this would be a case of Zuckering.

I’m sure Mark Zuckerberg wouldn’t be too happy to know that Brignull named this one after him, but Facebook is known for luring users into giving more information than they have to — which is why this one is aptly named.

One example of this I run into often doesn’t actually occur on Facebook. Instead, it’s one I encounter on BuzzFeed when I’m taking a break from writing. Here’s what happens:

My brain starts to hurt and I find myself needing a quick distraction. I go to the living room, sit on my couch and pull out my phone. I immediately go to BuzzFeed’s quiz section. They’re entertaining and I know I can get through them quickly. Like this one about movies:

An example of fun BuzzFeed quizzes. (Source: BuzzFeed) (Large preview)

I start the quiz and quickly get into a groove of reading the question, looking at the entertaining graphics and choosing my answer. It’s a great mind-numbing activity that helps me reset.

Until this happens:

BuzzFeed sneaks in additional questions. (Source: BuzzFeed) (Large preview)

This is an unrelated question that BuzzFeed has snuck into my quiz. It usually occurs two or three paces down the page. This example happens to be completely unrelated to the quiz I was taking, so I was able to spot it right away. But sometimes they do a very good job of blending the topics so that I’m fooled into providing them with a revealing answer.

When your design incorporates additional interactive elements that don’t actually need to be engaged with, you should let users know that’s the case. Not only is it a waste of time — especially for mobile users — but it distracts from the rest of the experience.

10. Roach Motel

The trademarked product “Roach Motel” from Black Flag is one that lures cockroaches and other pests into a sticky situation that is then very difficult to get out of. This is exactly what some websites do.

In some instances, a roach motel occurs when a website or app makes it incredibly difficult to delete an account or unsubscribe from a list. You’ll most commonly see this with free trials of SaaS products.

In other cases, it might be a landing page a visitor has fallen into, but is unable to back out of using the website’s navigation (since it’s gone). Instead, users have to rely on the browser’s Back button, which can be a pain if it resets any work that had been inputted prior to that landing page.

Then, there are roach motels like the Wells Fargo Center website:

Wells Fargo Center’s form to purchase tickets. (Source: Wells Fargo Center) (Large preview)

The first page of the ticket purchase form is fine. You indicate what price range you want your tickets to fall within and then you choose how many you need. Seems pretty straightforward.

What’s odd, though, is that it now says “Add to Cart.” It’s my assumption that I’ll be able to choose my specific seats at that point.

Wells Fargo Center automatically chooses my tickets and adds them to the cart. (Source: Wells Fargo Center) (Large preview)

What happens instead is that the Wells Fargo Center automatically chooses my tickets and adds them to the cart. I had no say in which seats I wanted. Instead, the most expensive tickets for $1,250 were added to my cart.

At this point, I decide that I want to back out and try to find better seats. When I click on “change seats”, it takes me back to the original page where I get to make only vague choices about where I want to sit and how much I want to pay. The trash icon below does the same thing except that it completely clears out the tickets in my cart. Either way, I’m left feeling helpless as I have no control over the experience.

In a last ditch effort, I thought I’d move on to the next step to see if I had any more control there. I clicked on “cost details”, saw the associated charges and upgrades (which I hadn’t expected) and realized I could only “Checkout” at that point:

The Wells Fargo Center form gets users stuck. (Source: Wells Fargo Center) (Large preview)

I eventually decided not to buy these tickets because I had no control over the process and because of how stuck I felt once I got deep inside it.

As you design journeys for your own users, don’t do this to them. Give them an easy way to reverse their tracks and to back out of a process if they’re unhappy with it. And, if it can be helped, give them more control over the choices and customizations they make. It’s hard enough to convert mobile users, don’t turn them off from your mobile website altogether because of this.

11. Sneak into Basket

There are typically two ways users will find an unexpected item in their shopping cart. The first is by the website automatically adding it on. The second is by the website tricking the user into adding it themselves by placing a checkbox or other add-on option in a spot where something else should be.

Case in point: the Central Park Zoo.

Buy tickets from the Central Park Zoo online. (Source: Central Park Zoo) (Large preview)

The form to purchase tickets is pretty basic. Simply choose the tickets for the people that will be visiting the zoo.

You make your selections and scroll down to make the purchase.

The first CTA in the Central Park Zoo form is not for purchasing. (Source: Central Park Zoo) (Large preview)

For mobile users that are in a hurry, they might not even think to read the button that appears. It’s big, bold and appears directly beneath the form. Why not click it?

However, upon closer inspection, you’ll see that “Yes, Add $5 to My Order” is what this CTA button calls for. Now, someone reading that quickly might read that as “Yes, Add to My Order” thinking it’s referring to the tickets.

It’s not until the mobile user makes one more swipe on their phone that they see the actual checkout button:

The real checkout button requires three full swipes of the Central Park Zoo page. (Source: Central Park Zoo) (Large preview)

As users, we are trained to understand how common web elements act. A contact form follows a simple formula:

  • Fill out the pertinent details.
  • Click the button to complete the purchase.

It’s an easy 1-2 punch to execute as a web designer. However, when you throw something in your users’ pathway that resembles a button, you’re very likely to trip them up in the process. Or you’ll find a lot of angry visitors who unknowingly added and paid extra money because of the confusing way the form was designed.

12. Trick Questions

This one happens a lot with things like exit-intent pop-ups. By using language that is confusing or incorrectly written (like a double negative), the site is able to keep visitors put until they realize their mistake in understanding the question.

Tricky messaging can also be used to drive up costs. Here is what I experienced when trying to order flowers from 1-800-Flowers:

Ordering flowers from 1-800-Flowers. (Source: 1-800-Flowers) (Large preview)

I was pretty happy with this floral arrangement and thought the large would be nice for my friend’s table. As I scrolled down, I saw this checkbox for “FREE Shipping.” I didn’t bother to click on the “i” icon since I figured, “What more do I need to know about free shipping and no service charges? Sounds like a good deal to me.”

The free shipping promise from 1-800-Flowers isn’t what it seems to be. (Source: 1-800-Flowers) (Large preview)

After clicking the box, this message about the Celebrations Passport appeared, but I didn’t bother to pay attention to it. Once the box was checked, I quickly moved on to enter my zip code; I wanted those flowers delivered ASAP.

1-800-Flowers tries another upsell. (Source: 1-800-Flowers) (Large preview)

As I continued to select a delivery date, this upsell screen appeared on my phone. I considered it briefly and decided I don’t need any of these add-ons. I couldn’t find an “X” button, so I clicked “Continue” and hoped that none of these items had been added to my purchase.

A surprise in my 1-800-Flowers shopping cart. (Source: 1-800-Flowers) (Large preview)

I finally arrived at my shopping cart and discovered that ‘12 Months of Passport’ had also been added to my cart. Thankfully, I screenshotted the process for the purpose of this article. Otherwise, I would’ve had no idea where the add-on came from. Granted, it ended up here because I didn’t read the details closely.

That said, when you lead with something like “FREE shipping”, how many customers do you think will take time to read any further? We all understand what that phrase means in most contexts. By not clearly stating that this was a 1-800-Flowers upgrade, many users are likely to select that box and end up with an unintended item at checkout.

In addition to Brignull’s list, I want to add a couple more dark patterns that I find especially perturbing on the mobile web and in mobile apps.

Recommended reading: What You Need To Know To Increase Mobile Checkout Conversions

13. Unnecessarily Deep Navigation

This reference to navigation doesn’t really pertain to the hamburger menu mobile visitors use on websites. Instead, I’m referring more to those websites that have blog posts and quizzes that span multiple pages.

In some cases, I’m sure this is done for the purposes of keeping load times on individual pages fast. However, a properly optimized server and a website with a solid caching mechanism shouldn’t have those sorts of problems, even with a page loaded with images. My guess? These websites create multiple pages for a single post for the purposes of superficially bolstering the number of page views they get.

A good example of this comes from MagiQuiz:

A typical quiz from the MagiQuiz mobile site. (Source: MagiQuiz) (Large preview)

The image above shows what a typical quiz looks like from the MagiQuiz website. Engaging imagery, question and answers to choose from.

However, the image below is what the typical quiz interface looks like when you actually scroll through it. It’s littered with advertisements, distractingly breaking up the experience of the quiz on the page:

Ads litter the pages of the MagiQuiz site. (Source: MagiQuiz) (Large preview)

As if those in-line ads weren’t enough, users finally get to the bottom of the page to find this:

The “Continue” button is hidden among ads and indicates it’s not the end of the quiz. (Source: MagiQuiz) (Large preview)

It’s not actually the bottom of the quiz at all. All of that scrolling and skipping past unrelated ads made the quiz take so long, and now there’s still more to do in order to reach the payoff. That sucks — if you ask me!

Unfortunately, quiz sites such as MagiQuiz aren’t the only ones that do this. Major publishers like Forbes are guilty of this as well, breaking up otherwise short stories (no more than 800 or 1,000 words) into multiple pages. If this were a way to conserve server bandwidth, that would make sense, but I’m guessing this dark pattern is used for mainly selfish reasons.

14. Made-You-Look Notifications

One final dark pattern I want to call out is the made-you-look notification. I usually see this sort of thing on mobile apps that claim that I have activity or communications to look at. Since I’m already active on those apps, it’s usually not a big deal to open them and see what all the fuss is about. Sure, it’s annoying to discover the notification was just to remind me to respond to someone, but it’s not a problem if I was going to be in there anyway.

Mobile websites, on the other hand, shouldn’t be making use of this dark pattern. If there’s no history of engagement, then visitors’ attention should not be drawn to something that won’t improve the experience.

1-800-Flowers, again, is guilty of using this particular dark pattern:

1-800-Flowers tells me there’s a message in my inbox. (Source: 1-800-Flowers) (Large preview)

See how my inbox has a green number “1” hovering over it? It looks just like email reminders you’d get from Gmail or Outlook, right?

Here’s the problem with this: Before today, I’d never been to the 1-800-Flowers website nor do I have an account with them. Yet, my eye was drawn to that message sitting in my inbox. It’s just a gut reaction I have. When I see that someone has messaged me, it’s usually from a client that I want to get back to ASAP. It’s that sense of urgency that compels me to instantly click to find out what action is needed.

And, so, this is what I did:

1-800-Flowers fakes out users with inbox alerts. (Source: 1-800-Flowers) (Large preview)

I knew the message that appeared wouldn’t be of relevance to me even before I clicked it, but I needed to see what it said.

As you can imagine, I wasn’t too happy to see an unhelpful promotion like this waiting for me. It’s not even like 1-800-Flowers went to the trouble of promoting flowers for an upcoming occasion (like homecoming events or the approaching holiday season). They just wanted to distract me from what I set out to do in the first place.

Honestly, I’m not sure what 1-800-Flowers (and other brands that do this) hoped to gain from this dark pattern. When people come to a flower delivery site, they typically know what they’re there for. Let them take the user journey you’ve already so carefully planned it out for them and leave those urgent notifications for websites or apps that can share personalized content and messages with their users.

Wrapping Up

Okay, so what have we learned here? To begin with, dark patterns are a way to use design and content to trick users into taking an unintended action. Still, are they effective?

In all honesty, I’m going to guess that — initially — dark patterns work on many visitors. For companies that are only concerned with the superficial success of a website (i.e. visits, page views, and sales), then that may be a good thing.

For companies that understand that short-term gains in these areas can easily be outweighed by losses from refunds, low customer retention rates and lawsuits, dark patterns will ultimately prove not to be worth it.

Deceitful design tactics won’t get you anywhere good with your visitors. Not only does this deception hurt your ability to gain customer loyalty, but it hurts the overall user experience online.

Think about it: enough users get burned by a certain type of website (say, a SaaS tool that makes it difficult to cancel). So, now they comb through every field in the sign-up or check-out process because they’re nervous about being overcharged or sucked into a bad deal. Or they spend so much time digging through your site trying to find some hint that gives the jig away. At the end of the day, users just give up or avoid making those kinds of purchases online altogether.

The user experience should be fast and easy and take visitors on a straight and narrow path to conversion — not make them second-guess their decision to be there in the first place.

(ra, yk, il)
Categories: Around The Web

A Guide To Embracing Challenges And Excelling At Your UX Design Internship

Smashing Magazine - Fri, 09/21/2018 - 8:15am
A Guide To Embracing Challenges And Excelling At Your UX Design Internship A Guide To Embracing Challenges And Excelling At Your UX Design Internship Erica Chen 2018-09-21T14:15:20+02:00 2018-09-24T12:10:20+00:00

This is the story about my user design internship. I’m not saying that your internship is going to be anything like mine. In fact, if there’s one thing I can say to shape your expectations, it would be this: be ready to put them all aside. Above all else, remember to give yourself space and time to learn. I share my story as a reminder of how much I struggled and how well everything went despite my difficulties so that I’ll never stop trying and you won’t either.

It all started in May 2018, when I stepped off the plane in Granada, Spain, with a luggage at my side, laptop on my back, and some very rusty Spanish in my head. It was my first time in Europe and I would be here for the next three months doing an internship in UX design at Badger Maps. I was still pretty green in UX, having been learning about it for a barely a year at this point but I felt ready and eager to gain experience in a professional setting.

Follow along as I learned how to apply technical knowledge to complete the practical design tasks assigned to me:

  • Create a design system for our iOS app using Sketch;
  • Design a new feature that would display errors occurring in data imports;
  • Learn the basics HTML, CSS, and Flexbox to implement my design;
  • Create animations with Adobe Illustrator and After Effects.

This article is intended for beginners like me. If you are new to UX design looking to explore the field — read on to learn if a UX design internship is the right thing for you! For me, the work I ended up completing went well beyond my expectations. I learned how to a design system, how to compromise design with user needs, the challenges of implementing a new design, and how to create some “moments of delight.” Every day at the internship presented something new and unpredictable. At the conclusion of my internship, I realized I had created something real, something tangible, and it was like everything I had struggled with suddenly fell into place.

Recommended reading: How To Land A First-Rate Graphic Design Internship

Meet SmashingConf New York 2018 (Oct 23–24), focused on real challenges and real front-end solutions in the real world. From progressive web apps, Webpack and HTTP/2 to serverless, Vue.js and Nuxt — all the way to inclusive design, branding and machine learning. With Sarah Drasner, Sara Soueidan and many other speakers.

Check all topics and speakers ↬ Chapter 1: Legos

My first task was to create a design system for our existing iOS app. I had created design systems in the past for my own projects and applications, but I had never done them retrospectively and never for a design that wasn’t my own. To complete the assignment, I needed to reverse engineer the mockups in Sketch; I would first need to update and optimize the file in order to create the design system.

Working with organizing the Sketch file to create a design system. (Large preview)

It was also at this opportune moment when I learned the Sketch program on my computer had been outdated for about a year and a half. I didn’t know about any of the symbols, overrides and other features in the newer versions. Lesson learned: keep your software updated.

Creating footers and working with overrides in Sketch. (Large preview)

Before worrying about the symbols page, I went through the mockups artboard by artboard, making sure they were updated and true to the current released version of the application. Once that was done, I began creating symbols and overrides for different elements. I started with the header and footer and moved on from there.

As a rule of thumb, if an element showed up in more than one page, I would make it a symbol. I added different icons to the design system as I went, building up the library. However, it quickly became clear that the design system was evolving and changing faster than I could try to organize it. Halfway through, I stopped trying to keep the symbols organized, opting instead to go back and reorganize them once I had finished recreating each page. When I stopped going back and forth between mockups and symbols and worrying about the organization for both, I could work more efficiently.

It was easy to come to appreciate the overrides and symbols in Sketch. The features made the program much more powerful than what I was used to and increased the workability of the file for future designs. The task of creating the design system itself challenged me to dive deep into the program as well as understand all the details of the design of our application. I began to notice small inconsistencies in spacing, icon size, or font sizes that I was able to correct as I worked.

A caption to be shown below the image. (Large preview)

The final step was to go back into the symbols page and organize everything. I weeded through all the symbols, deleted those not in use and any replicas. Despite being a little tedious, this was a very valuable step in the process. Going through the symbols after working through the document gave me a chance to reevaluate how I had created the symbols for each page. Grouping them together forced me to consider how they were related throughout the app.

By going through this thought process, I realized how challenging it was to create a naming system. I needed to create a system broad enough to encompass enough elements, specific enough to avoid being vague, and that could easily be understood by another designer. It took me a few tries before I landed upon a workable system that I was happy with. Ultimately, I organized elements according to where they were used in the application, grouping pieces like lists together. It worked well for an application like Badger that had distinct designs for different features in the app. The final product was a more organized file that would be a lot easier to work with for any future design iterations.

Modernizing the design with new header designs. (Large preview)

As a capstone to this project, I experimented with modernizing the design. I redesigned the headers throughout the app, drawing on native apple apps for inspiration. Happily, the team was excited about it as well and are considering implementing the changes in future updates to the app.

Overall, working a Sketch file to such detail was an unexpectedly helpful experience. I left with a much greater fundamental understanding of things like font size, color, and spacing by virtue of redoing every page. The exercise of copying existing design required a minute attention to detail that was very satisfying. It was like putting together a Lego model: I had all the pieces and knew what the end product needed to look like. I just needed to organize everything and put them together to create the finished product. This is one of the reasons why I enjoy doing UX design. It’s about the problem solving and piecing together a puzzle to create something that everyone can appreciate.

Dashboard design for the Badger web application. (Large preview) Chapter 2: The Design

The next part of my internship allowed me to get into the weeds with some design work. The task: to design a new import page for the Badger web application.

The team was working on redesigning the badger to CRM integration to create a system that allowed users to view any data syncs and manage their accounts themselves. The current connection involves a lot of hands-on work from badger CSAs and AEs to set up and maintain. By providing an interface for users to directly interact with the data imports, we wanted to improve the user experience for our CRM integration.

Existing process: Users currently integrating Badger with their Salesforce accounts can’t manage the flow of information between the two. They can’t view any errors in data being imported to Badger or easily see the status of their import. To the right is the existing errors view for users importing via spreadsheets. We want to improve this user experience and make it accessible to Salesforce-integrated users as well. (Large preview)

My goal was to design a page that would display errors occurring in any data imports that also communicated to users how and where to make the necessary changes to their data. If there were more errors associated with a single import or users would like to view all errors at once, they should be able to download an excel file of all that information.

Objectives
  1. Create an import page that informs the user on the status of an import in process;
  2. Provide a historical record of account syncs between Badger and the CRM with detailed errors associated with each import;
  3. Provide links to the CRM for each account that has an import error in Badger;
  4. Allow users to download an excel file of all outstanding errors.
User Stories

Badger customer with CRM account:
As a customer with a CRM, I want to be able to connect my CRM to my badger and visualize all data syncs so that I’m aware of all errors in the process and can make changes as necessary.

Badger:
As a badger, I want users to be able to manage and view the status of their CRM integration so that I can save time and manual work helping and troubleshooting users syncing their badger to their CRM accounts.

Before I really delved into the design, we needed to go through some thinking to decide what information to show and how:

  1. Bulk versus continuous imports
    Depending on the type of user, there are two ways to import data to Badger. If done through spreadsheets, the imports would be batched and we would be able to visualize the imports in groups. Users integrated with their CRMs, however, would need to have their Badger data updated constantly as they made changes within their CRM. The design needed to be able to handle both use cases.
  2. Import records
    Because this was a new feature, we weren’t absolutely sure of the user behavior. Thus, deciding how to organize the information was challenging. Should we allow users to go for an infinity scroll in a list of their history? How would they search for a specific import? Should they be able to? Should we show the activity day-by-day or month by month?

Ultimately, we were only able to make a best guess for each of these issues — knowing that we could make appropriate adjustments in the future once users began using the feature. After thinking these issues out, I moved into wireframing. I had the opportunity to design something completely different and this was both liberating and challenging. The final design was a culmination of individual elements from various designs that were created along the way.

Design Process

The hardest part of this process was learning to start over. I eventually learned that forcing something into my design for solely aesthetic purposes was not ideal. Understanding this and letting my ideas go was key to arriving at a better design. I needed to learn how to go start over again and again to explore different ideas.

First few iterations: Experimenting with the placement of the header, buttons, and list design. Feedback at this point and for the next few days was consistently as it should be: 'let’s see what else we can do.' But the advantages to running like a headless chicken was that I occasionally stumbled upon some corn kernels of gold that I used in the final design. (Large preview) One design exploration that stretched a little too far from the badger application. After this, I circled back a little but the final design really benefited from exploring such different ideas. (Large preview) Challenges 1. Using white space

Right off the bat, I needed to explore what information we wanted to show on the page. There were many details we could include — and definitely the room to do it.

Initially, I was very intimidated at the prospect of having a lot of white space and a minimalistic design so tried really hard to come up with filler information, 75% of which our users wouldn’t really need. Then I crammed it all into my design, permitting minimal breathing room. A very good attitude for a city planner in San Francisco; not so much for creating user centric design. (Large preview)

All the unnecessary information added way too much cognitive load and took away from what the user was actually concerned about. Instead of trying to get rid of all the white space, I needed to work with it. With this in mind, I eventually chucked out all the irrelevant information to show only what we expect our users to be most concerned about: the errors associated with data imports.

This was the final version:

Imports organized according to day and month. This was a more logical organization for our purposes, especially because synchronizations between the CRM and Badger were continuous, not just on demand. (Large preview) 2. Navigation

The next challenge was deciding between a sidebar versus a header for displaying information. The advantages to the sidebar was that the information would be consistently visible as the user scrolled. But we also had to ensure that the information contained in the sidebar was logically related to what was going on in the rest of the page.

The header offered the advantage of a clean, single column design. The downside was that it took up a lot of vertical real estate depending on how much information was contained in the header. It also visually prioritized the contents of the header over what was below it for the user.

Iteration exploring the top navigation. Cons: users would scroll through the list of imports to view errors and have to scroll back up to see the summary. The contents and location of the two cells to the right was also confusing. It didn’t make sense for the two cells to scroll with the rest of the page because they were a summary of all information to its left. But it would make for a confusing user experience if they didn’t scroll. Overall, the organization of the information on the page was misaligned with the design. (Large preview)

Once I worked out what information to display where, the sidebar navigation became the more logical decision. We expect users to be primarily concerned with the errors associated with their imports and with a large header, too much of that information would fall below the fold. The sidebar could then be a container for an import and activity summary that would be visible as the user scrolled.

Sidebar design: After I decided on having a sidebar, it came down to deciding what information to include and how to display it.

Different sidebar design explorations. The design became increasingly simple as I narrowed in on the information the users wanted to see. (Large preview)

I struggled to create a design that was visually interesting because there was little information to show. For this reason, I once again found myself adding in unnecessary elements to fill up the space although I wanted to prioritize the user. I experimented with different content and color combinations, trying to find the compromise between design and usability. The more I worked with it, the more I was able to parse down the design to the bare bones. It became easier to differentiate useful information from fillers. The final product is a streamlined design with just a few summary statistics. It also offers great flexibility to include more information in the future.

Final design: Subtext beneath the buttons removed and the accounts created/accounts updated information is placed in its own container and shifted down to add visual interest. (Large preview)

Import process: The import progress page was created after the design for the import page was finalized. The biggest design challenge here was deciding how to display the in-progress import sync. I tried different solutions from pop-ups and overlays but ultimately settled with showing the progress in the sidebar. This way, users can still resolve any errors and see the historical record of their account data while an import is in progress. To prevent any interruptions to the import, the ‘Sync data’ and ‘Back to Badger’ buttons are disabled so users can’t leave the page.

Sync data and Back to Badger buttons disabled to prevent users from interrupting the sync and going back to the application. (Large preview)

With the designs done, I moved onto HTML and CSS.

Beginning to code my design. (Large preview) Chapter 3: HTML/CSS

This project was my first experience with any type of coding. Although I had tried to learn HTML and CSS before, I had never reached any level of proficiency. And what better way to start than with a mockup of one's own design?

Understanding the logic of organizing an HTML document reminded me of organizing the Sketch document with symbols and overrides. However, the similarities ended there. Coding felt like a very alien thing that I was consistently trying to wrap my head around. As my mentor would say, “You’re flexing very different muscles in programming than you are in design.” With the final product in hand now, I’m fully convinced that learning to code is the coolest thing I’ve learned to do since being potty trained.

The first challenge, after setting up a document and understanding the basics, was working with Flexbox. The design I had created involved two columns side by side. The right portion was meant to scroll while the left remained static. Flexbox seemed like a clean solution for this purpose, assuming I could get it to work.

Implementing Flexbox consisted of a lot of trial and error and blind copying of code while I scrambled through various websites, reading tutorials and inspecting code. With guidance from my mentor through this whole process, we eventually got it to work. I will never forget the moment when I finally understood that by using flex-direction: column I would get all of the elements into a single column, and flex-direction: row helped placed them in one row.

It makes so much sense now, although my initial understanding of it was the exact opposite (I thought flex-direction: column would put elements in columns next to each other). Surprisingly, I didn’t even come to this realization until after the code was working. I was reviewing my code and realized I didn’t understand it at all. What tipped me off? In my CSS, I had coded flex-direction: row into the class I named column. This scenario was pretty indicative of how the rest of my first coding experience went. My mental model was rarely aligned with the logic of the code, and they often clashed and went separate ways. When this happened, I had to go back, find my misconceptions, and correct the code.

After setting up Flexbox, I needed to figure out how to get the left column to stay fixed while the right portion scrolled. Turns out this couldn’t be achieved with a single line of code as I had hoped. But working through this helped me understand the parent-child relationship that aided me immensely with the rest of the process.

Vertical timeline with calendar icons. (Large preview)

Coding the vertical timeline and the dial was also a process. The timeline was simpler than I had originally anticipated. I was able to create a thin rectangle, set an inner shadow and a gradient filling to it, and assign it to the width of each activity log.

The dial was tricky. I tried implementing it with pure CSS with very little success. There were a few times I considered changing the design for something simpler (like a progress bar) but I’m quite happy I stuck with it.

Original and final dial designs. (Large preview)

A major struggle was getting outside progress dial to overlap the background circle along the border. This was where I changed the design a little bit — instead of having the unloaded portion of the progress dial cut out, it overlaps all around. It was a compromise between my design and code that I was initially unwilling to make. As it turns out, however, I was satisfied with the final result and once I realized this, I was happy to make that compromise. The final dial was implemented via JavaScript.

There was a moment in my coding process where I threw every line of code I’d ever written into every class to try to make it work. To make up for this lack of hindsight, I needed to spend quite a while going through and inspecting all the elements to remove useless code. I felt like a landlord kicking out the tenants who weren’t paying rent. It was most definitely a lesson learned in maintaining a level of housekeeping and being judicious and thoughtful with code.

The majority of the experience felt like blind traversing and retrospective learning. However, nothing was more satisfying than seeing the finished product. Going through the process made me interact with my work in a way I had never done before and gave me insight into how design is implemented. In all of my expectations for the internship, I never anticipated being able to code and create one of my own designs. Even after being told I would be able to do so on my first day, I didn’t believe it until after seeing this page completed.

Chapter 4: Working With Baby Badgers

As part of the process integrating Badger users with their CRM accounts, we needed our users to sign into their CRM — requiring us to redirect them out of badger to the native CRM website. To prevent a sudden, jarring switch from one website to another, I needed to design intermediate loading pages.

One of the first mockups of a sample static redirection page. It was simple and fulfilled its purpose but did little else. (Large preview)

I started out with your run-of-the-mill static redirection page. They were simple and definitely fulfilled their purpose, but we weren’t quite happy with them.

The challenge was to create something simple and interesting that informed the user they were leaving our website in just a few seconds it was visible. The design would need to introduce itself, explain why it was there, and leave before anyone got tired of looking at it. It was essentially an exercise in speed dating. With that in mind, I decided to try animations — specifically that of a cheeky little badger, inspired by the existing logo.

The evolution of “baby badger”. (Large preview)

Using the badger logo as a starting reference point, I created different badger characters in Adobe Illustrator. The original logo felt a little too severe for a loading animation, so I opted for something a little cuter. I kept the red chest and facial features from the original logo for consistency and worked away at creating a body and head around these elements. The head and stripes took a while to massage into shapes that I was happy with. The body took the form a little easier, but it took a little longer to find the right proportion between the size of the head and the body. Once I nailed that down, I was ready to move onto animating.

My attempt at stop animation. (Large preview)

My first instinct was to try a stop-motion animation. I figured it was going to be great — a lá Wallace and Gromit. But after the first attempt and then the second, and all the ensuing ones, it became clear that watching that show as a child had not fully equipped me with the skills required to do a stop-motion animation.

I just wasn't able to achieve the smoothness I wanted, and there were small inconsistencies that felt too jarring for a very short loading animation. Animation typically runs at 23 frames per second, and my badger animation only had about 15 frames per second. I considered adding more frames, but upon suggestion from my mentor, decided to try character animation instead.

This was the first time I had animated anything that was more than 5 moving parts and there was definitely a learning curve to understanding how to animate a two-dimensional character in a visually satisfying way. I needed to animate the individual elements to move by themselves independent of the whole in order to make the motion believable. As I worked on the animation, the layers I imported became increasingly granular. The head went from being one layer to five as I learned the behavior of the program and how to make the badger move.

I anchored each limb of the body and set each body part as a child to the parent layer of the body. I set the anchor points accordingly at the top of the thighs and shoulders to make sure they moved appropriately and then, using rotations and easing, simulated the movement of the body parts. The head was a tad bit tricky and required some vertical movement independent of the body. To make the jump seem more realistic, I wanted the head to hang in space a little before being pushed up by the rest of the body, and to come down just slightly after the rest of him. I also adjusted the angle I tried to make him seems as if he were leading with his nose, pointing up during the jump, and straightforward while he ran.

The overly anthropomorphic feet were abandoned from the original designs. They were one of the last changes made to baby badger. I hadn't considered how odd human toes looked like on a badger.

The animation featured on the page redirecting the user back to badger displayed the baby badger running back to badger with a knapsack full of information from the CRM.

Animation of baby badger running back to the badger application.

And finally: the confused badger. This was done for the last page I needed to create: an error page notifying the user of unexpected complications in the integration process. And what better way to do that then a sympathetic, confused badger?

Design exploration of the baby badger face. (Large preview)

The tricky part here was combining the side profile of the existing cartoon badger and the logo to create a front-facing head shape. Before beginning this project, I had never once seen a real live badger. Needless to say, Badger has found its way into my google image searches this month. I was surprised to see how flat the head of a badger actually is. In my first few designs, I tried to mimic this but wasn’t satisfied with the result. I worked with the shape some more, adjusting the placement of the nose, the stripes, and the ears to achieve the final result:

Swirly eyes inspired by the possum from the movie Fantastic Mister Fox.

This animation process has forced me to take my preexisting knowledge to a higher level. I needed to push myself beyond what I knew rather than limiting myself with what I thought I could do. I originally started with the stop-motion animation because I didn’t trust myself to do character animation. By giving myself the chance to try something new and different, I was able to achieve something that exceeded my own expectations.

Designs expanded from the original baby badger to be printed and used around the office and on marketing material. (Large preview) Conclusion

The three months I spent at my internship were incredibly gratifying. Every single day was about learning and trying something new. There were challenges to everything I did — even with tasks I was more familiar with such as design. Every time I created something, I was very insecure and apprehensive about how it would be received. There was a lot of self-doubt and lots of discarded ideas.

For that reason, it was incredible to be part of a team and to have a mentor to lead me in the right direction. Being told to try something else was often the only encouragement I needed to try something else and achieve something bigger and better. I like to picture myself as a rodent in a whack-a-mole game, being hit on the head over and over but always popping up again and again. Now the struggles and challenges have come to an end, I only want to do it all over again.

I appreciate what I’ve learned and how I was pushed to go beyond what I thought I could do. It’s crazy to see how far I’ve come in a few months. My understanding of being a UX designer has grown immensely, from figuring out the features, to hammering out the design, and then writing front-end code to implement it. This internship has taught me how much more I have to learn and has motivated me to keep working. I’ve come to understand that what I can do should never be limited by what I know how to do.

(mb, ra, yk, il)
Categories: Around The Web

Building A PWA Using Angular 6

Smashing Magazine - Thu, 09/20/2018 - 7:35am
Building A PWA Using Angular 6 Building A PWA Using Angular 6 Ahmed Bouchefra 2018-09-20T13:35:23+02:00 2018-09-24T12:10:20+00:00

In this tutorial, we’ll be using the latest Angular 6 to build a PWA by implementing the core tenets that make a PWA. We’ll start by creating a front-end web application that consumes a JSON API. For this matter, we’ll be using the Angular HttpClient module to send HTTP requests to a statically JSON API generated from the Simplified JavaScript Jargon GitHub repository. We’ll also use Material Design for building the UI via the Angular Material package.

Next, we’ll use the “Audits” panel (Lighthouse) from Chrome DevTools to analyze our web application against the core tenets of PWAs. Finally, we’ll explain and add the PWA features to our web application according to the “Progressive Web App” section in the Lighthouse report.

Before we start implementing our PWA, let’s first introduce PWAs and Lighthouse.

Recommended reading: Native And PWA: Choices, Not Challengers!

What’s A PWA?

A Progressive Web App or PWA is a web application that has a set of capabilities (similar to native apps) which provide an app-like experience to users. PWAs need to meet a set of essential requirements that we’ll see next. PWAs are similar to native apps but are deployed and accessible from web servers via URLs, so we don’t need to go through app stores.

A PWA needs to be:

  • Progressive
    Work for every user, regardless of browser choice, because they are built with progressive enhancement as a core tenet.
  • Responsive
    Fit any form factor, desktop, mobile, tablet, or whatever is next.
  • Connectivity independent
    Enhanced with service workers to work offline or on low-quality networks.
  • App-like
    Use the app-shell model to provide app-style navigation and interactions.
  • Fresh
    Always up-to-date thanks to the service worker update process.
  • Safe
    Served via HTTPS to prevent snooping and ensure content has not been tampered with.
  • Discoverable
    Are identifiable as “applications” thanks to W3C manifests and service worker registration scope allowing search engines to find them.
  • Re-engageable
    Make re-engagement easy through features like push notifications.
  • Installable
    Allow users to “keep” apps they find most useful on their home screen without the hassle of an app store.
  • Linkable
    Easily share via URL and not require complex installation.

Getting workflow just right ain’t an easy task. So are proper estimates. Or alignment among different departments. That’s why we’ve set up “this-is-how-I-work”-sessions — with smart cookies sharing what works well for them. A part of the Smashing Membership, of course.

Explore Smashing Membership ↬ Introducing Lighthouse

Lighthouse is an open-source auditing tool created by Google which can be used to audit websites and applications for accessibility performance, SEO, best practices and PWA features.

You can access Lighthouse from the Audit tab in Chrome DevTools as a module in Node.js or as a CLI tool. You can use Lighthouse by providing an URL and then running the audits which will provide you with a report containing the auditing results which are basically suggestions on how you can improve your web application.

Installing Angular CLI v6 And Generating A Project

In this section, we’ll install the latest version of Angular CLI then we’ll use it to create a new Angular 6 project.

Angular CLI requires Node.js >= 8.9+ so first make sure you have the required version installed by running the following command:

$ node -v Checking Node version. (Large preview)

In case you don’t have Node.js installed, you can simply head on to the official Node download page and grab the Node binaries for your system.

Now, you can go ahead and install the latest version of Angular CLI by running:

$ npm install -g @angular/cli

Note: Depending on your npm configuration, you may need to add _sudo_ to install packages globally.

You can generate your Angular 6 project by running the following command in your terminal:

$ ng new pwademo

This will create a project with a structure that looks like:

Angular project structure. (Large preview)

Most work that’s done will be inside the src/ folder that contains the source code of the application.

Creating The Angular Application

After generating a project, we’ll build a web application that consumes a JSON API and displays the items on the home page. We’ll use the HttpClient service for sending HTTP requests and Angular Material for building the UI.

Adding Angular Material

Thanks to Angular CLI v6 and the new ng add command, adding Angular Material to your project is only one command away. You just need to run the following command from your terminal:

$ cd pwademo $ ng add @angular/material Adding Angular Material. (Large preview)

You can see from the screenshot that the command installs the required package from npm and update a bunch of files for setting up Angular Material in your project which previously needed manual updates.

Setting Up HttpClient And Consuming The JSON API

Now, let’s setup the Angular project to use HttpClient for sending HTTP requests. First, you need to import the HttpClientModule module in the main application module in the src/app/app.module.ts file:

/*...*/ import { HttpClientModule } from '@angular/common/http'; @NgModule({ declarations: [ AppComponent ], imports: [ /*...*/ HttpClientModule ], providers: [], bootstrap: [AppComponent] }) export class AppModule { }

That’s it. We can now inject and use HttpClient in any component or service that belongs to the main module.

For demo purposes, we’ll consume a statically generated JSON API from the Simplified JavaScript Jargon GitHub repository. If you are consuming any other resource, make sure you have CORS enabled so the browser doesn’t disallow reading the remote resource due to the Same Origin Policy.

Let’s create a service that interfaces with the API. Inside your project folder, run:

$ ng g service api

This will create a service called ApiService in the src/app/api.service.ts file.

Now open the src/app/api.service.ts file and update it to reflect the following changes:

import { Injectable } from '@angular/core'; import { HttpClient } from '@angular/common/http'; import { Observable } from 'rxjs'; export interface Item{ name: string; description: string; url: string; html: string; markdown: string; } @Injectable({ providedIn: 'root' }) export class ApiService { private dataURL: string = "https://www.techiediaries.com/api/data.json"; constructor(private httpClient: HttpClient) {} fetch(): Observable<Item[]>{ return <Observable<Item[]>this.httpClient.get(this.dataURL); } }

We first imported the HttpClient and Observable classes then injected the HttpClient in the constructor as httpClient and added a fetch() method which calls the get() method of HttpClient (for sending an HTTP GET request to our JSON endpoint) and returns an Observable that we can subscribe to later.

We also declared an Item interface which represents a single item of the returned JSON data.

Next import this service from the application component. Open the src/app/app.component.ts file and add:

import { Component, OnInit } from '@angular/core'; import { ApiService } from './api.service'; import { Item } from './api.service'; @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.css'] }) export class AppComponent implements OnInit{ title = 'pwademo'; items: Array<Item>; constructor(private apiService: ApiService){ } ngOnInit(){ this.fetchData(); } fetchData(){ this.apiService.fetch().subscribe((data: Array<Item>)=>{ console.log(data); this.items = data; }, (err)=>{ console.log(err); }); } }

We import the ApiService that we created before and we inject it as apiService, we also import the Item class which represents a single item of our JSON data and we declare the items variable of type Array<Item> which will hold the fetched items.

Next, we add a fetchData() method which calls our fetch() method that we defined in the ApiService which returns an Observable. We simply subscribe to this observable in order to send a GET request to our JSON endpoint and get the response data that we finally assign to the items array.

We call the fetchData() method in the ngOnInit() life-cycle event so it will be called once the AppComponent component is initialized.

Adding The Application UI

Our application UI will consist of a navigation bar and the skeleton of the page which will be created with Angular Material.

Before using an Angular Material component, you’ll need to import its module. Each Material component belongs to its own module.

Open the src/app/app.module.ts file and add the following imports:

/*...*/ import { MatToolbarModule } from '@angular/material/toolbar'; import { MatCardModule } from '@angular/material/card'; import { MatButtonModule } from '@angular/material/button'; @NgModule({ declarations: [ AppComponent ], imports: [ /*...*/ MatToolbarModule, MatCardModule, MatButtonModule ], providers: [], bootstrap: [AppComponent] }) export class AppModule { }

We import modules for toolbar, card and button components and we add them to the imports array of the AppModule.

Next, open the src/app/app.component.html file, delete what’s in there and add:

<mat-toolbar color="primary"> <mat-toolbar-row> <span>JS-jargon</span> </mat-toolbar-row> </mat-toolbar> <main> <mat-card *ngFor="let item of items"> <mat-card-header> <mat-card-title>{{item.name}}</mat-card-title> </mat-card-header> <mat-card-content> {{item.description}} </mat-card-content> <mat-card-actions> <a mat-raised-button href="{{item.url}}" color="primary">More</a> </mat-card-actions> </mat-card> </main>

We use Material components to create the UI. The <mat-toolbar> component is used to create a Material toolbar and the <mat-card> component is used to create a Material card etc.

We iterate over the items array which gets populated by the fetchData() method when the component is initialized, and display items as Material cards. Each card contains the name, description and a link for more information (The link is styled as a Material button using the mat-raised-button directive).

This is a screenshot of the application:

Demo Application. (Large preview) Building The Application For Production

Typically, when checking your application for PWA features you should first build it for production because most PWA features are not added in development. For example, you don’t want to have service workers and caching enabled in development since you will periodically need to update the files.

Let’s build the application for production using the following command:

$ ng build --prod

The production build will be available from the dist/pwademo folder. We can use a tool like http-server to serve it.

First, install http-server using the following command:

$ npm i -g http-server

You can then run it using the following command:

$ cd dist/pwademo $ http-server -o

The -o option will automatically open the default browser in your system and navigate to the http://127.0.0.1:8080/ address where our web application is available.

Analyzing The Application Using Lighthouse

Let’s now analyze our application using Lighthouse. First, launch Chrome and visit our application address http://127.0.0.1:8080/.

Next, open Developer Tools or press Ctrl + Shift + I and click on the Audit panel.

Perform an audit. (Large preview)

You preferably need to set the Emulation to Mobile instead of Desktop to emulate a mobile environment. Next, click on Perform an audit… blue button. You’ll have a dialog opened in which you need to choose the types of the audits you want to perform against your web application. Un-check all types but Progressive Web App and click the Run audit button.

Progressive Web App Audits. (Large preview)

Wait for the Lighthouse to generate the report. This is a screenshot of the result at this stage:

Initial Report. (Large preview)

Lighthouse performs a series of checks which validate the aspects of a Progressive Web App specified by the PWA Checklist. We get an initial score of 36⁄100 that’s because we have some audits passed.

Our application has 7 failed audits mainly related to Service Workers, Progressive Enhancement, HTTPS and Web App Manifest which are the core aspects of a PWA.

Registering A Service Worker

The first two failed audits (“Does not register a service worker” and “Does not respond with a 200 when offline”) are related to Service Workers and caching. So what’s a service worker?

A service worker is a feature that’s available on modern browsers which can be used as a network proxy that lets your application intercept network requests to cache assets and data. This could be used for implementing PWA features such as offline support and Push notifications etc.

To pass these audits we simply need to register a service worker and use it to cache files locally. When offline, the SW should return the locally cached version of the file. We’ll see a bit later how to add that with one CLI command.

Recommended reading: Making A Service Worker: A Case Study

Progressive Enhancement

The third failed audit (“Does not provide fallback content when JavaScript is not available”) is related to Progressive Enhancement which is an essential aspect of a PWA and It simply refers to the capability of PWAs to run on different browsers but provide advanced features if they’re available. One simple example of PE is the use of the <noscript> HTML tag that informs users of the need to enable JavaScript to run the application in case It’s not enabled:

<noscript> Please enable JavaScript to run this application. </noscript> HTTPS

The fourth failed audit (“Does not redirect HTTP traffic to HTTPS”) is related to HTTPS which is also a core aspect of PWAs (service workers can be only served from secure origins, except for localhost). The “Uses HTTPS” audit itself is considered as passed by Lighthouse since we’re auditing localhost but once you use an actual host you need a SSL certificate. You can get a free SSL certificate from different services such as Let’s Encrypt, Cloudflare, Firebase or Netlify etc.

The Web App Manifest

The three failed audits (“User will not be prompted to Install the Web App”, “Is not configured for a custom Splash Screen” and “Address bar does not match brand colors”) are related to a missing Web App Manifest which is a file in JSON format that provides the name, description, icons and other information required by a PWA. It lets users install the web app on the home screen just like native apps without going through an app store.

You need to provide a web app manifest and reference it from the index.html file using a <link> tag with rel property set to manifest. We’ll see next how we can do that automatically with one CLI command.

Implementing PWA Features

Angular CLI v6 allows you to quickly add PWA features to an existing Angular application. You can turn your application into a PWA by simply running the following command in your terminal from the root of the project:

$ ng add @angular/pwa

The command automatically adds PWA features to our Angular application, such as:

  • A manifest.json file,
  • Different sizes of icons in the src/assets/icons folder,
  • The ngsw-worker.js service worker.

Open the dist/ folder which contains the production build. You’ll find various files but let’s concentrate on the files related to PWA features that we mentioned above:

A manifest.json file was added with the following content:

{ "name": "pwademo", "short_name": "pwademo", "theme_color": "#1976d2", "background_color": "#fafafa", "display": "standalone", "scope": "/", "start_url": "/", "icons": [ { "src": "assets/icons/icon-72x72.png", "sizes": "72x72", "type": "image/png" }, { "src": "assets/icons/icon-96x96.png", "sizes": "96x96", "type": "image/png" }, { "src": "assets/icons/icon-128x128.png", "sizes": "128x128", "type": "image/png" }, { "src": "assets/icons/icon-144x144.png", "sizes": "144x144", "type": "image/png" }, { "src": "assets/icons/icon-152x152.png", "sizes": "152x152", "type": "image/png" }, { "src": "assets/icons/icon-192x192.png", "sizes": "192x192", "type": "image/png" }, { "src": "assets/icons/icon-384x384.png", "sizes": "384x384", "type": "image/png" }, { "src": "assets/icons/icon-512x512.png", "sizes": "512x512", "type": "image/png" } ] }

As you can see, the added manifest.json file has all the information required by a PWA such as the name, description and start_url etc.

Angular project structure. (Large preview)

The manifest.json file, links to icons with different sizes, that were also added automatically in the assets/icons folder. You will, of course, need to change those icons with your own once you are ready to build the final version of your PWA.

Angular project structure. (Large preview)

In the index.html file, the manifest.json file is referenced using:

<link rel="manifest" href="manifest.json">

The ngsw-worker.js file, was also automatically added, which contains the service worker. The code to install this service worker is automatically inserted in the src/app/app.module.ts file:

... import { ServiceWorkerModule } from '@angular/service-worker'; @NgModule({ declarations: [ AppComponent ], imports: [ ... ServiceWorkerModule.register('/ngsw-worker.js', { enabled: environment.production }) ],

The @angular/service-worker is installed by the ng add command and added as a dependency to pwademo/package.json:

"dependencies": { ... "@angular/service-worker": "^6.1.0" }

The service worker build support is also enabled in the CLI. In the angular.json file a "serviceWorker": true configuration option is added.

In the index.html file a meta tag for theme-color with a value of #1976d2 is added (It also corresponds to the theme_color value in the manifest.json file):

<meta name="theme-color" content="#1976d2">

The theme color tells the browser what color to tint UI elements such as the address bar.

Adding the theme color to both the index.html and manifest.json files fixes the Address Bar Matches Brand Colors audit.

The Service Worker Configuration File

Another file src/ngsw-config.json is added to the project but It’s not a required file for PWAs. It’s a configuration file which allows you to specify which files and data URLs the Angular service worker should cache and how it should update the cached files and data. You can find all details about this file from the official docs.

Note: As of this writing, with the latest 6.1.3 previous ng add @angular/pwa command will fail with this error: Path “/ngsw-config.json” already exists so for now the solution is to downgrade @angular/cli and @angular/pwa to version 6.0.8.

Simply run the following commands in your project:

$ npm i @angular/cli@6.0.8 $ ng i @angular/pwa@6.0.8 $ ng add @angular/pwa

Now let’s re-run the audits against our local PWA hosted locally. This is the new PWA score:

PWA Report. (Large preview)

The Angular CLI doesn’t automatically add the JavaScript fallback code we mentioned in the Progressive Enhancement section so open the src/index.html file and add it:

<noscript> Please enable JavaScript to run this application. </noscript>

Next, rebuild your application and re-run the audits. This is the result now:

PWA Report. (Large preview)

We have only one failed audit which is related to HTTPS redirect. We need to host the application and configure HTTP to HTTPS redirect.

Let’s now run the audits against a hosted and secured version of our PWA.

PWA Final Report. (Large preview)

We get a score of 100⁄100 which means we’ve successfully implemented all core tenets of PWAs.

You can get the final code of this demo PWA from this GitHub repository.

Conclusion

In this tutorial, we’ve built a simple Angular application and have turned it into a PWA using Angular CLI. We used Google’s Lighthouse to audit our application for PWA features and explained various core tenets of PWAs such as Service Workers for adding offline support and push notifications. The Web Manifest file for enabling add-to-home-screen and splash screen features, Progressive Enhancement as well as HTTPS .

You may also need to manually check for other items highlighted (under the “Additional items to manually check” section) but not automatically checked by Lighthouse. These checks are required by the baseline PWA Checklist by Google. They do not affect the PWA score but it’s important that you verify them manually. For example, you need to make sure your site works cross-browser and that each page has a URL which is important for the purpose of shareability on social media.

Since PWAs are also about other aspects such as better perceived performance and accessibility, you can also use Lighthouse for auditing your PWA (or any general website) for these aspects and improve it as needed.

(rb, ra, yk, il)
Categories: Around The Web

Visual Studio Live Share Can Do That?

Smashing Magazine - Wed, 09/19/2018 - 7:30am
Visual Studio Live Share Can Do That? Visual Studio Live Share Can Do That? Burke Holland 2018-09-19T13:30:17+02:00 2018-09-24T12:10:20+00:00

A few months ago, Microsoft released its free Visual Studio (VS) Live Share service. VS Live Share is Google Docs level collaboration for code. Multiple developers can collaborate on the same file at the same time without ever leaving their own editor.

After the release of Live Share, I realized that many of us have resigned ourselves to being isolated in our code and we’re not even aware that there are better ways to work with a service like VS Live Share. This is partly because we are stuck in old habits and partly because we just aren’t aware of what all VS Live Share can do. That last part I can help with!

In this article, we’ll go over the features and best practices for VS Live Share that make developer collaboration as easy as being an “Anonymous Hippo.”

Google Docs has an interesting way of handling anonymous participants (Large preview) Share Your Code

Live Share comes as an extension for both Visual Studio and Visual Studio Code (VS Code). In this article, we’re going to focus on VS Code.

(Large preview)

You can also install it via the VS Live Share Extension Pack, which includes the following extensions, all of which we are going to cover in this article…

  • VS Live Share
  • VS Live Share Audio
  • Slack Chat extension

Front-end is messy and complicated these days. That's why we publish articles, printed books and webinars with useful techniques to improve your work. Even better: Smashing Membership with a growing selection of front-end & UX goodies. So you get your work done, better and faster.

Explore Smashing Membership ↬

Once the extension is installed, you will need to log in to the VS Live Share service. You can do that by opening the Command Palette Ctrl/Cmd + Shift + P and select “Sign In With Browser”. If you don’t log in and you try and start a new sharing session, you will be prompted to log in at that time.

Use the VS Code Command Palette to start a new Live Share session (Large preview)

There are several ways to kick off a VS Live Share session. You can do it from the Command Palette, you can click that “Share” button in the bottom toolbar, or you can use the VS Live Share explorer view in the Sidebar.

There are a myriad of ways to start a new VS Live Share session (Large preview)

A link is copied to your clipboard. You can then send that link to others, and they can join your Live Share session — provided they are using VS Code as well. Which, aren’t we all?

Now you can collaborate just like you were working on a regular old Word document:

The other person can not only see your code, but they can edit it, save it, execute it and even debug it. For you, they show up as a cursor with a name on it. You show up in their editor the same way.

The VS Live Share Explorer

The VS Live Share explorer shows up as a new icon in the Action Bar — which is that bar of icons on the far right of my screen (the far left of yours for default Action Bar placement). This is a sort of “ground zero” for everything VS Live Share. From here, you can start sessions, end them, share terminals, servers, and see who is connected.

The VS Live Share Explorer is a heads-up view of all things Live Share (Large preview)

It’s a good idea to bind a keyboard shortcut to this VS Live Share Explorer view so that you can quickly toggle between that and your files. You can do this by pressing Ctrl/Cmd + K (or Ctrl/Cmd + S) and then searching for “Show Live Share”. I bound mine to Ctrl/Cmd + L, which doesn’t seem to be bound to anything else. I find this shortcut to be intuitive (L for Live Share) and easy to hit on the keyboard.

You can create a binding for the VS Live Share Explorer viewlet (Large preview) Share Code Read-Only

When you start a new sharing session, you will be notified thusly and asked if you would like to share your workspace read-only. If you select read-only, people will be able to see your code and follow your movements, but they will not be able to interact.

Sharing sessions are read-write by default, but you can make them read-only (Large preview)

This mode is useful when you are sharing with someone that you don’t necessarily trust — maybe a vendor, partner or an estranged ex.

It’s also particularly useful for instructors. Note that at the time of this writing, VS Live Share is locked to 5 concurrent users. Since you probably are going to want more than that in read-only mode, especially if you’re teaching a group, you can up the limit to 30 by adding the following line to your User Settings file: Ctrl/Cmd + ,.

"liveshare.features": "experimental" Change The Default Join Behavior

Anyone with the link can join your Live Share session. When they join, you’ll see a pop-up letting you know. Likewise, when they disconnect, you get notified. This is the default behavior for VS Live Share.

VS Code will alert you whenever someone joins your session (Large preview)

It’s a good idea to change this so that you have to manually approve someone before they can join your session. This is to protect you in the case where you go to lunch and forget to disconnect your session. Your co-workers can’t log back in, change one letter in your database connection string and then laugh while you spend the next four hours trying to figure out how your life has gone so horribly wrong.

To enable this, add the following line to your User Settings file Ctrl/Cmd + ,.

"liveshare.guestApprovalRequired": true

Now you’ll be prompted when someone wants to join. If you block someone, they are blocked for the duration of the session. If they try to join again, you won’t be notified and they will be unceremoniously rejected by VS Live Share.

Go and enjoy your lunch. Your computer is safe.

Focus Followers

By default, anyone who joins your Live Share session is “following” you. That means that their editor will load up whatever file you are in and scroll whenever you scroll. Even if you switch files, participants will see exactly what you see.

The second that a person makes changes to a file, they are no longer following you. So if you are both working on a file together, and then you go to a different file, they won’t automatically go with you. That can lead to a lot of confusion with you talking about code in the file you’re in while the other person is looking at something entirely different.

Besides just telling each other where you are (which works, btw), there is a handy command called “Focus Participants” that is in the Command Palette Ctrl/Cmd + Shift + P.

Access the “focus” command from the VS Code Command Palette (Large preview)

You can also access it as an icon in the VS Live Share Explorer view.

Send a follow request by clicking the follow icon in the VS Live Share Explorer viewlet (Large preview)

This will focus your participants on the next thing you click on or scroll to. By default, VS Live Share focus requests are accepted implicitly. If you don’t want people to be able to focus you, you can add the following line to your User Settings file.

"liveshare.focusBehavior": "prompt"

Also note that you can follow participants. If you click on their name in the VS Live Share Explorer view, you will begin to follow them.

Because following is turned off as soon as the other person begins editing code, it can be tough to know exactly when people are following you and when they aren’t. One place you can look is in the VS Live Share Explorer view. It will tell you the file that a person is in, but not whether or not they are following you.

A good practice is to just remember that focus is always changing so people may or may not see what you see at any given time.

Debug As A Team

Participants can share any debug sessions that you run. If you start a debug session, they will get the exact same experience that you do. If it breaks on your side, it breaks on theirs, and they get the full debug view into all of your code.

They can step in, out, over, add watches, evaluate in the Debug Console; any debugging that you can do, they can do too, and they can control it.

Debugging can also be launched by participants. Be default, though, VS Code does not allow your debugger to be started remotely. To enable this, add the following line to your User Settings file Ctrl/Cmd + ,:

"liveshare.allowGuestDebugControl": true Share Your Terminal

A lot of the work we do as developers isn’t in our code; it’s in the terminal. Some days it seems like I spend about as much time on my terminal as I do in my editor. This means that if you have an error on your terminal or need to type some command, it would be nice if your participants in VS Live Share can see your terminal in addition to your code.

VS Code has an integrated terminal, and you can share it with VS Live Share.

Access the “Share Terminal” command from the VS Code Command Palette (Large preview)

When you do this, you have the opportunity to share your terminal as read-only, or as read-write.

Always share your terminal read-only unless you absolutely have to share it with write access (Large preview)

By default, you should be sharing your terminal as read-only. When you share your terminal read-write, the user can execute arbitrary commands directly on your terminal. Let that sink in for a moment. That’s heavy.

It goes without saying that having remote write access to someone’s terminal comes with a lot of trust and responsibility. You should only ever share your terminal read-write with people that you trust implicitly. Estranged ex’s are probably off the table.

Sharing your terminal read-only safely allows the person on the other end of the line to see what you are typing and your terminal output in real time, but restricts them from typing anything into that terminal.

Should you find yourself in a scenario where it would be quicker for the other person to just get at your terminal instead of trying to walk you through some wacky command with a ton of flags, you can share your terminal read-write. In this mode, the other person has full remote access to your terminal. Choose your friends wisely.

Share Your localhost

In the video above, the terminal command ends with a link to a site running on http://localhost:8080. With VS Live Share, you can share that localhost so that the other person can access it just like it was their own localhost.

If you are running a shared debug session, when the participant hits that localhost URL on their end, it will break for both of you if a breakpoint is hit. Even better, you can share any TCP process. That means that you can share something like a database or a Redis cache. For instance, you could share your local Mongo DB server. Seriously! This means no more changing config files or trying to get a shared database up. Just share the port for your local Mongo DB instance.

Share The Right Files The Right Way

Sometimes you don’t want collaborators to see certain files. There are likely private keys and passwords in your project that are not checked into source control and not suitable for public viewing. In this case, you would want to hide those files from anyone participating in your Live Share session.

By default, VS Live Share will hide any file that is specified in your .gitignore. If there is a file that you want to hide, just add it to your .gitignore. Note though, that this only hides the file in the project view. If you are in a shared debugging session and you step into a file that is in the .gitignore, it is still loaded up in the editor and your collaborators will be able to see it.

You can get more fine-grained control over how you share files by creating a .vsls.json file.

For instance, if you wanted to make sure that any files that are in the .gitignore are never visible, even during debugging, you can set the gitignore property to exclude.

{ "$schema": "http://json.schemastore.org/vsls", "gitignore":"exclude" }

Likewise, you could show everything in your .gitignore and control file visibilty directly from the .vsls.json file. To do that, set the gitignore to none and then use the excludeFiles and hideFiles properties. Remember — exclude means never visible, and hide means “not visible in the file explorer.”

{ "$schema": "http://json.schemastore.org/vsls", "gitignore":"none", "excludeFiles":[ "*.env" ], "hideFiles": [ "dist" ] } Sharing And Extensions

Part of the appeal of VS Code to a lot of developers is the massive extensions marketplace. Most people will have more than a few installed. It’s important to understand how extensions will work, or not work, in the context of VS Live Share.

VS Live Share will synchronize anything that is specific to the context of the project you are sharing. For instance, if you have the Vetur extension installed because you are working with a Vue project, it will be shared across to any participants — regardless of whether or not they have it installed as well. The same is true for other context-specific things, like linters, formatters, debuggers, and language services.

VS Live Share does not synchronize extensions that are user specific. These would be things like themes, icons, keyboard bindings, and so on. As a general rule of thumb, VS Live Share shares your context, not your screen. You can consult the official docs article on this subject for a more in-depth explanation of what extensions you can expect to be shared.

Communicate While You Collaborate

One of the first things people do on their inaugural VS Live Share experience is to try to communicate by typing in code comments. This seems like the write (get it?) thing to do, but not really how VS Live Share was designed to be used.

VS Live Share is not meant to replace your chat client of choice. You likely already have a preferred chat mechanism, and VS Live Share assumes that you will continue to use that.

If you’re already using Slack, there is a VS Code extension called Slack Chat. This extension is still a tad early in its development, but it looks quite promising. It puts VS Code in split mode and embeds Slack on the right-hand side. Even better, you can start a Live Share session directly from the Slack chat.

The Slack Chat extension puts Slack inside of your editor (Large preview)

Another tool that looks quite interesting is called CodeStream.

CodeStream

While VS Live Share looks to improve collaboration from the editor, CodeStream is aiming to solve that same problem from a chat perspective.

The CodeStream extension allows you to chat directly within VS Code and those chats become part of your code history. You can highlight a chunk of code to discuss and it goes directly into the chat so there is context for your comments. These comments are then saved as part of your Git repo. They also show up in your code as little comment icons, and these comments will show up no matter which branch you are on.

When it comes to VS Live Share, CodeStream offers a complimentary set of features. You can start new sessions directly from the chat pane, as well as by clicking on an avatar. New sessions automatically create a corresponding chat channel that you can persist with the code, or dispose of when you are done.

If chatting isn’t enough to get the job done, and you need to collaborate like it’s 1999, help is just a phone call away.

VS Live Share Audio

While VS Live Share isn’t trying to reinvent chat, it does re-invent your telephone. Kind of.

With the VS Live Share Audio extension, you can call someone directly and do voice chat from within VS Code.

Make audio calls from VS Code using the VS Live Share Audio extension (Large preview)

The other person will then get a prompt to join your call.

VS Code will ask you if you want to join an audio call that is in process (Large preview)

You will see a speaker icon in the bottom status bar when you are connected to a call. You can click on that speaker to change your audio device, mute yourself, or disconnect from the call.

You have full control over audio settings when in a VS Live Share Audio call (Large preview)

The last tip I’ll give you is probably the most important, and it’s not a fancy feature or obscure setting you didn’t know existed.

Change Your Muscle Memory

We’ve got years of learned behavior when it comes to getting help or sharing our code. The state of developer collaboration tools has been so bad for so long that we are conditioned to paste code into Slack, start an awkward Skype calls that consist mostly of “tell me when you can see my screen”, or crowd around a monitor and point excessively, i.e. stock photo style.

(Large preview)

The most important thing you can do to get the most out of VS Live Share is to actually use VS Live Share. And it will have to be a “conscious” effort.

Your brain is good at patterns. You are constantly recognizing and classifying the world around you based on patterns you have identified, and you are so good at it, you don’t even realize you are doing it. You then develop default responses to these patterns. You form instincts. This is why you will default to the old ways of collaboration without even thinking about what you are doing. Before you know it you will be on a Skype call with someone sharing your screen — even if you have Live Share installed.

I’ve written a lot about VS Code and people will ask me from time to time how they can get more productive with their editor. I always say the same thing: the next time you reach for the mouse to do something, stop. Can you do that something with the keyboard instead? You probably can. Look up the shortcut and then make yourself use it. At first it’s going to be slower, but if you are willing to deliberately adopt a different behavior, you will be astonished at how fast your brain will default to the more productive way of doing something.

The same goes for Live Share. You will be on a call sharing your screen when it occurs to you that you could be using Live Share. At that moment, stop; click that “Share” button in the bottom of VS Code.

Yes, the person on the other end may not have the extension installed. Yes, it may take a moment to set it up. But if you work on establishing this behavior now, the next time you go to do this, it will “just work” and it won’t be long before you don’t even have to think about it, and at that point, you will finally have achieved that “Anonymous Hippo” level of collaboration.

More Resources (rb, ra, il)
Categories: Around The Web

Fixed Elements And Overlays In XD: Incredibly Easy And Fun Methods For Your Prototypes

Smashing Magazine - Tue, 09/18/2018 - 6:30am
Fixed Elements And Overlays In XD: Incredibly Easy And Fun Methods For Your Prototypes Fixed Elements And Overlays In XD: Incredibly Easy And Fun Methods For Your Prototypes Manuela Langella 2018-09-18T12:30:32+02:00 2018-09-24T12:10:20+00:00

(This article is kindly sponsored by Adobe.) A fixed element is an object you set to a fixed position on the artboard, allowing other items to scroll underneath. This way, you get a realistic simulation of scrolling on desktop and mobile. With the new overlay feature, you can simulate interactions such as lightbox effects and submenus.

How do famous brands use fixed elements and overlays? Well, let’s take a look at some examples to get some inspiration first.

From left to right: 1) McDonald’s mobile home 2) A submenu slides up when you click on the hamburger menu. This is an example of an overlay. 3) Netflix’s Italian mobile website home screen. 4) Netflix sets its call to action as a fixed element. When you scroll down, the button stays fixed to the bottom of the screen. 5) Adobe mobile home 6) By clicking on the menu symbol, a submenu comes out as an overlay. (Large preview)

In this tutorial, we will learn how to set a menu bar as a fixed element and how to apply an overlay transition in a prototype, to simulate a menu opening from the click of a button. Both examples will be done in a mobile template, so that we can see our simulation in action directly on our mobile device. I’ve also included an Illustrator file with icons, which you can use to set up your examples quickly.

Let’s get started.

Preparing The Mobile Template

Open Adobe Xd, and choose the “iPhone 6/7/8 Plus” template. Then, go to File → Save As and choose a name to save your file (mine is mobile.xd).

(Large preview)

Let’s create a restaurant app in which people can select what to order from a list of food.

We will create two home layouts. The first one will be a long page, which we will use to see how fixed navigation works. The second will have a full-screen image, and the user will be able to click and open a menu bar that overlays the home screen.

To get started, click on the artboard icon on the left side, and click to the right of your current artboard. This will create a second identical artboard, near the first one.

(Large preview)

Let’s begin to design our elements, starting with the navigation bar. Click on the Rectangle tool (R) and draw a shape 414 pixels wide and 48 pixels tall. Set its color as #DE4F4F.

(Large preview)

I’ve prepared some icons in Illustrator to use in our layout. Just open the Illustrator file I’ve provided, and drag and drop the icons in your library, as shown below:

Large preview

In doing so, your icons will be automatically uploaded to your Adobe XD library, too.

To learn more about how to use libraries in different apps, read my earlier article, in which I go over some examples of how to add icons and elements to a library (in Illustrator, for instance) and then access them by opening that library in other apps (XD, in this case).

Once you have added the icons, open your XD library. You should see the icons in place:

(Large preview)

Drag and drop the icons on your artboard, as shown below. Position them, and make sure they are all about 25 pixels wide.

(Large preview)

Because we need our icons to be white, we have to modify these. We can directly modify them in the library, as demonstrated in my previous tutorial. With that done, we’ll see them updated in XD directly, without having to drag them from the library again.

(Large preview)

Now that the icons we want are in place, let’s create a logo. Let’s call this app “Gusto”. We’ll simply use the Text tool to add it. (I’m using the Leckerli One font here, but feel free to use whichever you like.) Align the logo to the middle of the navigation bar by clicking “Align center (horizontally)” in the right sidebar.

(Large preview)

Group all of the navigation elements together, and call the group “Menu”. To do this, select all elements in the left panel, right-click and choose “Group”.

(Large preview) (Large preview)

Let’s add a beautiful hero image. I selected one from Pexels. Drag it on your artboard, and resize its height to 380 pixels.

(Large preview)

Now, click on Rectangle tool (R), and draw a rectangle the same size as the hero image, and place it on the image. Set a gradient for the rectangle’s color, using the values shown in the image below.

(Large preview)

(If you’d like more information about gradients, feel free to see my previous tutorial on how to apply them in XD.)

Insert some white text on the hero image and a circle for a button. Place a little circle with a number on the cart icon as well; we will need it later.

(Large preview)

Next, let’s increase the artboard’s height. We have to do that in order to insert new elements and to create the scrolling simulation.

After double-clicking on the artboard, set its height to 1265 pixels. Be sure that “Scrolling” is set to “Vertical” and that the “Viewport Height” is set to 736 pixels. A little blue marker will allow you to set the scrolling boundary towards the bottom of the artboard, as seen below:

(Large preview)

Let’s add in our content: Gusto’s mouthwatering menu. Click on the Rectangle tool (R) to create a rectangle for the picture that we will add.

(Large preview)

Drag and drop a picture directly into the box we just created; the image will automatically fit in it. Click on it once, and drag the little white circle from an angle inwards, in order to round all of the angles. Their values should be around 25, as shown in the picture below. Get rid of the border by unchecking the border value in the right sidebar.

Large preview

Click on the Text tool (T), and write a title on the right side of the image. I chose Lato as the font, at 14 pixels. Feel free to use another font, but maintain the 14-pixel size.

(Large preview)

Grab the Text tool (T) again, and write some lines for the description (Lato, 10 pixels) and for the price (Lato, 16 pixels).

(Large preview)

Take the Rectangle tool (R) and draw a rectangle of 100 by 30 pixels. Color it with the same orange we used on the button for the hero image; add the text “Add to Cart” with the Text tool (T); and add the cart icon from the library. All of these steps are covered in the short video below:

Finally, click on “Repeat Grid” to create a grid for this section. Once that’s done, we can change images and text easily, as shown in the video below:

If you want to learn more about how to create grids, follow my tutorial.

I used the following pictures from Pexels:

  • https://www.pexels.com/photo/close-up-of-food-247685/
  • https://www.pexels.com/photo/food-dinner-pasta-spaghetti-8500/
  • https://www.pexels.com/photo/selective-focus-photography-of-beef-steak-with-sauce-675951/
  • https://www.pexels.com/photo/food-plate-chocolate-dessert-132694/
  • https://www.pexels.com/photo/bread-food-sandwich-wood-62097/

Add some titles, descriptions and buttons.

(Large preview)

Finally, let’s add a rectangle for the footer, with the text “Gusto” in the center. Set the rectangle’s fill color to #211919.

(Large preview)

Yes! We’ve completed the first template design. Let’s set up our second template before we begin prototyping.

For our second mobile layout, just copy and paste the navigation and hero section from the first layout, and size the hero image to be full screen. Then, add a “Try Now” button to it.

In the short video below, I show you how to copy and paste elements into the second artboard, create a new button with the Rectangle tool (R) and write text on it with the Text tool (T).

(Large preview)

Excellent! Let’s move on and create our prototypes.

Setting Fixed Elements

We want to make the top navigation of our layout fixed, making it stick to its position as we scroll the artboard.

Click on your “Menu” group to select it, and select “Fixed Position” in the right sidebar.

(Large preview)

Important: In order for all elements to scroll under the menu, the menu should be on top of all other elements. Simply place the menu folder at the top, in the left sidebar.

(Large preview)

Now, to see your fixed navigation in action, simply click on the “Desktop Preview” button and try scrolling. You should see this:

Large preview

Tremendously simple, isn’t it?

Setting Overlay Elements

To see how overlays work in XD, we first need to create the elements that will be overlaid. When you click an item in the menu, what would you expect to happen? Exactly: A submenu should appear.

Let’s create three different submenus, like the ones in the image below, using the Rectangle tool (R). I chose a rectangle because the menu will overlay the screen, so it will cover not the whole artboard but just a part of it.

Follow the video below to see how I created the three overlay menus. You will see that I used the Rectangle tool (R), Line tool (L) and Text tool (T). We’re using rectangles to create the menu backgrounds because we need an object to overlay the screen. I’ve included the icons in the Adobe Illustrator file which you can directly download over here.

Below, you’ll see how I use “Repeat Grid” and how I modify elements inside of it.

Here is the final result:

(Large preview)

We will work on the second home layout at this point.

Set the visual mode to “Prototype”, selecting it from the top left of the screen.

(Large preview)

Next, double-click on the little hamburger menu icon, and drag and drop the little blue arrow onto the “Overlay 1” artboard. When the popup window appears, choose “Overlay” and “Slide right”. Then, click the “Desktop Preview” button to see it in action.

Large preview

Let’s do the same thing with the user icon and cart icon. Double-click on the user icon in Prototype mode, and drag and drop the little blue arrow onto the “Overlay 2” artboard. When the popup window appears, choose “Overlay” and “Slide left”. Then, click the “Desktop Preview” button to see it in action.

Large preview

Now, double-click on the cart icon in Prototype mode, and drag and drop the little blue arrow onto the “Overlay 3” artboard. When the popup windows appears, choose “Overlay” and “Slide left”. Click the “Desktop Preview” button again to see it work.

Large preview

We’re done! These great new features are super-easy to learn, and they’ll add a new level of interactivity simulation to your prototypes.

Quick tip: Want to preview the layout on your phone? Just upload your XD file to Creative Cloud, download the XD app for mobile, and open your document.

Here’s what we have learned in this tutorial:

  • set and create mobile layouts and elements,
  • set fixed elements,
  • use overlays to simulate a click-to-open submenu.

Where would you use fixed elements or overlays? Feel free to share your examples in the comments below!

This article is part of the UX design series sponsored by Adobe. Adobe XD 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.

(il, yk)
Categories: Around The Web

Flexbox: How Big Is That Flexible Box?

Smashing Magazine - Mon, 09/17/2018 - 7:30am
Flexbox: How Big Is That Flexible Box? Flexbox: How Big Is That Flexible Box? Rachel Andrew 2018-09-17T13:30:30+02:00 2018-09-24T12:10:20+00:00

This is the third part of my series on Flexbox. In the past two articles, we have looked at what happens when you create a flex container and explored alignment as it works in Flexbox. This time we are going to take a look at sizing. How do we control the size of our flex items, and what choices is the browser making when it controls the size?

Initial Display Of Flex Items

If I have a set of items, which have variable lengths of content inside, and set their parent to display: flex, the items will display as a row and line up at the start of that axis. In the example below my three items have a small amount of content and are able to display the content of each item as an unbroken line. There is space at the end of the flex container which the items do not grow into because the initial value of flex-grow is 0, do not grow.

The flex items have room to each be displayed on one line (Large preview)

If I add more text to these items, they eventually fill the container, and the text begins to wrap. The boxes are assigned a portion of the space in the container which corresponds to how much text is in each box — an item with a longer string of text is assigned more space. This means that we don’t end up with a tall skinny column with a lot of text when the next door item only contains a single word.

The space is distributed to give more space to a longer item (Large preview)

This behavior is likely to be familiar to you if you have ever used Flexbox, but perhaps you have wondered how the browser is working that sizing out, as if you look in multiple modern browsers you will see that they all do the same thing. This is down to the fact that detail such as this is worked out in the specification, making sure that anyone implementing Flexbox in a new browser or other user agent is aware of how this calculation is supposed to work. We can use the spec to find this information out for ourselves.

Meet SmashingConf New York 2018 (Oct 23–24), focused on real challenges and real front-end solutions in the real world. From progressive web apps, Webpack and HTTP/2 to serverless, Vue.js and Nuxt — all the way to inclusive design, branding and machine learning. With Sarah Drasner, Sara Soueidan and many other speakers.

Check all topics and speakers ↬ The CSS Intrinsic And Extrinsic Sizing Specification

You fairly quickly discover when looking at anything about sizing in the Flexbox specification, that a lot of the information you need is in another spec — CSS Intrisnic and Extrinsic Sizing. This is because the sizing concepts we are using aren’t unique to Flexbox, in the same way that alignment properties aren’t unique to Flexbox. However, for how these sizing constructs are used in Flexbox, you need to look in the Flexbox spec. It can feel a little like you are jumping back and forth, so I’ll round up a few key definitions here, which I’ll be using in the rest of the article.

Preferred Size

The preferred size of a box is the size defined by a width or a height, or the logical aliases for these properties of inline-size and block-size. By using:

.box { width: 500px; }

Or the logical alias inline-size:

.box { inline-size: 500px; }

You are stating that you want your box to be 500 pixels wide, or 500 pixels in the inline direction.

min-content Size

The min-content size is the smallest size that a box can be without causing overflow. If your box contains text then all possible soft-wrapping opportunities will be taken.

max-content Size

The max-content size is the largest size the box can be to contain the contents. If the box contains text with no formatting to break it up, then it will display as one long unbroken string.

Flex Item Main Size

The main size of a flex item is the size it has in the main dimension. If you are working in a row — in English — then the main size is the width. In a column in English, the main size is the height.

Items also have a minimum and maximum main size as defined by their min-width or min-height on the main dimension.

Working Out The Size Of A Flex Item

Now that we have some terms defined, we can have a look at how our flex items are sized. The initial value of the flex properties are as follows:

  • flex-grow: 0
  • flex-shrink: 1
  • flex-basis: auto

The flex-basis is the thing that sizing is calculated from. If we set flex-basis to 0 and flex-grow to 1 then all of our boxes have no starting width, so the space in the flex container is shared out evenly, assigning the same amount of space to each item.

See the Pen Smashing Flexbox Series 3: flex: 1 1 0; by Rachel Andrew (@rachelandrew) on CodePen.

Whereas if flex-basis is auto and flex-grow: 1, only the spare space is distributed, taking the size of the content into account.

See the Pen Smashing Flexbox Series 3: flex: 1 1 auto short text by Rachel Andrew (@rachelandrew) on CodePen.

In situations where there is no spare space, for example when we have more content than can fit in a single line, then there is no space to distribute.

See the Pen Smashing Flexbox Series 3: flex: 1 1 auto long text by Rachel Andrew (@rachelandrew) on CodePen.

This shows us that figuring out what auto means is pretty important if we want to know how Flexbox works out the size of our boxes. The value of auto is going to be our starting point.

Defining Auto

When auto is defined as a value for something in CSS, it will have a very specific meaning in that context, one that is worth taking a look at. The CSS Working Group spend a lot of time figuring out what auto means in any context, as this talk for spec editor Fantasai explains.

We can find the information about what auto means when used as a flex-basis in the specification. The terms defined above should help us dissect this statement.

“When specified on a flex item, the auto keyword retrieves the value of the main size property as the used `flex-basis`. If that value is itself auto, then the used value is `content`.”

So if our flex-basis is auto, Flexbox has a look at the defined main size property. We would have a main size if we had given any of our flex items a width. In the below example, the items all have a width of 110px, so this is being used as the main size as the initial value for flex-basis is auto.

See the Pen Smashing Flexbox Series 3: flex items with a width by Rachel Andrew (@rachelandrew) on CodePen.

However, our initial example has items which have no width, this means that their main size is auto and so we need to move onto the next sentence, “If that value is itself auto, then the used value is content.”

We now need to look at what the spec says about the content keyword. This is another value that you can use (in supporting browsers) for your flex-basis, for example:

.item { flex: 1 1 content; }

The specification defines content as follows:

“Indicates an automatic size based on the flex item's content. (It is typically equivalent to the max-content size, but with adjustments to handle aspect ratios, intrinsic sizing constraints, and orthogonal flows”

In our example, with flex items that contain text, then we can ignore some of the more complicated adjustments and treat content as being the max-content size.

So this explains why, when we have a small amount of text in each item, the text doesn’t wrap. The flex items are auto-sized, so Flexbox is looking at their max-content size, the items fit in their container at that size, and the job is done!

The story doesn’t end here, as when we add more content the boxes don’t stay at max-content size. If they did they would break out of the flex container and cause overflow. Once they fill the container, the content begins to wrap and the items become different sizes based on the content inside them.

Resolving Flexible Lengths

It’s at this point where the specification becomes reasonably complex looking, however, the steps that need to happen are as follows:

First, add up the main size of all the items and see if it is bigger or smaller than the available space in the container.

If the container size is bigger than the total, we are going to care about the flex-grow factor, as we have space to grow.

In the first case our items have available space to grow into. (Large preview)

If the container size is smaller than the total then we are going to care about the flex-shrink factor as we need to shrink.

In the second case our items are too large and need to shrink to fit into the container. (Large preview)

Freeze any inflexible items, which means that we can decide on a size for certain items already. If we are using flex-grow this would include any items which have flex-grow: 0. This is the scenario we have when our flex items have space left in the container. The initial value of flex-grow is 0, so they get as big as their max-width and then they don’t grow any more from their main size.

If we are using flex-shrink then this would include any items with flex-shrink: 0. We can see what happens in this step if we give our set of flex items a flex-shrink factor of 0. The items become frozen in their max-content state and so do not flex and arrange themselves to fit in the container.

See the Pen Smashing Flexbox Series 3: flex: 0 0 auto by Rachel Andrew (@rachelandrew) on CodePen.

In our case — with the initial values of flex items — our items can shrink. So the steps continue and the algorithm enters a loop in which it works out how much space to assign or take away. In our case we are using flex-shrink as the total size of our items is bigger than the container, so we need to take away space.

The flex-shrink factor is multiplied by the items inner base size, in our case that is the max-content size. This gives a value with which to reduce space. If items removed space only according to the flex-shrink factor then small items could essentially vanish, having had all of their space removed, while the larger item still has space to shrink.

There is an additional step in this loop to check for items which would become smaller or larger than their target main size, in which case the item stops growing or shrinking. Again, this is to avoid certain items becoming tiny, or massive in comparison to the rest of the items.

All that was simplified in terms of the spec as I’ve not looked at some of the more edge-casey scenarios, and you can generally simply further in your mind, assuming you are happy to let Flexbox do its thing and are not after pixel perfection. Remembering the following two facts will work in most cases.

If you are growing from auto then the flex-basis will either be treated as any width or height on the item or the max-content size. Space will then be assigned according to the flex-grow factor using that size as a starting point.

If you are shrinking from auto then the flex-basis will either be treated as any width or height on the item or the max-content size. Space will then be removed according to the flex-basis size multiplied by the flex-shrink factor, and therefore removed in proportion to the max-content size of the items.

Controlling Growing And Shrinking

I’ve spent most of this article describing what Flexbox does when left to its own devices. You can, of course, exercise greater control over your flex items by using the flex properties. They will hopefully seem more predictable with an understanding of what is happening behind the scenes.

By setting your own flex-basis, or given the item itself a size which is then used as the flex-basis you take back control from the algorithm, telling Flexbox that you want to grow or shrink from this particular size. You can turn off growing or shrinking altogether by setting flex-grow or flex-shrink to 0. On this point, however, it is worth using a desire to control flex items as a time to check whether you are using the right layout method. If you find yourself trying to line up flex items in two dimensions then you might be better choosing Grid Layout.

Debugging Size Related Issues

If your flex items are ending up an unexpected size, then this is usually because your flex-basis is auto and there is something giving that item a width, which is then being used as the flex-basis. Inspecting the item in DevTools may help identify where the size is coming from. You can also try setting a flex-basis of 0 which will force Flexbox to treat the item as having zero width. Even if this isn’t the outcome that you want, it will help to identify the flex-basis value in use as being the culprit for your sizing issues.

Flex Gaps

A much-requested feature of Flexbox is the ability to specify gaps or gutters between flex items in the same way that we can specify gaps in grid layout and multi-column layout. This feature is specified for Flexbox as part of Box Alignment, and the first browser implementation is on the way. Firefox expects to ship the gap properties for Flexbox in Firefox 63. The following example can be viewed in Firefox Nightly.

See the Pen Smashing Flexbox Series 3: flex-gaps by Rachel Andrew (@rachelandrew) on CodePen.

The image as seen in Firefox 63 (Large preview)

As with grid layout, the length of the gap is taken into account before space is distributed to flex items.

Wrapping Up

In this article, I’ve tried to explain some of the finer points of how Flexbox works out how big the flex items are. It can seem a little academic, however, taking some time to understand the way this works can save you huge amounts of time when using Flexbox in your layouts. I find it really helpful to come back to the fact that, by default, Flexbox is trying to give you the most sensible layout of a bunch of items with varying sizes. If an item has more content, it is given more space. If you and your design don’t agree with what Flexbox thinks is best then you can take control back by setting your own flex-basis.

(il)
Categories: Around The Web

Monthly Web Development Update 9/2018: Native Lazy Loading And Imaginary Work

Smashing Magazine - Fri, 09/14/2018 - 8:50am
Monthly Web Development Update 9/2018: Native Lazy Loading And Imaginary Work Monthly Web Development Update 9/2018: Native Lazy Loading And Imaginary Work Anselm Hannemann 2018-09-14T14:50:19+02:00 2018-09-24T12:10:20+00:00

It’s an interesting concept to compare JavaScript with CO2 and yet a very valid one. Alex Russel who works for the Chrome team and has a lot of insights into the current state of the web says that using too much JavaScript or using it exclusively (without progressive enhancement/graceful degradation) will have the same effect as too much CO2 for the ecosystem on planet Earth — the ecosystem will fall apart. And just like we need a certain amount of CO2 to live, we need JavaScript on the web. It’s that fine line that makes the difference — the line between not too much and none at all.

I feel that with the native browser APIs that we have these days we have a fantastic opportunity to build great web services without bloating them too much and without relying only on JavaScript. We can enhance native elements with the Custom Elements API easily via ES6 Classes, with so little code that it seems ridiculous to build all that on your own in a third-party framework. Coincidentally, the Github engineering team published an article about how they dropped jQuery entirely and what they now use instead: native JavaScript and small, lean code that is progressively enhancing their platform. Less code, better maintainability, and more stability.

News
  • Chrome 70 is now in beta, bringing shape detection as an origin trial that allows us to perform QR code reading, face detection, and text recognition in images. The Web Authentication API got some updates, too, and referrerpolicy support was added to <script> elements. This version will also deprecate Custom Elements v0, HTML Imports, and Shadow DOM v0.
  • Finally, with Firefox 62, Mozilla ships ::selection instead of :-moz-selection. They also implemented flat(), and flatMap() for JavaScript arrays and developers get a new Shape Path Editor.
  • Chrome 69 is out and brings us CSS Scroll Snap Points, the CSS viewport-fit property for cutout-displays like the one of iPhone X, and the Web Locks API which allows scripts running in one tab or worker to asynchronously acquire a lock, hold it while work is performed, and then release it. The update also comes with CSS conic gradient support, toggleAttribute() (which is similar to the classList.toggle() method but for attributes), and flat() and flatMap() for arrays. Unfortunately, this release changed how the browser displays the URL, and it seems that people consider it a security bug. Let’s see how that will evolve.
  • With Firefox 62 supporting variable web fonts, we finally have support in all major browsers and can use it widely now to improve performance, be more creative with typography, and reduce data traffic drastically.
  • Manuel Rego Casasnovas wrote about recent changes on CSS Grid Layout in percentages and indefinite height in the Chrome browser.
  • Anyone who isn’t an expert would be hard-pressed to explain how tracking on the internet actually works. That’s why Firefox now changes their default settings and enforces tracking blocking in their browser by default.
  • PHP7.3 is coming soon with new Heredoc and Nowdoc syntax, trailing commas in function calls, is_countable(), array_key_first(), array_key_last(), and Argon2 password hash enhancements.

Meet SmashingConf New York 2018 (Oct 23–24), focused on real challenges and real front-end solutions in the real world. From progressive web apps, Webpack and HTTP/2 to serverless, Vue.js and Nuxt — all the way to inclusive design, branding and machine learning. With Sarah Drasner, Sara Soueidan and many other speakers.

Check all topics and speakers ↬ General
  • Alex Russell’s “The ‘Developer Experience’ Bait-and-Switch” is a great piece that explains the toxic environments we currently build for the web and why JavaScript can be compared to CO2 — both are needed in small portions, but if there’s too much of it, it’ll put the entire ecosystem (the web) at risk. A thoughtful article that I recommend everyone here to read, share, and remember.
  • As Alexa, Cortana, Siri, and even customer support chat bots become the norm we have to start considering not only how our content looks but how it could sound. We can — and should — use HTML and ARIA to make our content structured, sensible, and most importantly, meaningful.
Web Performance Security
  • Nightwatch Cybersecurity published a security vulnerability in Android that exposes information about the user’s device to all applications running on it. This seems to include the WiFi network name, BSSID, local IP addresses, DNS server information, and the MAC address — all in all quite a lot of private information that allows people to track individual Android devices. Unfortunately, all Android OS versions including forks (except for Android P/9 where a fix was provided) seem to be affected with no plan to fix older versions.
CSS
  • Chen Hui Jing explains how to customize radio buttons without compromising their accessibility.
  • CSS Shapes have quite some history already. Brought to the web early by an initiative of the Adobe Web team, browser vendors removed the implementations soon again, and are now slowly coming back with iterated, improved specifications and implementations. Rachel Andrew shares how to implement CSS Shapes.
  • Sara Soueidan wrote down the reasons she switched from defining CSS colors as HEX or RGB to HSL and what the benefits are.
  • With the web’s growth come new features to better accommodate its new form factors and use cases. One feature I’m excited about is the color-adjust property, proposed in CSS Color Module Level 4. It is an acknowledgment that the web will continue to show up on devices that have less-than-stellar displays.
Creating color harmonies becomes a piece of cake with HSL. (Image credit) HTML & SVG JavaScript Accessibility
  • Ethan Marcotte reflects on what accessibility means and realizes that it’s not about making a website compatible with some assistive technology or software but about making it usable for everyone who wants to access it, regardless of the technology. This is a huge difference because his approach includes people who have difficulties reading a website even though they use the same browser and the same laptop as you. Maybe they are in bright sunlight, have difficulties with small text, or get distracted by bright colors or animated elements.
  • Eric Bailey emphasizes how important it is to manually test for accessibility.
  • Scott O’Hara shares a breadcrumb navigation using aria-label to provide an accessible name and aria-current to indicate the currently active link.
Work & Life We all have been there before: Imagining a solution in your head and implementing it are two entirely different things. (Image credit) Going Beyond…
  • I love the concept of doodling, and even though I don’t do it regularly, it always fascinates me. Doodle Addicts is a platform that collects doodles from people all around the world. A nice gallery to get inspiration from.
  • Jonny Brooks-Bartlett wrote an interesting article on why so many data scientists are leaving their jobs. The job might sound quite interesting and like a good bet these days, but often expectations don’t match reality and politics and ethical decisions are extremely difficult.
  • Marco Lambertini explains how technology can help us save the planet, but more than anything we need to learn to value nature and its resources.
  • An interesting discussion was raised this week by a very well-known Open Source contributor who tried to change the license of one of their projects in order to prevent companies who support the U.S. ICE institution from using their software. The change was quickly reverted after it was revealed that it wasn’t legally enforceable. However, the entire topic (which comes up way more often lately) shows that more and more people think about the impact of their work. They don’t want it to be used for bad, but for good. And while the idea of open, non-restricted source is desirable, it’s only if people use it to support human rights and for improving lives. I’m curious about new solutions that could ensure this; maybe we’ll see more terms of service for open-source projects soon (which would then be legally binding but may prevent free open-source projects from using them).
(cm)

Categories: Around The Web

Smashing Book 6 Is Here: New Frontiers In Web Design

Smashing Magazine - Thu, 09/13/2018 - 7:25am
Smashing Book 6 Is Here: New Frontiers In Web Design Smashing Book 6 Is Here: New Frontiers In Web Design Vitaly Friedman 2018-09-13T13:25:00+02:00 2018-09-24T12:10:20+00:00

Imagine you were living in a perfect world. A world where everybody has fast, stable and unthrottled connections, reliable and powerful devices, exquisite screens, and capable, resilient browsers. The screens are diverse in size and pixel density, yet our interfaces adapt to varying conditions swiftly and seamlessly. What a glorious time for all of us — designers, developers, senior Webpack configurators and everybody in-between — to be alive, wouldn’t you agree?

Well, we all know that the reality is slightly more nuanced and complicated than that. That’s why we created Smashing Book 6, our shiny new book that explores uncharted territories and seeks to discover new reliable front-end and UX techniques. And now, after 10 months of work, the book is ready, and it's shipping. Jump to table of contents and get the book right away.

  • eBook
  • Hardcover
eBook$19Get the eBook

PDF, ePUB, Kindle. Free for Smashing Members.

Hardcover$39Get the Print (incl. eBook)

Printed, quality hardcover. Free airmail shipping worldwide.

About The Book

Finding your way through front-end and UX these days is challenging and time-consuming. But frankly, we all just don’t have time to afford betting on a wrong strategy. Smashing Book 6 sheds some light on new challenges and opportunities, but also uncovers new traps and pitfalls in this brave new front-end world of ours.

Our books aren't concerned with short-living trends, and our new book isn't an exception. Smashing Book 6 is focused on real challenges and real front-end solutions in the real world: from accessible apps to performance to CSS Grid Layout to advanced service workers to responsive art direction. No chit-chat or theory. Things that worked, in actual projects. Jump to table of contents.

The Smashing Book 6, with 536 pages on real-life challenges and opportunities on the web. Photo by our dear friend Marc Thiele. (Large preview)

In the book, Laura and Marcy explore strategies for maintainable design systems and accessible single-page apps with React, Angular etc. Mike, Rachel and Lyza share insights on using CSS Custom Properties and CSS Grid in production today. Yoav and Lyza take a dive deep into performance patterns and service workers in times of Progressive Web Apps and HTTP/2.

Inner design of the Smashing Book 6. Designed by one-and-only Chiara Aliotta. Large view.

Ada, Adrian and Greg explore how to design for watches and new form factors, as well as AR/VR/XR, chatbots and conversational UIs. The last chapter will guide you through some practical strategies to break out of generic, predictable, and soulless interfaces — with dozens of examples of responsive art direction. But most importantly: it’s the book dedicated to headaches and solutions in the fragile, inconsistent, fragmented and wonderfully diverse web we find ourselves in today.

Table Of Contents

Want to peek inside? Download a free PDF sample (PDF, ca. 21 MB) with a chapter on bringing personality back to the web by yours truly. Overall, the book contains 10 chapters:

  1. Making Design Systems Work In Real-Life
    by Laura Elizabeth
  2. Accessibility In Times Of Single-Page Applications
    by Marcy Sutton
  3. Production-Ready CSS Grid Layouts
    by Rachel Andrew
  4. Strategic Guide To CSS Custom Properties
    by Mike Riethmueller
  5. Building An Advanced Service Worker
    by Lyza Gardner
  6. Loading Assets On The Web
    by Yoav Weiss
  7. Conversation Interface Design Patterns
    by Adrian Zumbrunnen
  8. Building Chatbots And Designing For Watches
    by Greg Nudelman
  9. Cross Reality And The Web (AR/VR)
    by Ada Rose Cannon
  10. Bringing Personality Back To The Web (free PDF sample, 21MB)
    by Vitaly Friedman
.c-garfield-the-cat img { border-radius: 11px; } @supports (display: grid) { .smb6-authors { display: grid; grid-template-columns: repeat(auto-fit, 130px); grid-gap: 1em; } .smb6-authors figcaption { grid-column: 1 / -1; } .smb6-authors::before { display: none; } }
From left to right: Laura Elizabeth, Marcy Sutton, Rachel Andrew, Mike Riethmuller, Lyza D. Gardner, Yoav Weiss, Adrian Zumbrunnen, Greg Nudelman, Ada Rose Edwards, and yours truly.

  • 536 pages. Quality hardcover + eBook (PDF, ePUB, Kindle).
    Published late September 2018.
  • Written by and for designers and front-end developers.
    Designed with love from Italy by Chiara Aliotta.
  • Free airmail worldwide shipping from Germany.
    Check delivery times for your country.
  • If you are a Smashing Member, don't forget to apply your Membership discount.
  • Good enough? Get the book right away.
  • eBook
  • Hardcover
eBook$19Get the eBook

PDF, ePUB, Kindle. Free for Smashing Members.

Hardcover$39Get the Print (incl. eBook)

Printed, quality hardcover. Free airmail shipping worldwide.

About The Designer

The cover was designed with love from Italy by one-and-only Chiara Aliotta. She founded the design studio Until Sunday and has directed the overall artistic look and feel of different tech companies and not-for-profit organizations around the world. We’re very happy that she gave Smashing Book 6 that special, magical touch.

Behind The Scenes Of The Design Process

We asked Chiara to share some insights into the design process of the cover and the interior design and she was very kind to share some thoughts with us:

"It all started with a few exchanges of emails and a Skype meeting where Vitaly shared his idea of the book and the general content. I had a lot of freedom, which is always exciting and scary at the same time. The only bond (if we want to call it like this) was that the "S" of Smashing Magazine should be the main protagonist of the cover, reinvented and creatively presented as per all the other previous Smashing Books.

The illustration on paper. The cover sketched on paper. Also check the close-up photo. (Large preview)

I worked around few keywords that Vitaly was using to describe the book during our meetings and then developed an idea around classical novels of adventure where the main hero leaves home, encounters great hazards, risks, and then eventually returns wiser and/or richer than he/she was before.

So I thought of Smashing Book 6 as a way to propose this basic and mythic structure under a new light: through the articles of this book, the modern web designer will be experiencing true and deep adventures.

I imagined the "S" as an engine, the starting point of this experience, from where different worlds were creating and expanding. So the cover was the map of these uncharted territories that the book explores.

Every element on the cover has a particular meaning that constructs the S. Large view.

I am a person who judges books by its cover and having read some of the chapters and knowing some of the well-established writers, I wanted to honour its content and their work by creating a gorgeous cover and chapter illustrations.

For this edition of Smashing Book, I imagined a textile cover in deep blue, where the graphic is printed using a very old technique, the hot gold foil stamping.

Together with Markus, part of the Smashing Magazine team and responsible for the publishing of all the Smashing Books, we worked closely to choose the final details of the binding and guarantee an elegant and sophisticated result, adding a touch of glam to the book.

Smashing Book 6 comes wrapped with a little bookmark. Photo by our dear friend Marc Thiele.

As a final touch, I added a paper wrap around the book that invites the readers to "unlock their adventure", suggesting a physical action: the reader needs to tear off the paper before starting reading the book. And for this only version, we introduced a customise Smashing Magazine bookmark, also in printed on gold paper. Few more reasons to prefer the paperback version over the digital ones!"

A huge round of applause to Chiara for her wonderful work and sharing the thoughts with us. We were remarkably happy with everything from design to content. But what did readers think? Well, I’m glad that you asked!

Sketches for chapter illustrations. (Large preview) Feedback and Testimonials

We've sent the shiny new book to over 200 people to peek through and read, and we were able to gather some first insights. We'd love to hear your thoughts, too!

“Web design is getting pretty darned complicated. The new book from SmashingMag aims to bring the learning curve down to an accessible level.”

Aaron Walter, InVision “Just got the new Smashing Book 6 by SmashingMag. What a blast! From CSS Grid Layout, CSS Custom Properties and service workers all the way to the HTTP/2 and conversational interfaces and many more. I recommend it to all the people who build interfaces.”

Mihael Tomić, Osijek, Croatia “The books published by SmashingMag and team are getting better each time. I was thrilled to be able to preview it... EVERY CHAPTER IS GOOD! Having focused on a11y for much of my career, Marcy Sutton’s chapter is a personal favorite.”

Stephen Hay, Amsterdam, Netherlands The Smashing Book 6, with 536 pages on real-life challenges and solutions for the web. Huge thank-you note to the smashing community for supporting the book and out little magazine all these years. (Large preview) Thank You For Your Support!

We’re very honored and proud to have worked with wonderful people from the industry who shared what they’ve learned in their work. We kindly thank all the hard-working people involved in making this book reality. We kindly thank you for your ongoing support of the book and our little magazine as well. It would be wonderful if you could mention the book by any chance as well in your social circles and perhaps link to this very post.

We’ve also prepared a little media kit .zip with a few photos and illustrations that you could use if you wanted to — just sayin’!

We can’t wait to hear your thoughts about the book! Happy reading, and we hope that you’ll find the book as useful as we do. Just have a cup of coffee (or tea) ready before you start reading, of course, stay smashing and... meow!

  • eBook
  • Hardcover
eBook$19Get the eBook

PDF, ePUB, Kindle. Free for Smashing Members.

Hardcover$39Get the Print (incl. eBook)

Printed, quality hardcover. Free airmail shipping worldwide.

(ra, il)
Categories: Around The Web

The Importance Of Manual Accessibility Testing

Smashing Magazine - Wed, 09/12/2018 - 7:30am
The Importance Of Manual Accessibility Testing The Importance Of Manual Accessibility Testing Eric Bailey 2018-09-12T13:30:55+02:00 2018-09-24T12:10:20+00:00

Earlier this year, a man drove his car into a lake after following directions from a smartphone app that helps drivers navigate by issuing turn-by-turn directions. Unfortunately, the app’s programming did not include instructions to avoid roads that turn into boat launches.

From the perspective of the app, it did exactly what it was programmed to do, i.e. to find the most optimal route from point A to point B given the information made available to it. From the perspective of the man, it failed him by not taking the real world into account.

The same principle applies for accessibility testing.

Designing For Accessibility And Inclusion

The more inclusive you are to the needs of your users, the more accessible your design is. Let’s take a closer look at the different lenses of accessibility through which you can refine your designs. Read article →

Automated Accessibility Testing

I am going to assume that you’re reading this article because you’re interested in learning how to test your websites and web apps to ensure they’re accessible. If you want to learn more about why accessibility is necessary, the topic has been covered extensively elsewhere.

Automated accessibility testing is a process where you use a series of scripts to test for the presence, or lack of certain conditions in code. These conditions are dictated by the Web Content Accessibility Guidelines (WCAG), a standard by the W3C that outlines how to make digital experiences accessible.

Meet SmashingConf New York 2018 (Oct 23–24), focused on real challenges and real front-end solutions in the real world. From progressive web apps, Webpack and HTTP/2 to serverless, Vue.js and Nuxt — all the way to inclusive design, branding and machine learning. With Sarah Drasner, Sara Soueidan and many other speakers.

Check all topics and speakers ↬

For example, an automated accessibility test might check to see if the tabindex attribute is present and if its value is greater than 0. The pseudocode would be something like:

Failures can then be collected and used to generate reports that disclose the number, and severity of accessibility issues. Certain automated accessibility products can also integrate as a Continuous Integration or Continuous Deployment (CI/CD) tool, presenting just-in-time warnings to developers when they attempt to add code to a central repository.

These automated programs are incredible resources. Modern websites and web apps are complicated things that involve hundreds of states, thousands of lines of code, and complicated multi-screen interactions. It’d be absurd to expect a human (or a team of humans) to mind all the code controlling every possible permutation of the site, to say nothing of things like regressions, software rot, and A/B tests.

Automation really shines here. It can repeatedly and tirelessly pour over these details with perfect memory, at a rate far faster than any human is capable of.

However…

Automated accessibility tests aren’t a turnkey solution, nor are they a silver bullet. There are some limitations to keep in mind when using them.

Thinking To Think Of Things

One of both the best and worst aspects of the web is that there are many different ways to implement a solution to a problem. While this flexibility has kept the web robust and adaptable and ensured it outlived other competing technologies, it also means that you’ll sometimes see code that is, um, creatively implemented.

The test suite is only as good as what its author thought to check for. A naïve developer might only write tests for the happy path, where everyone writes semantic HTML, fault-tolerant JavaScript, and well-scoped CSS. However, this is the real world. We need to acknowledge that things like tight deadlines, unfamiliarity with the programming language, atypical user input, and sketchy 3rd party scripts exist.

For example, the automated accessibility testing site Tenon.io wisely includes a rule that checks to see if a form element has both a label element and an aria-label associated with it, and if the text strings for both declarations differ. If they do, it will flag it as an issue, as the visible label may be different than what someone would hear if they were navigating using a screen reader.

If you’re not using a testing service that includes this rule, it won’t be reported. The code will still “pass”, but it’s passing by omission, not because it’s actually accessible.

State

Some automated accessibility tests cannot parse the various states of interactive content. Critical parts of the user interface are effectively invisible to automation unless the test is run when the content is in an active, selected, or disabled state.

By interactive content, I mean things that the user has yet to take action on, or aren’t present when the page loads. Unopened modals, collapsed accordions, hidden tab content and carousel slides are all examples.

It takes sophisticated software to automatically test the various states of every component within a single screen, let alone across an entire web app or website. While it is possible to augment testing software with automated accessibility checks, it is very resource-intensive, usually requiring a dedicated team of engineers to set up and maintain.

“Valid” Markup

Accessible Rich Internet Applications (ARIA) is a set of attributes that extend HTML to allow it to describe interaction in a way that can be better understood by assistive technologies. For example, the aria-expanded attribute can be toggled by JavaScript to programmatically communicate if a component is in an expanded (true) or collapsed (false) state. This is superior to toggling a CSS class like .is-expanded, where the update in state is only communicated visually.

Just having the presence of ARIA does not guarantee that it will automatically make something accessible. Unfortunately, and in spite of its first rule of use, ARIA is commonly misunderstood, and consequently abused. A lot of off-the-shelf code has this problem, perpetuating the issue.

For example, certain ARIA attributes and values can only be applied to certain elements. If incorrectly applied, assistive technology will ignore or misreport the declaration. Certain roles, known as Abstract Roles, only exist to set up the overall taxonomy and should never be placed in markup.

<button role="command">Save</button> <!-- Never do this -->

To further complicate the issue, support for ARIA is varied across browsers. While an attribute may be used appropriately, the browser may not communicate the declared role, property, or state to assistive technology.

There is also the scenario where ARIA can be applied to an element and be valid from a technical standpoint, yet be unusable from an assistive technology perspective. For example:

<h1 aria-hidden=“true”> Tired of unevenly cooked asparagus? Try this tip from the world’s oldest cookbook. </h1>

This one Weird Trick.

The aria-hidden declaration will remove the presence of content from assistive technology, yet allow it to be still rendered visibly on the page. It’s a problematic pattern.

Headings — especially first-level headings — are vital in communicating the purpose of a page. If a person is using assistive technology to navigate, the aria-hidden declaration applied to the h1 element will make it difficult for them to quickly determine the page’s purpose. It will force them to navigate around the rest of the page to gain context, an annoying and labor-intensive process.

Some automated accessibility tests may scan the code and not report an error since the syntax itself is valid. The automation has no way of knowing the greater context of the declaration’s use.

This isn’t to say you should completely avoid using ARIA! When authored with care and deliberation, ARIA can fix the gaps in accessibility that sometimes plague complicated interactions; it provides some much-needed context to the people who rely on assistive technology.

Much-Needed Context

As the soggy car demonstrates, computers are awful at understanding the overall situation of the outside world. It’s up to us humans to be the ultimate arbiters in determining if what the computer spits out is useful or not.

Debunking

Before we discuss how to provide appropriate context, there are a few common misunderstandings about accessibility work that need to be addressed:

First, not all screen reader users are blind. In addition to all the points Adrian Roselli outlines in his post, some food for thought: the use of voice assistants is on the rise. When’s the last time you spoke to Siri or Alexa?

Second, accessibility is more than just screen readers. The rules outlined in the Web Content Accessibility Guidelines ensure that the largest number of people can read and operate technology, regardless of ability or circumstance.

For example, the rule that stipulates a website or web app needs to be able to work regardless of device orientation benefits everyone. Some people may need to mount their device in a fixed location in a specific orientation, such as in landscape mode on the arm of a wheelchair. Others might want to lie in bed and watch a movie, or better investigate a product photo (pinch and pull zooming will also be helpful to have here).

Third, disabilities can be conditional and can be brought about by your environment. It can be a short-term thing, like rain on your glasses, sleep deprivation, or an allergies-induced migraine. It can also be longer-term, such as a debilitating illness, broken limb, or a depressive episode. Multiple, compounding conditions can (and do) affect individuals.

That all being said, many accessibility fixes that help screen readers work properly also benefit other assistive technologies.

Get Your Feet Wet

Knowing where to begin can be overwhelming. Consider Michiel Bijl’s great advice:

“Before you release a website, tab through it. If you cannot see where you are on the page after each tab; you're not finished yet. #a11y

Tab through a few of the main user flows on your website or web app to determine if all interactive components’ focus states are visually apparent, and if they can be activated via keyboard input. If there’s something you can click or tap on that isn’t getting highlighted when receiving keyboard focus, take note of it. Also pay attention to the order interactive components are highlighted when focused — it should match the reading order of the site.

An obvious focus state and logical tab order go a great way to helping make your site accessible. These two features benefit a wide variety of assistive technology, including, but not limited to, screen readers.

If you need a baseline to compare your testing to, Dave Rupert has an excellent project called A11Y Nutrition Cards, which outlines expected behavior for common interactive components. In addition, Scott O’Hara maintains a project called a11y Styled Form Controls. This project provides examples of components such as switches, checkboxes, and radio buttons that have well-tested and documented support for assistive technology. A clever reader might use one of these resources to help them try out the other!

(Large preview) The Fourth Myth

With that out of the way, I’m going to share a fourth myth with you: not every assistive technology user is a power user. Like with any other piece of software, there’s a learning curve involved.

In her post about Aaptiv’s redesign, Lisa Zhu discovers that their initial accessibility fix wasn’t intuitive. While their first implementation was “technically” correct, it didn’t line up with how people who rely on VoiceOver actually use their devices. A second solution simplified the interaction to better align with their expectations.

Don’t assume that just because something hypothetically functions that it’s actually usable. Trust your gut: if it feels especially awkward, cumbersome, or tedious to operate for you, chances are it’ll be for others.

Dive Right In

While not every accessibility issue is a screen reader issue, you should still get in the habit of testing your site with one. Not an emulator, simulator, or some other proxy solution.

If you find yourself struggling to operate a complicated interactive component using basic screen reader commands, it’s probably a sign that the component needs to be simplified. Chances are that the simplification will help non-assistive technology users as well. Good design benefits everyone!

The same goes for navigation. If it’s difficult to move around the website or web app, it’s probably a sign that you need to update your heading structure and landmark roles. Both of these features are used by assistive technology to quickly and efficiently navigate.

Both of these are sidebars, but only one of them is semantically described as such. A computer doesn't know what a sidebar is, so it's up to you to tell it.

Another good thing to review is the text content used to describe your links. Hopping from link to link is another common assistive technology navigation technique; some screen readers can even generate a list of all link content on the page:

“Think before you link! Your "helpful" click here links look like this to a screen reader user. ALT = JAWS links list”


Neil Milliken

When navigating using an ordered list devoid of the surrounding non-link content, avoiding ambiguous terms like “click here” or “more info” can go a long way to ensuring a person can understand the overall meaning of the page. As a bonus, it’ll help alleviate cognitive concerns for everyone, as you are more accurately explaining what a user should expect after activating a link.

How To Test

Each screen reader has a different approach to how it announces content. This is intentional. It’s a balancing act between the product’s features, the operating system it is installed on, the form factor it is available in, and the types of input it can receive.

The Browser Wars taught us the folly of developing for only one browser. Similarly, we should not cater to a single screen reader. It is important to note that many people rely exclusively on a specific screen reader and browser combination — by circumstance, preference, or necessity’making this all the more important. However, there is a caveat: each screen reader works better when used with a specific browser, typically the one that allows it access to the greatest amount of accessibility API information.

All of these screen readers can be used for free, provided you have the hardware. You can also virtualize that hardware, either for free or on the cheap.

Automate

Automated accessibility tests should be your first line of defense. They will help you catch a great deal of nitpicky, easily-preventable errors before they get committed. Repeated errors may also signal problems in template logic, where one upstream tweak can fix multiple pages. Identifying and resolving these issues allows you to spend your valuable manual testing time much more wisely.

It may also be helpful to log accessibility issues in a place where people can collaborate, such as Google Sheets. Quantifying the frequency and severity of errors can lead to good things like updated documentation, opportunities for lunch and learn education, and other healthy changes to organizational workflow.

Much like manual testing with a variety of screen readers, it is recommended that you use a combination of automated tools to prevent gaps.

Windows

The two most popular screen readers on Windows are JAWS and NVDA.

JAWS

JAWS (Job Access With Speech) is the most popular and feature-rich screen reader on the market. It works best with Firefox and Chrome, with concessions for supporting Internet Explorer. Although it is pay software, it can be operated in full in demo mode for 40 minutes at a time (this should be more than sufficient to perform basic testing).

NVDA

NVDA (NonVisual Desktop Access) is free, although a donation is strongly encouraged. It is a feature-rich alternative to JAWS. It works best with Firefox.

Narrator

Windows comes bundled with a built-in screen reader called Narrator. It works well with Edge, but has difficulty interfacing with other browsers.

Apple macOS

VoiceOver is a powerful screen reader that comes bundled with macOS. Use it in conjunction with Safari, first making sure that full keyboard access is enabled.

iOS

VoiceOver is also included in iOS, and is the most popular mobile screen reader. Much like its desktop counterpart, it works best with Safari. An interesting note here is that according to the 2017 WebAIM screen reader survey, a not-insignificant amount of respondents augment their phone with external hardware keyboards.

Android

Google recently folded TalkBack, their mobile screen reader, into a larger collection of accessibility services called the Android Accessibility Suite. It works best with Mobile Chrome. While many Android apps are notoriously inaccessible, it is still worth testing on this platform. Android’s growing presence in emerging markets, as well as increasing internet use amongst elderly and lower-income demographics, should give pause for consideration.

Popular screen readers Screen Reader Platform Preferred Browser(s) Manual Launch Quit JAWS Windows Chrome, Firefox JAWS 2018 Documentation Launch JAWS as you would any other Windows application Insert + F4 NVDA Windows Firefox NVDA 2018.2.1 User Guide Ctrl + Alt + N Insert + Q Narrator Windows Edge Get started with Narrator Windows key + Control + Enter Windows key + Control + Enter VoiceOver macOS Safari VoiceOver Getting Started Guide Command + F5 or tap the Touch ID button 3 times Command + F5 or tap the Touch ID button 3 times Mobile VoiceOver iOS Mobile Safari VoiceOver overview - iPhone User Guide Tell Siri to, “Turn on VoiceOver.” or activate in Settings Tell Siri to, “Turn off VoiceOver.” or deactivate in Settings Android Accessibility Suite Android Mobile Chrome Get started on Android with TalkBack Press both volume keys for 3 seconds Press both volume keys for 3 seconds Call The Professionals

If you do not require the use of assistive technology on a frequent basis then you do not fully understand how the people who do interact with the web.

Much like traditional user testing, being too close to the thing you created may cloud your judgment. Empathy exercises are a good way to become aware of the problem space, but you should not use yourself as a litmus test for whether the entire experience is truly accessible. You are not the expert.

If your product serves a huge population of users, if its core base of users trends towards having a higher probability of disability conditions (specialized product, elderly populations, foreign language speakers, etc.), and/or if it is required to be compliant by law, I would strongly encourage allocating a portion of your budget for testing by people with disabilities.

“At what point does your organisation stop supporting a browser in terms of % usage? 18% of the global pop. have an #Accessibility requirement, 2% people have a colour vision deficient. But you consider 2% IE usage support more important? Support everyone be inclusive.”

Mark Wilcock

This isn’t to say you should completely delegate the responsibility to these testers. Much as how automated accessibility testing can detect smaller issues to remove, a first round of basic manual testing helps professional testers focus their efforts on the complicated interactions you need an expert’s opinion on. In addition to optimizing the value of their time, it helps to get you more comfortable triaging. It is also a professional courtesy, plain and simple.

There are a few companies that perform manual testing by people with disabilities:

Designed Experiences

We also need to acknowledge the other large barrier to accessible sites that can’t be automated away: poor user experience.

User experience can make or break a product. Your code can compile perfectly, your time to first paint can be lightning quick, and your Webpack setup can be beyond reproach. All this is irrelevant if the end result is unusable. User experience encompasses all users, including those who navigate with the aid of assistive technology.

If a person cannot operate your website or web app, they’ll abandon it and not think twice. If they are forced to use your site to get a service unavailable by other means, there’s a growing precedent for taking legal action (and rightly so).

As a discipline, user experience can be roughly divided into two parts: how something looks and how it behaves They’re intrinsically interlinked concepts — work on either may affect both. While accessible design is a topic unto itself, there are some big-picture things we can keep in mind when approaching accessible user experiences from a testing perspective:

How It Looks

The WCAG does a great job covering a lot of the basics of good design. Color contrast, font size, user-facing state: a lot of these things can be targeted by automation. What you should pay attention to is all the atomic, difficult to quantify bits that compound to create your designs. Things like the words you choose, the fonts you use to display them, the spacing between things, affordances for interaction, the way you handle your breakpoints, etc.

“A good font should tell you:
the difference between m and rn
the difference between I and l
the difference between O and 0.”

mallory, alice & bob

It’s one of those “an ounce of prevention is worth a pound of cure” situations. Smart, accessible defaults can save countless time and money down the line. Lean and mean startups all the way up to multinational conglomerates value efficient use of resources, and this is one of those places where you can really capitalize on that. Put your basic design patterns — say collected in something like a mood board or living style guide — in front of people early and often to see if your designed intent is clear.

How It Behaves

An enticing color palette and collection of thoughtfully-curated stock photography only go so far. Eventually, you’re going to have to synthesize all your design decisions to create something that addresses a need.

Behavior can be as small as a microinteraction, or as large as finding a product and purchasing it. What’s important here is to make sure that all the barriers to a person trying to accomplish the task at hand are removed.

If you’re using personas, don’t create a separate persona for a user with a disability. Instead, blend accessibility considerations into your existing ones. As a persona is an abstracted representation of the types of users you want to cater to, you want to make sure the kinds of conditions they may be experiencing are included. Disability conditions aren’t limited to just physical impairments, either. Things like a metered data plan, non-native language, or anxiety are all worth integrating.

“When looking at your site's analytics, remember that if you don't see many users on lower end phones or from more remote areas, it's not because they aren't a target for your product or service. It is because your mobile experience sucks.
As a developer, it's your job to fix it.”

Estelle Weyl

User testing, ideally simulating conditions as close to what a person would be doing in the real world (including their individual device preferences and presence of assistive technology), is also key. Verifying that people are actually able to make the logical leaps necessary to operate your interface addresses a lot of cognitive concerns, a difficult-to-quantify yet vital thing to accommodate.

We Shape Our Tools, Our Tools Shape Us

Our tool use corresponds to the kind of work we do: Carpenters drive nails with hammers, chefs cook using skillets, surgeons cut with scalpels. It’s a self-reinforcing phenomenon, and it tends to lead to over-categorization.

Sometimes this over-categorization gets in the way of us remembering to consider the real world. A surgeon might have a carpentry hobby; a chef might be a retired veterinarian. It’s important to understand that accessibility is everyone’s responsibility, and there are many paths to making our websites and web apps the best they can be for everyone. To paraphrase Mikey Ilagan, accessibility is a holistic practice, essential to some but useful to all.

Used with discretion, ARIA is a very good tool to have at our disposal. We shouldn’t shy away from using it, provided we understand the how and why behind why they work.

The same goes for automated accessibility tests, as well as GPS apps. They’re great tools to have, just get to know the terrain a little bit first.

Resources Automated Accessibility Tools Professional Services References Quick Tests Further Reading (rb, ra, yk, il)
Categories: Around The Web

Introduction To Animation And The iMessage App Store With Shruggie

Smashing Magazine - Mon, 09/10/2018 - 8:45am
Introduction To Animation And The iMessage App Store With Shruggie Introduction To Animation And The iMessage App Store With Shruggie Simon Schmid 2018-09-10T14:45:42+02:00 2018-09-24T12:10:20+00:00

When the App Store for iMessage in late 2016 went live, I released Kaomotion, a sticker app with animated kaomoji inside. Ever since the release of this app, I wanted to write up a tutorial about how a simple text character like shruggie (i.e. ¯\_(ツ)_/¯) can be animated to give it life-like features:

The Shruggie animation we’re going to make. (Large preview)

What you are going to read in this article is a step-by-step guide of setting up a canvas in After Effects and then going through with the animation. You’ll also read about how well the app containing more than 30 animated stickers worked and what some of the specific issues are you might be having on the App Store for iMessage:

  1. Canvas Setup
  2. Working With A (Text) Layer
  3. Working With Rulers
  4. Understanding The Puppet Pin Tool
  5. Animation And Timeline
  6. Further Reading And Tools
  7. Bonus Reading: Life On The App Store For iMessage

Without further ado, let’s jump right in.

Meet SmashingConf New York 2018 (Oct 23–24), focused on real challenges and real front-end solutions in the real world. From progressive web apps, Webpack and HTTP/2 to serverless, Vue.js and Nuxt — all the way to inclusive design, branding and machine learning. With Sarah Drasner, Sara Soueidan and many other speakers.

Check all topics and speakers ↬ 1. Canvas Setup

We’re starting with setting up a new composition (⌘ + N) within After Effects with the following settings:

  • 1000px × 1000px;
  • a frame rate of 30 frames per second;
  • a quarter on resolution;
  • a run time of 2 seconds.

This is going to be the basic canvas we’re going to work with during the animation. We’re choosing a square since that is what you have to deal with within iMessage and Apple’s sticker implementation.

After Effects canvas set up. (Large preview) 2. Working With A (Text) Layer

Since kaomoji are simple text-based emoticons we’re going to copy-paste a a Shruggie “¯\_(ツ)_/¯” from the first source we can find being Jeremy Burge’s Emojipedia via Google.

After having found it on Emojipedia we’re pasting it as a text layer into After Effects. It’s time to utilise the text tool.

The Text Tool

Copy ⌘ + T in with ⌘ + V:

Using the text layer. (Large preview)

The Shruggie inside your canvas might not look exactly the way you’ve found him on Google, or on Emojipedia for that matter, that’s because of differences in font types. We’ve chosen a font that makes Shruggie look decent and made him stretch across the canvas to prepare him for his facelift: double-click on the Source Name to select all characters.

The Character Menu

Double click Name Source and then get the font type in your Character menu.

The character menu. (Large preview) Scaling A Layer

Select Layer, then S + Scale (by sliding right for example).

To position the layer properly, we’re scaling it up to fill the canvas by selecting the layer by pressing S, then Scale and then finally moving the scale until it fits.

Scaling a layer. (Large preview)

To further explore some smaller tweaks let’s look into making our Shruggie a little more connected. For that we’re looking into some kerning and height options. To adjust the gap between Shruggie’s arm and hand, we’ll use the kerning tool (V/A) either manually in the menu or with another keyboard shortcut:

Kerning

Select Space + ALT + ← →. When we’re happy with the kerning gaps, we’ll adjust the height of the arms and make it look like the arms are actually connected. To join up the slashes with the underscore we’re going to play around with increasing the height of the slash/vertical scale, moving it vertically and potentially adjusting the baseline. In our case we’ve increased the height of the slash character to 120% and then adjusted vertically:

Text kerning in action. (Large preview) Moving Vertically

Make selection + ALT + SHIFT + ↑ ↓

Move selection vertically. (Large preview)

If you repeat the steps above on the other side we’ll by now have a pretty looking Shruggie, but what’s that, we don’t like how it aligns at all, do we?

Unaligned Shruggy, can we fix it? (Large preview)

Let’s further align this sorry looking Shruggie.

That’s what rulers are for.

3. Working With Rulers

To conjure up rulers we’re going to use another keyboard shortcut:

Display Rulers

⌘ + R

This gives you the ruler view, from which you can practically drag rulers as visual cues into your canvas.

Setting up rulers. (Large preview)

The next steps are a repetition of what we’ve done before: we’re selecting the middle part and moving it down vertically to align with Shruggie’s arms, shoulders, and hands. It looks pretty good, but let’s double-check on that first impression by zooming in!

Zoom in

You can zoom in by pressing ⌘ + +, and also by pressing on the , + . keys. In our case, we found we need to change it to properly align Shruggie’s face with his arms, which is another repetition of the above resizing and realigning skills.

Guess what? We’re now ready to animate!

Categories: Around The Web

Getting Started With Machine Learning

Smashing Magazine - Fri, 09/07/2018 - 8:00am
Getting Started With Machine Learning Getting Started With Machine Learning Alvin Wan 2018-09-07T14:00:26+02:00 2018-09-24T12:10:20+00:00

The goal of machine learning is to find patterns in data and use those patterns to make predictions. It can also give us a framework to discuss machine learning problems and solutions — as you’ll see in this article.

First, we will start with definitions and applications for machine learning. Then, we will discuss abstractions in machine learning and use that to frame our discussion: data, models, optimization models, and optimization algorithms. Later on in the article, we will discuss fundamental topics that underlie all machine learning methods and conclude with practical guidance for getting started with using machine learning. By the end, you should have an understanding of how to advance your practice and study of machine learning.

Let’s begin.

So, What Exactly Is Machine Learning?

Machine learning is generically a set of techniques to find patterns in data. Applications range from self-driving cars to personal AI assistants, from translating between French and Taiwanese to translating between voice and text. There are a few common applications of machine learning that already or could potentially permeate your day-to-day.

  1. Detecting anomalies
    Recognize spikes in website traffic or highlight abnormal bank activity.
  2. Recommend similar content
    Find products you may be looking for or even Smashing Magazine articles that are relevant.
  3. Predict the future
    Plan the path of neighboring vehicles or identify and extrapolate market trends for stocks.

The above are few of many applications of machine learning, but most applications tie back to learning the underlying distribution of data. A distribution specifies events and probability of each event. For example:

  • With 50% probability, you buy an item $5 or less.
  • With 25% probability, you buy an item $5-$10.
  • With 24% probability, you buy an item $10-100.
  • With 1% probability, you buy an item > $100.

Our new book, in which Alla Kholmatova explores how to create effective and maintainable design systems to design great digital products. Meet Design Systems, with common traps, gotchas and the lessons Alla has learned over the years.

Table of Contents →

Using this distribution, we can accomplish all of our tasks above:

  1. Detecting anomalies
    With a $100 purchase, we can confidently call this an anomaly.
  2. Recommend similar content
    A purchase of $3 means we should recommend more items $5 or less.
  3. Predict the future
    Without any prior information, we can predict that the next purchase will be $5 or less.

With a distribution of data, we can accomplish a myriad of tasks. In sum, one goal in machine learning is to learn this distribution.

Even more generically, our goal is to learn a specific function with particular inputs and outputs. We call this function our model. Our input is denoted x. Say our model, which accepts input x, is

f(x) = ax

Here, a is a parameter of our model. Each parameter corresponds to a different instance of our model. In other words, the model where a=2 is different from the model where a=3. In machine learning, our goal is to learn this parameter, changing it until we do “well.” How do we determine which values of a do “well”?

We need to define a way to evaluate our model, for each parameter a. To start, the output of f(x) is our prediction. We will refer to y as our label, meaning the true and desired output. With our predictions and our labels, we can define a loss function. One such loss function is simply the difference between our prediction and our label, |f(x) - y|. Using this loss function, we can then evaluate different parameters for our model. Picking the best parameter for our model is known as training. If we have a few possible parameters, we can simply try each parameter and pick the one with the smallest loss!

However, most problems are not as simple. What happens if there are an infinite number of different parameters? Let’s say all decimal values between 0 and 1? Between 0 and infinity? This brings us to our next topic: abstractions in machine learning. We will discuss different facets of machine learning, to compartmentalize your knowledge into data, models, objectives, and methods of solving objectives. Beyond learning the right parameter, there are plenty of other challenges: how do we break down a problem as complex as controlling a robot? How do we control a self-driving car? What does it mean to train a model that identifies faces? The section below will help you organize answers to these questions.

Abstractions

There are countless topics in machine learning — at various levels of specificity. To better understand where each piece fits in the larger picture, consider the following abstractions for machine learning. These abstractions compartmentalize our discussion of machine learning topics, and knowing them will make it easier for you to frame topics. The following classifications are taken from Professor Jonathan Shewchuck at UC Berkeley:

  1. Application and Data
    Consider the possible inputs and the desired output for the problem.
    Questions: What is your goal? How is your data structured? Are there labels? Is it reasonable for us to extract output from the provided inputs?

    Example: The goal is to classify pictures of handwritten digits. The input is an image of a handwritten number. The output is a number.
  2. Model
    Determine the class of functions under consideration.
    Questions: Are linear functions sufficient? Quadratic functions? Polynomials? What types of patterns are we interested in? Are neural networks appropriate? Logistic regression?

    Example: Linear regression
  3. Optimization Problem
    Formulate a concrete objective in mathematics.
    Questions: How do we define loss? How do we define success? Should we apply additionally penalties to bias our algorithm? Are there imbalances in the data our objective needs to consider?

    Example: Find `x` that minimizes |Ax-b|^2
  4. Optimization Algorithm
    Determine how you will solve the optimization problem.
    Questions: Can we compute a solution by hand? Do we need an iterative algorithm? Can we convert this problem to an equivalent but easier-to-solve objective, and solve that one?

    Example: Take derivative of the function. Set it to zero. Solve for our optimal parameter.
Abstraction 1: Data

In practice, collecting, managing, and packaging data is 90% of the battle. The data contains samples in which each sample is a specific realization of our input. For example, our input may generically be images of dogs. The first sample is specifically a picture of Maxie, my Bernese Mountain dog-chow chow mix at home. The second sample is specifically a picture of Charlie, a young corgi.

While training your model, it is important to handle your data properly. This means separating our data accordingly and not peeking prematurely at any set of data. In general, our data is split into three portions:

  1. Training set
    This is the dataset you train your model on. The model may see this set hundreds of times.
  2. Validation set
    This is the dataset you evaluate your model on, to assess accuracy and tune your model or method accordingly.
  3. Test set
    This is the dataset you evaluate on to assess accuracy, once at the very end. Running on the test set prematurely could mean your model overfits to the test set as well, so run only once. We will discuss the notion of “overfitting” in more detail below.
Abstraction 2: Models

Machine learning methods are split into the following two:

Supervised Learning

In supervised learning, our algorithm has access to labeled data. Still, we explore the following two classes of problems:

  • Classification
    Determine which of k classes {C_1, C_2, ... C_k} to which each sample belongs, e.g. “Which breed of dog is this?” The dog could be one of {"corgi", "bernese mountain dog", "chow chow"...}
  • Regression
    Determine a real-valued output (which are often probabilities), e.g. “What is the probability this patient has neuroblastoma (eye cancer)?”
Unsupervised Learning

In unsupervised learning, our algorithm does not have access to labels, and we explore the following classes of problems:

  • Clustering
    Cluster samples into k clusters. We do not have a label for the resulting clusters. “Which DNA sequences are most similar?”
  • Dimensionality reduction
    Reduce the number of “unique” (linearly independent) features we consider. “What are common features of faces?”
Abstraction 3: Optimization Objective

Before discussing optimization objectives and algorithms, we’ll need an example to discuss. Least squares are the canonical example. We will restrict our attention to a specific form of least squares: Let us return to our grade-school problem of fitting a line to some points.

Let’s recall the equation of a line:

y = m * x + b

Assume we have such a line. This is the true underlying model.

True model. The line that generates our data. (Large preview)

Now, sample points from this line.

True data. Data that is sampled from the true model. (Large preview)

For each point, jiggle it a little bit. In other words, add noise, which is random perturbations. This noise is due to real-world processes.

Noise. Real-world perturbations that affect our data. This may be due to imprecision in measurements, lossy compression, and so on. (Large preview)

This gives us our observed data. We will call these points (x_1, y_1), (x_2, y_2), (x_3, y_3).... This is the training data we are given to train a model on. We do not have access to the underlying line that generated this data (the original green line).

Observations. Our true data with noise and ultimately what we will use to train a model. (Large preview)

Say we have an estimate for the parameters of a line. In this case, the parameters are m and b. This gives us a predicted line, drawn in blue below.

Proposed model. The result of training a model on our observations. (Large preview)

We wish to evaluate our blue line, to see how accurate it is. To start, we use m and b to estimate y. We compute a set of ŷ values.

ŷ_i = m * x_i + b

The error for a single predicted ŷ_i and true y_i is simply

(ŷ_i−y_i)^2

Our total error is then the sum of squared differences, across all samples. This yields our loss.

∑(ŷ_i−y_i)^2

Presented visually, this is the vertical distance between our observed points and our predicted line.

Observed error. The distance between our observed data and our proposed model. (Large preview)

Plugging in ŷ_i from above, we then have the total error in terms of m and b.

∑(m * x_i + b − y_i)^2

Finally, we want to minimize this quantity. This yields our objective function, abstraction 3 from our list of abstractions above.

min_{m, b} ∑(m * x_i + b−y_i)^2

The above states in mathematics that the goal is to minimize the loss by changing values of m and b. The purpose of this section was to motivate fitting a line of best of fit, a special case of least squares. Additionally, we showed examined the least squares objective. Next, we need to solve this objective.

Abstraction 4: Optimization Algorithm

How do we minimize this? We take the derivative with respect to m`, set to 0 and solve. After solving, we obtain the analytical solution. Solving for an analytical solution was our optimization algorithm, the fourth and final abstraction in our list of abstractions.

Note: The important portion of this section is to inform you that least squares have a closed form solution, meaning that the optimal solution for our problem can be computed, explicitly. To understand why this is significant, we need to examine a problem without a closed-form solution. For example, we could never solve x=logx for a standard base-10 logarithm. Try graphing these two lines, and we see that they never intersect. In which case, we have no closed-form solution. On the other hand, ordinary least squares have a closed-form — which is good news. For any problem reduced to least squares, we can then compute the optimal solution, given our data and assumptions.

Fundamental Topics

Before studying more methods, it is necessary to understand the undercurrents of machine learning. These will govern the initial study of machine learning:

Bias-Variance Tradeoffs

One of machine learning’s most dreaded evils is overfitting in which a model is too closely tailored to the training data. In the limit, the most overfit model will memorize the data. This might mean that if one does well on exam A, one repeats every detail for exam B — down to the duration of an inter-exam restroom trip and whether or not one used the urinal.

A related but less common evil is underfitting, where the model is not sufficiently expressive to capture important information in the data. This could mean that one looks only at homework scores to predict exam scores, ignoring the effects of reading notes, completing practice exams, and more. Our goal is to build a model that generalizes to new examples while making the appropriate distinctions.

Given these two evils, there are a variety of approaches to fighting both. One is modifying your optimization objective to include a term that penalizes model complexity. Another is tuning hyperparameters that govern either your objective or your algorithm, which may correspond to notions such as “training speed” or “momentum.” The bias-variance tradeoff gives us a precise way of defining and handling both overfitting and underfitting.

Maximum Likelihood Estimation (MLE) + Maximum A Posteriori (MAP)

Say we have ice cream flavors A, B, and C. We observe different recipes. Our goal is to predict which flavor each recipe produces.

One way to predict flavors based on recipes is to first estimate the following probability:

P(flavor|recipe)

Given this probability and a new recipe, how can we predict the flavor? Given a recipe, simply consider the probability of each of the flavors A, B, C.

P(flavor=A|recipe) = 0.4 P(flavor=B|recipe) = 0.5 P(flavor=C|recipe) = 0.1

Then, pick the flavor that has the highest probability. Above, flavor B has the highest probability, given our recipe. Thus, we predict flavor B. Restating the above rule in mathematics, we have:

argmax_{flavor} P(flavor|recipe) # argmax means take the flavor that corresponds to the max value

However, the only information at our disposal is the reverse: the probability of some recipe given the flavor.

P(recipe|flavor)

For Maximum Likelihood Estimates, we make assumptions and find that the two values are proportional.

P(recipe|flavor) ~ P(flavor|recipe)

Since we’re only interested in the class with maximum probability P(flavor|recipe), we can simply find the class with maximum probability, for a proportional value P(recipe|flavor).

argmax_{flavor} P(recipe|flavor)

MLE offers the above objective as one way to predict, using the probability of data given the labels.

However, allow me to convince you that it’s reasonable to assume we have (x|y). We can estimate this from observed, real-world data. For example, say we wish to estimate the number of marbles each student in your class carries, based on the number of rubber ducks the student carries.

Each student’s number of rubber ducks is the data x, and the number of marbles she or he has is y. We will use this sample data below.

| x | y | |---|---| | 1 | 2 | | 1 | 1 | | 1 | 2 | | 2 | 1 | | 2 | 2 | | 1 | 2 |

For every y, we can compute the number of x, given us P(x|y). For the first one, P(x=1|y=1), consider all of the rows where y=1. There are 2, and only one of them has x=1. Therefore, P(x=1|y=1) = 1⁄2. We can repeat this for all values of x and y.

P(x=1|y=1) = 1/2 P(x=2|y=1) = 1/2 P(x=1|y=2) = 3/4 P(x=2|y=2) = 1/4 Featurizations, Regularization

Least squares draw lines of best fit for us. Note that least squares can fit the model anytime the model is linear in its inputs x and outputs y.

Say m=1. We have the following equation:

y = x + b

However, what if we had data that doesn’t generally follow a line? Specifically, consider a set of data sampled along a circle. Recall that the equation for a circle is:

x^2 + y^2 = r^2

Can least squares fit this well? As it stands, no. The model is not linear in its inputs x and outputs y. Instead, the model above is quadratic in x and y. However, it turns out that we can use still use least squares, just with a modification. To accomplish this, we featurize our samples.

Consider the following: what if the input to our model was x_ = x^2 and y_ = y^2? Then, our model is trying to learn the following model.

x_ + y_ = r^2

Is this linear in the model’s input x_ and output y_? Yes. Note the subtlety. The current model is still quadratic in x,y but it is linear in x_,y_. This means that least squares can fit the data if we square x^2 and y^2 before training least squares.

More generally, we can take any non-linear featurization to apply least squares to labels that are non-linear in the features. This is a fairly powerful tool, known as featurization.

However, featurizations lead to more complex models. Regularization allows us to penalize model complexity, ensuring that we do not overfit the training data.

Conclusion

In this article, you’ve touched on major topics in the fundamentals of machine learning. Using the abstractions above, you now have a framework to discuss machine learning problems and solutions. Using the fundamental topics above, you now also have quintessential concepts to learn more about, giving you the necessary tools to evaluate risk and other concerns in a machine learning application.

Further Reading

We will continue to explore these topics in depth, both the undercurrents of machine learning and specific methods. In the interim, here are resources to further your study and exploration of machine learning:

(ra, il)
Categories: Around The Web

Designing A Textbox, Unabridged

Smashing Magazine - Thu, 09/06/2018 - 7:30am
Designing A Textbox, Unabridged Designing A Textbox, Unabridged Shane Hudson 2018-09-06T13:30:16+02:00 2018-09-24T12:10:20+00:00

Ever spent an hour (or even a day) working on something just to throw the whole lot away and redo it in five minutes? That isn’t just a beginner’s code mistake; it is a real-world situation that you can easily find yourself in especially if the problem you’re trying to solve isn’t well understood to begin with.

This is why I’m such a big proponent of upfront design, user research, and creating often multiple prototypes — also known as the old adage of “You don’t know what you don’t know.” At the same time, it is very easy to look at something someone else has made, which may have taken them quite a lot of time, and think it is extremely easy because you have the benefit of hindsight by seeing a finished product.

This idea that simple is easy was summed up nicely by Jen Simmons while speaking about CSS Grid and Piet Mondrian’s paintings:

“I feel like these paintings, you know, if you look at them with the sense of like ‘Why’s that important? I could have done that.’ It's like, well yeah, you could paint that today because we’re so used to this kind of thinking, but would you have painted this when everything around you was Victorian — when everything around you was this other style?”

I feel this sums up the feeling I have about seeing websites and design systems that make complete sense; it’s almost as if the fact they make sense means they were easy to make. Of course, it is usually the opposite; writing the code is the simple bit, but it’s the thinking and process that goes into it that takes the most effort.

With that in mind, I’m going to explore building a text box, in an exaggeration of situations many of us often find ourselves in. Hopefully, by the end of this article, we can all feel more emphatic to how the journey from start to finish is rarely linear.

A Comprehensive Guide To User Testing

So you think you’ve designed something that’s perfect, but your test tells you otherwise. Let’s explore the importance of user testing. Read more →

Getting workflow just right ain’t an easy task. So are proper estimates. Or alignment among different departments. That’s why we’ve set up “this-is-how-I-work”-sessions — with smart cookies sharing what works well for them. A part of the Smashing Membership, of course.

Explore Smashing Membership ↬ Brief

We all know that careful planning and understanding of the user need is important to a successful project of any size. We also all know that all too often we feel to need to rush to quickly design and develop new features. That can often mean our common sense and best practices are forgotten as we slog away to quickly get onto the next task on the everlasting to-do list. Rinse and repeat.

Today our task is to build a text box. Simple enough, it needs to allow a user to type in some text. In fact, it is so simple that we leave the task to last because there is so much other important stuff to do. Then, just before we pack up to go home, we smirk and write:

<input type="text">

There we go!

Oh wait, we probably need to hook that up to send data to the backend when the form is submitted, like so:

<input type="text" name="our_textbox">

That’s better. Done. Time to go home.

How Do You Add A New Line?

The issue with using a simple text box is it is pretty useless if you want to type a lot of text. For a name or title it works fine, but quite often a user will type more text than you expect. Trust me when I say if you leave a textbox for long enough without strict validation, someone will paste the entire of War and Peace. In many cases, this can be prevented by having a maximum amount of characters.

In this situation though, we have found out that our laziness (or bad prioritization) of leaving it to the last minute meant we didn’t consider the real requirements. We just wanted to do another task on that everlasting to-do list and get home. This text box needs to be reusable; examples of its usage include as a content entry box, a Twitter-style note box, and a user feedback box. In all of those cases, the user is likely to type a lot of text, and a basic text box would just scroll sideways. Sometimes that may be okay, but generally, that’s an awful experience.

Thankfully for us, that simple mistake doesn’t take long to fix:

<textarea name="our_textbox"></textarea>

Now, let’s take a moment to consider that line. A <textarea>: as simple as it can get without removing the name. Isn’t it interesting, or is it just my pedantic mind that we need to use a completely different element to add a new line? It isn’t a type of input, or an attribute used to add multi-line to an input. Also, the <textarea> element is not self-closing but an input is? Strange.

This “moment to consider” sent me time traveling back to October 1993, trawling through the depths of the www-talk mailing list. There was clearly much discussion about the future of the web and what “HTML+” should contain. This was 1993 and they were discussing ideas such as <input type="range"> which wasn’t available until HTML5, and Jim Davis said:

“Well, it's far-fetched I suppose, but you might use HTML forms as part of a game playing interface.”

This really does show that the web wasn’t just intended to be about documents as is widely believed. Marc Andreessen suggested to have <input type="textarea"> instead of allowing new lines in the single-line text type, [saying]: (http://1997.webhistory.org/www.lists/www-talk.1993q4/0200.html)

“Makes the browser code cleaner — they have to be handled differently internally.”

That’s a fair reason to have <textarea> separate to text, but that’s still not what we ended up with. So why is <textarea> its own element?

I didn’t find any decision in the mailing list archives, but by the following month, the HTML+ Discussion Document had the <textarea> element and a note saying:

“In the initial design for forms, multi-line text fields were supported by the INPUT element with TYPE=TEXT. Unfortunately, this causes problems for fields with long text values as SGML limits the length of attributea literals. The HTML+ DTD allows for up to 1024 characters (the SGML default is only 240 characters!)”

Ah, so that’s why the text goes within the element and cannot be self-closing; they were not able to use an attribute for long text. In 1994, the <textarea> element was included, along with many others from HTML+ such as <option> in the HTML 2 spec.

Okay, that’s enough. I could easily explore the archives further but back to the task.

Styling A <textarea>

So we’ve got a default <textarea>. If you rarely use them or haven’t seen the browser defaults in a long time, then you may be surprised. A <textarea> (made almost purely for multi-line text) looks very similar to a normal text input except most browser defaults style the border darker, the box slightly larger, and there are lines in the bottom right. Those lines are the resize handle; they aren’t actually part of the spec so browsers all handle (pun absolutely intended) it in their own way. That generally means that the resize handle cannot be restyled, though you can disable resizing by setting resize: none to the <textarea>. It is possible to create a custom handle or use browser specific pseudo elements such as ::-webkit-resizer.

A default textarea with no styling (Large preview)

It’s important to understand the defaults, especially because of the resizing ability. It’s a very unique behavior; the user is able to drag to change the size of the element by default. If you don’t override the minimum and maximum sizes then the size could be as small as 9px × 9px (when I checked Chrome) or as large as they have patience to drag it. That’s something that could cause mayhem with the rest of the site’s layout if it’s not considered. Imagine a grid where <textarea> is in one column and a blue box is in another; the size of the blue box is purely decided by the size of the <textarea>.

Other than that, we can approach styling a <textarea> much the same as any other input. Want to change the grey around the edge into thick green dashes? Sure here you go: border: 5px dashed green;. Want to restyle the focus in which a lot of browsers have a slightly blurred box shadow? Change the outline — responsibly though, you know, that’s important for accessibility. You can even add a background image to your <textarea> if that interests you (I can think of a few ideas that would have been popular when skeuomorphic design was more celebrated).

Scope Creep

We’ve all experienced scope creep in our work, whether it is a client that doesn’t think the final version matches their idea or you just try to squeeze in a tiny tweak and end up taking forever to finish it. So I ( enjoying creating the persona of an exaggerated project manager telling us what we need to build) have decided that our <textarea> just is not good enough. Yes, it is now multi-line, and that’s great, and yes it even ‘pops’ a bit more with its new styling. Yet, it just doesn’t fit the very vague user need that I’ve pretty much just thought of now after we thought we were almost done.

What happens if the user puts in thousands of words? Or drags the resize handle so far it breaks the layout? It needs to be reusable, as we have already mentioned, but in some of the situations (such as a ‘Twittereqsue’ note taking box), we will need a limit. So the next task is to add a character limit. The user needs to be able to see how many characters they have left.

In the same way we started with <input> instead of <textarea>, it is very easy to think that adding the maxlength attribute would solve our issue. That is one way to limit the amount of characters the user types, it uses the browser’s built-in validation, but it is not able to display how many characters are left.

We started with the HTML, then added the CSS, now it is time for some JavaScript. As we’ve seen, charging along like a bull in a china shop without stopping to consider the right approaches can really slow us down in the long run. Especially in situations where there is a large refactor required to change it. So let’s think about this counter; it needs to update as the user types, so we need to trigger an event when the user types. It then needs to check if the amount of text is already at the maximum length.

So which event handler should we choose?

  • change
    Intuitively, it may make sense to choose the change event. It works on <textarea> and does what it says on the tin. Except, it only triggers when the element loses focus so it wouldn’t update while typing.
  • keypress
    The keypress event is triggered when typing any character, which is a good start. But it does not trigger when characters are deleted, so the counter wouldn’t update after pressing backspace. It also doesn’t trigger after a copy/paste.
  • keyup
    This one gets quite close, it is triggered whenever a key has been pressed (including the backspace button). So it does trigger when deleting characters, but still not after a copy/paste.
  • input
    This is the one we want. This triggers whenever a character is added, deleted or pasted.

This is another good example of how using our intuition just isn’t enough sometimes. There are so many quirks (especially in JavaScript!) that are all important to consider before getting started. So the code to add a counter that updates needs to update a counter (which we’ve done with a span that has a class called counter) by adding an input event handler to the <textarea>. The maximum amount of characters is set in a variable called maxLength and added to the HTML, so if the value is changed it is changed in only one place.

var textEl = document.querySelector('textarea') var counterEl = document.querySelector('.counter') var maxLength = 200 textEl.setAttribute('maxlength', maxLength) textEl.addEventListener('input', (val) => { var count = textEl.value.length counterEl.innerHTML = ${count}/${maxLength} }) Browser Compatibility And Progressive Enhancement

Progressive enhancement is a mindset in which we understand that we have no control over what the user exactly sees on their screen, and instead, we try to guide the browser. Responsive Web Design is a good example, where we build a website that adjusts to suit the content on the particular size viewport without manually setting what each size would look like. It means that on the one hand, we strongly care that a website works across all browsers and devices, but on the other hand, we don’t care that they look exactly the same.

Currently, we are missing a trick. We haven’t set a sensible default for the counter. The default is currently “0/200” if 200 were the maximum length; this kind of makes sense but has two downsides. The first, it doesn’t really make sense at first glance. You need to start typing before it is obvious the 0 updates as you type. The other downside is that the 0 updates as you type, meaning if the JavaScript event doesn’t trigger properly (maybe the script did not download correctly or uses JavaScript that an old browser doesn’t support such as the double arrow in the code above) then it won’t do anything. A better way would be to think carefully beforehand. How would we go about making it useful when it is both working and when it isn’t?

In this case, we could make the default text be “200 character limit.” This would mean that without any JavaScript at all, the user would always see the character limit but it just wouldn’t feedback about how close they are to the limit. However, when the JavaScript is working, it would update as they type and could say “200 characters remaining” instead. It is a very subtle change but means that although two users could get different experiences, neither are getting an experience that feels broken.

Another default that we could set is the maxlength on the element itself rather than afterwards with JavaScript. Without doing this, the baseline version (the one without JS) would be able to type past the limit.

User Testing

It’s all very well testing on various browsers and thinking about the various permutations of how devices could serve the website in a different way, but are users able to use it?

Generally speaking, no. I’m consistently shocked by user testing; people never use a site how you expect them to. This means that user testing is crucial.

It’s quite hard to simulate a user test session in an article, so for the purposes of this article, I’m going to just focus on one point that I’ve seen users struggle with on various projects.

The user is happily writing away, gets to 0 characters remaining, and then gets stuck. They forget what they were writing, or they don’t notice that it had stopped typing.

This happens because there is nothing telling the user that something has changed; if they are typing away without paying much attention, then they can hit the maximum length without noticing. This is a frustrating experience.

One way to solve this issue is to allow overtyping, so the maximum length still counts for it to be valid when submitted but it allows the user to type as much as they want and then edit it before submission. This is a good solution as it gives the control back to the user.

Okay, so how do we implement overtyping? Instead of jumping into the code, let’s step through in theory. maxlength doesn’t allow overtyping, it just stops allowing input once it hits the limit. So we need to remove maxlength and write a JS equivalent. We can use the input event handler as we did before, as we know that works on paste, etc. So in that event, the handler would check if the user has typed more than the limit, and if so, the counter text could change to say “10 characters too many.” The baseline version (without the JS) would no longer have a limit at all, so a useful middle ground could be to add the maxlength to the element in the HTML and remove the attribute using JavaScript.

That way, the user would see that they are over the limit without being cut off while typing. There would still need to be validation to make sure it isn’t submitted, but that is worth the extra small bit of work to make the user experience far better.

Allowing the user to overtype (Large preview) Designing The Overtype

This gets us to quite a solid position: the user is now able to use any device and get a decent experience. If they type too much it is not going to cut them off; instead, it will just allow it and encourage them to edit it down.

There’s a variety of ways this could be designed differently, so let’s look at how Twitter handles it:

Twitter's <textarea> (Large preview)

Twitter has been iterating its main tweet <textarea> since they started the company. The current version uses a lot of techniques that we could consider using.

As you type on Twitter, there is a circle that completes once you get to the character limit of 280. Interestingly, it doesn’t say how many characters are available until you are 20 characters away from the limit. At that point, the incomplete circle turns orange. Once you have 0 characters remaining, it turns red. After the 0 characters, the countdown goes negative; it doesn’t appear to have a limit on how far you can overtype (I tried as far as 4,000 characters remaining) but the tweet button is disabled while overtyping.

So this works the same way as our <textarea> does, with the main difference being the characters represented by a circle that updates and shows the number of characters remaining after 260 characters. We could implement this by removing the text and replacing it with an SVG circle.

The other thing that Twitter does is add a red background behind the overtyped text. This makes it completely obvious that the user is going to need to edit or remove some of the text to publish the tweet. It is a really nice part of the design. So how would we implement that? We would start again from the beginning.

You remember the part where we realized that a basic input text box would not give us multiline? And that a maxlength attribute would not give us the ability to overtype? This is one of those cases. As far as I know, there is nothing in CSS that gives us the ability to style parts of the text inside a <textarea>. This is the point where some people would suggest web components, as what we would need is a pretend <textarea>. We would need some kind of element — probably a div — with contenteditable on it and in JS we would need to wrap the overtyped text in a span that is styled with CSS.

What would the baseline non-JS version look like then? Well, it wouldn’t work at all because while contenteditable will work without JS, we would have no way to actually do anything with it. So we would need to have a <textarea> by default and remove that if JS is available. We would also need to do a lot of accessibility testing because while we can trust a <textarea> to be accessible relying on browser features is a much safer bet than building your own components. How does Twitter handle it? You may have seen it; if you are on a train and your JavaScript doesn’t load while going into a tunnel then you get chucked into a decade-old legacy version of Twitter where there is no character limit at all.

What happens then if you tweet over the character limit? Twitter reloads the page with an error message saying “Your Tweet was over the character limit. You’ll have to be more clever.” No, Twitter. You need to be more clever.

Retro

The only way to conclude this dramatization is a retrospective. What went well? What did we learn? What would we do differently next time or what would we change completely?

We started very simple with a basic textbox; in some ways, this is good because it can be all too easy to overcomplicate things from the beginning and an MVP approach is good. However, as time went on, we realized how important it is to have some critical thinking and to consider what we are doing. We should have known a basic textbox wouldn’t be enough and that a way of setting a maximum length would be useful. It is even possible that if we have conducted or sat in on user research sessions in the past that we could have anticipated the need to allow overtyping. As for the browser compatibility and user experiences across devices, considering progressive enhancement from the beginning would have caught most of those potential issues.

So one change we could make is to be much more proactive about the thinking process instead of jumping straight into the task, thinking that the code is easy when actually the code is the least important part.

On a similar vein to that, we had the “scope creep” of maxlength, and while we could possibly have anticipated that, we would rather not have any scope creep at all. So everybody involved from the beginning would be very useful, as a diverse multidisciplinary approach to even small tasks like this can seriously reduce the time it takes to figure out and fix all the unexpected tweaks.

Back To The Real World

Okay, so I can get quite deep into this made-up project, but I think it demonstrates well how complicated the most seemingly simple tasks can be. Being user-focussed, having a progressive enhancement mindset, and thinking things through from the beginning can have a real impact on both the speed and quality of delivery. And I didn’t even mention testing!

I went into some detail about the history of the <textarea> and which event listeners to use, some of this can seem overkill, but I find it fascinating to gain a real understanding of the subtleties of the web, and it can often help demystify issues we will face in the future.

(ra, il)
Categories: Around The Web

Preparing Your App For iOS 12 Notifications

Smashing Magazine - Wed, 09/05/2018 - 7:30am
Preparing Your App For iOS 12 Notifications Preparing Your App For iOS 12 Notifications Kaya Thomas 2018-09-05T13:30:35+02:00 2018-09-24T12:10:20+00:00

In 2016, Apple announced a new extension that will allow developers to better customize their push and local notifications called the UNNotificationContentExtension. The extension gets triggered when a user long presses or 3D touches on a notification whenever it is delivered to the phone or from the lock/home screen. In the content extension, developers can use a view controller to structure the UI of their notification, but there was no user interaction enabled within the view controller — until now. With the release of iOS 12 and XCode 10, the view controller in the content extension now enables user interaction which means notifications will become even more powerful and customizable.

At WWDC 2018, Apple also announced several changes to notification settings and how they appear on the home screen. In an effort to make users more aware of how they are using apps and allowing more user control of their app usage, there is a new notification setting called “Deliver Quietly.” Users can set your app to Delivery Quietly from the Notification Center, which means they will not receive banners or sound notifications from your app, but they will appear in the Notification Center. Apple using an in-house algorithm, which presumably tracks often you interact with notifications, will also ask users if they still want to receive notifications from particular apps and encourage you to turn on Deliver Quietly or turn them off completely.

Notifications are getting a big refresh in iOS 12, and I’ve only scratched the surface. In the rest of this article, we’ll go over the rest of the new notification features coming to iOS 12 and how you can implement them in your own app.

Recommended reading: WWDC 2018 Diary Of An iOS Developer

Remote vs Local Notifications

There are two ways to send push notifications to a device: remotely or locally. To send notifications remotely, you need a server that can send JSON payloads to Apple’s Push Notification Service. Along with a payload, you also need to send the device token and any other authentication certificate or tokens that verify your server is allowed to send the push notification through Apple. For this article, we focus on local notifications which do not need a separate server. Local notifications are requested and sent through the UNUserNotificationCenter. We’ll go over later how specifically to make the request for a local notification.

In order to send a notification, you first need to get permission from the user on whether or not they want you to send them notifications. With the release of iOS 12, there are a lot of changes to notification settings and permissions so let’s break it down. To test out any of the code yourself, make sure you have the Xcode 10 beta installed.

Meet SmashingConf New York 2018 (Oct 23–24), focused on real challenges and real front-end solutions in the real world. From progressive web apps, Webpack and HTTP/2 to serverless, Vue.js and Nuxt — all the way to inclusive design, branding and machine learning. With Sarah Drasner, Sara Soueidan and many other speakers.

Check all topics and speakers ↬ Notification Settings And Permissions Deliver Quietly

Delivery Quietly is Apple’s attempt to allow users more control over the noise they may receive from notifications. Instead of going into the settings app and looking for the app whose notification settings you want to change, you can now change the setting directly from the notification. This means that a lot more users may turn off notifications for your app or just delivery them quietly which means the app will get badged and notifications only show up in the Notification Center. If your app has its own custom notification settings, Apple is allowing you to link directly to that screen from the settings management view pictured below.

Delivery quietly feature. (Large preview)

In order to link to your custom notification setting screen, you must set providesAppNotificationSettings as a UNAuthorizationOption when you are requesting notification permissions in the app delegate.

In didFinishLaunchingWithOptions, add the following code:

UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .badge, .sound, .providesAppNotificationSettings]) { ... }

When you do this, you’ll now see your custom notification settings in two places:

  • If the user selects Turn Off when they go to manage settings directly from the notification;
  • In the notification settings within the system’s Settings app.
Deep link to to custom notification settings for NotificationTester from notification in the Notification Center. (Large preview) Deep link to custom notification settings for NotificationTester from system’s Settings app. (Large preview)

You also have to make sure to handle the callback for when the user selects on either way to get to your notification settings. Your app delegate or an extension of your app delegate has to conform to the protocol UNUserNotificationCenterDelegate so you can then implement the following callback method:

func userNotificationCenter(_ center: UNUserNotificationCenter, openSettingsFor notification: UNNotification?) { let navController = self.window?.rootViewController as! UINavigationController let notificationSettingsVC = NotificationSettingsViewController() navController.pushViewController(notificationSettingsVC, animated: true) }

Another new UNAuthorizationOption is provisional authorization. If you don’t mind your notifications being delivered quietly, you can set add .provisional to your authorization options as shown below. This means that you don’t have to prompt the user to allow notifications — the notifications will still show up in the Notification Center.

UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .badge, .provisional]) { ... }

So now that you’ve determined how to request permission from the user to deliver notifications and how to navigate users to your own customized settings view, let’s go more into more detail about the actual notifications.

Sending Grouped Notifications

Before we get into the customization of the UI of a notification, let’s go over how to make the request for a local notification. First, you have to register any UNNotificationCategory, which are like templates for the notifications you want to send. Any notification set to a particular category will inherit any actions or options that were registered with that category. After you’ve requested permission to send notifications in didFinishLaunchingWithOptions, you can register your categories in the same method.

let hiddenPreviewsPlaceholder = "%u new podcast episodes available" let summaryFormat = "%u more episodes of %@" let podcastCategory = UNNotificationCategory(identifier: "podcast", actions: [], intentIdentifiers: [], hiddenPreviewsBodyPlaceholder: hiddenPreviewsPlaceholder, categorySummaryFormat: summaryFormat, options: []) UNUserNotificationCenter.current().setNotificationCategories([podcastCategory])

In the above code, I start by initiating two variables:

  • hiddenPreviewsPlaceholder
    This placeholder is used in case the user has “Show Previews” off for your app; if we don’t have a placeholder there, your notification will show with only “Notification” also the text.
  • summaryFormat
    This string is new for iOS 12 and coincides with the new feature called “Group Notifications” that will help the Notification Center look a lot cleaner. All notifications will show up in stacks which will be either representing all notifications from the app or specific groups that the developer has set for there app.

The code below shows how we associate a notification with a group.

@objc func sendPodcastNotification(for podcastName: String) { let content = UNMutableNotificationContent() content.body = "Introducing Season 7" content.title = "New episode of \(podcastName):" content.threadIdentifier = podcastName.lowercased() content.summaryArgument = podcastName content.categoryIdentifier = NotificationCategoryType.podcast.rawValue sendNotification(with: content) }

For now, I’ve hardcoded the text of the notification just for the example. The threadIdentifier is what creates the groups that we show as stacks in the Notification Center. In this example, I want the notifications grouped by podcast so each notification you get is separated by what podcast it’s associated with. The summaryArgument matches back to our categorySummaryFormat we set in the app delegate. In this case, we want the string for the format: "%u more episodes of %@" to be the podcast name. Lastly, we have to set the category identifier to ensure the notification has the template we set in the app delegate.

func sendNotification(for category: String, with content: UNNotificationContent) { let uuid = UUID().uuidString let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 5, repeats: false) let request = UNNotificationRequest(identifier: uuid, content: content, trigger: trigger) UNUserNotificationCenter.current().add(request, withCompletionHandler: nil) }

The above method is how we request the notification to be sent to the device. The identifier for the request is just a random unique string; the content is passed in and we create the content in our sendPodcastNotification method, and lastly, the trigger is when you want the notification to send. If you want the notification to send immediately, you can set that parameter to nil.

Grouped notifications for NotificationTester. (Large preview) Notification grouped with previews turned off. (Large preview)

Using the methods we’ve described above, here’s the result on the simulator. I have a button that has the sendPodcastNotification method as a target. I tapped the button three times to have the notifications sent to the device. In the first photo, I have “Show Previews” set to “Always” so I see the podcast and the name of the new episodes along with the summary that shows I have two more new episodes to check out. When “Show Previews” is set to “Never,” the result is the second image above. The user won’t see which podcast it is to respect the “No Preview” setting, but they can still see that I have three new episodes to check out.

Notification Content Extension

Now that we understand how to set our notification categories and make the request for them to be sent, we can go over how to customize the look of the notification using the Notification Service and Notification Content extensions. The Notification Service extension allows you to edit the notification content and download any attachments in your notification like images, audio or video files. The Notification Content extension contains a view controller and storyboard that allows you to customize the look of your notification as well as handle any user interaction within the view controller or taps on notification actions.

To add these extensions to your app go File →  New →  Target.

Adding new target to app for the Notification Content Extension. (Large preview)

You can only add them one at a time, so name your extension and repeat the process to add the other. If a pop-up appears asking you to activate your new scheme, click the “Activate” button to set it up for debugging.

For the purpose of this tutorial, we will be focusing on the Notification Content Extension. For local notifications, we can include the attachments in the request, which we’ll go over later.

First, go to the Info.plist file in the Notification Content Extension target.

Info.plist for the Notification Content Extension. (Large preview)

The following attributes are required:

  • UNNotificationExtensionCategory
    A string value equal to the notification category which we created and set in the app delegate. This will let the content extension know which notification you want to have custom UI for.
  • UNNotificationExtensionInitialContentSizeRatio
    A number between 0 and 1 which determines the aspect ratio of your UI. The default value is 1 which will allow your interface to have its total height equal to its width.

I’ve also set UNNotificationExtensionDefaultContentHidden to “YES” so that the default notification does not show when the content extension is running.

You can use the storyboard to set up your view or create the UI programmatically in the view controller. For this example I’ve set up my storyboard with an image view which will show the podcast logo, two labels for the title and body of the notification content, and a “Like” button which will show a heart image.

Now, in order to get the image showing for the podcast logo and the button, we need to go back to our notification request:

guard let pathUrlForPodcastImg = Bundle.main.url(forResource: "startup", withExtension: "jpg") else { return } let imgAttachment = try! UNNotificationAttachment(identifier: "image", url: pathUrlForPodcastImg, options: nil) guard let pathUrlForButtonNormal = Bundle.main.url(forResource: "heart-outline", withExtension: "png") else { return } let buttonNormalStateImgAtt = try! UNNotificationAttachment(identifier: "button-normal-image", url: pathUrlForButtonNormal, options: nil) guard let pathUrlForButtonHighlighted = Bundle.main.url(forResource: "heart-filled", withExtension: "png") else { return } let buttonHighlightStateImgAtt = try! UNNotificationAttachment(identifier: "button-highlight-image", url: pathUrlForButtonHighlighted, options: nil) content.attachments = [imgAttachment, buttonNormalStateImgAtt, buttonHighlightStateImgAtt]

I added a folder in my project that contains all the images we need for the notification so we can access them through the main bundle.

Xcode project navigator. (Large preview)

For each image, we get the file path and use that to create a UNNotificationAttachment. Added that to our notification content allows us to access the images in the Notification Content Extension in the didReceive method shown below.

func didReceive(_ notification: UNNotification) { self.newEpisodeLabel.text = notification.request.content.title self.episodeNameLabel.text = notification.request.content.body let imgAttachment = notification.request.content.attachments[0] let buttonNormalStateAtt = notification.request.content.attachments[1] let buttonHighlightStateAtt = notification.request.content.attachments[2] guard let imageData = NSData(contentsOf: imgAttachment.url), let buttonNormalStateImgData = NSData(contentsOf: buttonNormalStateAtt.url), let buttonHighlightStateImgData = NSData(contentsOf: buttonHighlightStateAtt.url) else { return } let image = UIImage(data: imageData as Data) let buttonNormalStateImg = UIImage(data: buttonNormalStateImgData as Data)?.withRenderingMode(.alwaysOriginal) let buttonHighlightStateImg = UIImage(data: buttonHighlightStateImgData as Data)?.withRenderingMode(.alwaysOriginal) imageView.image = image likeButton.setImage(buttonNormalStateImg, for: .normal) likeButton.setImage(buttonHighlightStateImg, for: .selected) }

Now we can use the file path URLs we set in the request to grab the data for the URL and turn them into images. Notice that I have two different images for the different button states which will allow us to update the UI for user interaction. When I run the app and send the request, here’s what the notification looks like:

Content extension loaded for NotificationTester app. (Large preview)

Everything I’ve mentioned so far in relation to the content extension isn’t new in iOS 12, so let’s dig into the two new features: User Interaction and Dynamic Actions. When the content extension was first added in iOS 10, there was no ability to capture user touch within a notification, but now we can register UIControl events and respond when the user interacts with a UI element.

For this example, we want to show the user that the “Like” button has been selected or unselected. We already set the images for the .normal and .selected states, so now we just need to add a target for the UIButton so we can update the selected state.

override func viewDidLoad() { super.viewDidLoad() // Do any required interface initialization here. likeButton.addTarget(self, action: #selector(likeButtonTapped(sender:)), for: .touchUpInside) } @objc func likeButtonTapped(sender: UIButton) { likeButton.isSelected = !sender.isSelected }

Now with the above code we get the following behavior:

Selecting like button within notification. (Large preview)

In the selector method likeButtonTapped, we could also add any logic for saving the liked state in User Defaults or the Keychain, so we have access to it in our main application.

Notification actions have existed since iOS 10, but once you click on them, usually the user will be rerouted to the main application or the content extension is dismissed. Now in iOS 12, we can update the list of notification actions that are shown in response to which action the user selects.

First, let’s go back to our app delegate where we create our notification categories so we can add some actions to our podcast category.

let playAction = UNNotificationAction(identifier: "play-action", title: "Play", options: []) let queueAction = UNNotificationAction(identifier: "queue-action", title: "Queue Next", options: []) let podcastCategory = UNNotificationCategory(identifier: "podcast", actions: [playAction, queueAction], intentIdentifiers: [], hiddenPreviewsBodyPlaceholder: hiddenPreviewsPlaceholder, categorySummaryFormat: summaryFormat, options: [])

Now when we run the app and send a notification, we see the following actions shown below:

Notification quick actions. (Large preview)

When the user selects “Play,” we want the action to be updated to “Pause.” If they select “Queue Next,” we want that action to be updated to “Remove from Queue.” We can do this in our didReceive method in the Notification Content Extension’s view controller.

func didReceive(_ response: UNNotificationResponse, completionHandler completion: (UNNotificationContentExtensionResponseOption) -> Void) { guard let currentActions = extensionContext?.notificationActions else { return } if response.actionIdentifier == "play-action" { let pauseAction = UNNotificationAction(identifier: "pause-action", title: "Pause", options: []) let otherAction = currentActions[1] let newActions = [pauseAction, otherAction] extensionContext?.notificationActions = newActions } else if response.actionIdentifier == "queue-action" { let removeAction = UNNotificationAction(identifier: "remove-action", title: "Remove from Queue", options: []) let otherAction = currentActions[0] let newActions = [otherAction, removeAction] extensionContext?.notificationActions = newActions } else if response.actionIdentifier == "pause-action" { let playAction = UNNotificationAction(identifier: "play-action", title: "Play", options: []) let otherAction = currentActions[1] let newActions = [playAction, otherAction] extensionContext?.notificationActions = newActions } else if response.actionIdentifier == "remove-action" { let queueAction = UNNotificationAction(identifier: "queue-action", title: "Queue Next", options: []) let otherAction = currentActions[0] let newActions = [otherAction, queueAction] extensionContext?.notificationActions = newActions } completion(.doNotDismiss) }

By resetting the extensionContext?.notificationActions list to contain the updated actions, it allows us to change the actions every time the user selects one. The behavior is shown below:

Dynamic notification quick actions. (Large preview) Summary

There’s a lot to do before iOS 12 launches to make sure your notifications are ready. The steps vary in complexity and you don’t have to implement them all. Make sure to first download XCode 10 beta so you can try out the features we’ve gone over. If you want to play around with the demo app I’ve referenced throughout the article, check it out on Github.

For Your Notification Permissions Request And Settings, You’ll Need To:
  • Determine whether or not you want to enable provisional authorization and add it to your authorization options.
  • If you have already have a customized notification settings view in your app, add providesAppNotificationSettings to your authorization options as well as implement the call back in your app delegate or whichever class conforms to UNUserNotificationCenterDelegate.
For Notification Grouping:
  • Add a thread identifier to your remote and local notifications so your notifications are correctly grouped in the Notification Center.
  • When registering your notification categories, add the category summary parameter if you want your grouped notification to be more descriptive than “more notifications.”
  • If you want to customize the summary text even more, then add a summary identifier to match whichever formatting you added for the category summary.
For Customized Rich Notifications:
  • Add the Notification Content extension target to your app to create rich notifications.
  • Design and implement the view controller to contain whichever elements you want in your notification.
  • Consider which interactive elements would be useful to you, i.e. buttons, table view, switches, etc.
  • Update the didReceive method in the view controller to respond to selected actions and update the list of actions if necessary.
Further Reading (ra, yk, il)
Categories: Around The Web

Take A New Look At CSS Shapes

Smashing Magazine - Tue, 09/04/2018 - 7:30am
Take A New Look At CSS Shapes Take A New Look At CSS Shapes Rachel Andrew 2018-09-04T13:30:57+02:00 2018-09-24T12:10:20+00:00

CSS Shapes Level 1 has been available in Chrome and Safari for a number of years, however, this week it ships in a production version of Firefox with the release of Firefox 62 — along with a very nice addition to the Firefox DevTools to help us work with Shapes. In this article, I’ll take a look at some of the things you can do with CSS Shapes. Perhaps it’s time to consider adding some curves to your designs?

What Are CSS Shapes?

The CSS Shapes specification Level 1 defines three new properties:

  • shape-outside
  • shape-image-threshold
  • shape-margin

The purpose of this specification is to allow content to flow around a non-rectangular shape, something which is quite unusual on our boxy web. There are a few different ways to create shapes, which we will have a look at in this tutorial. We will also have a look at the Shape Path Editor, available in Firefox, as it can help you to easily understand the shapes on your page and work with them.

In the current specification, shapes can only be applied to a float, so any shapes example needs to start with a floated element. In the example below, I have a PNG image with a transparent background in which I have floated the image left. The text that follows the image now flows around the right and bottom of my image.

What I would like to happen is for my content to follow the shape of the opaque part of the image, rather than follow the line of the physical image file. To do this, I use the shape-outside property, with the value being the URL of my image. I’m using the actual image file to create a path for the content to flow around.

See the Pen Smashing Shapes: image by Rachel Andrew (@rachelandrew) on CodePen.

Note that your image needs to be CORS compatible, so hosted on the same server as the rest of your content or sending the correct headers if hosted on a CDN. Browser DevTools will usually tell you if your image is being blocked due to CORS.

This method of creating shapes uses the alpha channel of the image to create the shape, as we have a shape with a fully transparent area, then all we need do is pass the URL of the image to shape-outside and the shape path follows the line of the fully opaque area.

Front-end is messy and complicated these days. That's why we publish articles, printed books and webinars with useful techniques to improve your work. Even better: Smashing Membership with a growing selection of front-end & UX goodies. So you get your work done, better and faster.

Explore Smashing Membership ↬ Creating A Margin

To push the line of the text away from the image we can use the shape-margin property. This creates a margin between the line of the shape and the content running alongside it.

See the Pen Smashing Shapes: shape-margin by Rachel Andrew (@rachelandrew) on CodePen.

Using Generated Content For Our Shape

In the case above, we have the image displayed on the page and then the text curved around it. However, you could also use an image as the path for the shape in order to create a curved text effect without also including the image on the page. You still need something to float, however, and so for this, we can use Generated Content.

See the Pen Smashing Shapes: generated content by Rachel Andrew (@rachelandrew) on CodePen.

In this example, we have inserted some generated content, floated it left, given it a width and a height and then used shape-outside with our image just as before. We then get a curved line against the whitespace, but no visible image.

Using A Gradient For Our Shape

A CSS gradient is just like an image, which means we can use a gradient to create a shape, which can make for some interesting effects. In this next example, I have created a gradient which goes from blue to transparent; your gradient will need to have a transparent or semi-transparent area in order to use shapes. Once again, I have used generated content to add the gradient and am then using the gradient in the value for shape-outside.

Once the gradient becomes fully transparent, then the shape comes into play, and the content runs along the edge of the gradient.

See the Pen Smashing Shapes: gradients by Rachel Andrew (@rachelandrew) on CodePen.

Using shape-image-threshold To Position Text Over A Semi-Opaque Image

So far we have looked at using a completely transparent part of an image or of a gradient in order to create our shape, however, the third property defined in the CSS Shapes specification means that we can use images or gradients with semi-opaque areas by setting a threshold. A value for shape-image-threshold of 1 means fully opaque while 0 means fully transparent.

A gradient like our example above is a great way to see this in action as we can change the shape-image-threshold value and move the line along which the text falls to more opaque areas or more transparent areas. This property works in exactly the same way with an image that has an alpha channel yet is not fully transparent.

See the Pen Smashing Shapes: shape-image-threshold by Rachel Andrew (@rachelandrew) on CodePen.

This method of creating shapes from images and gradients is — I think — the most straightforward way of creating a shape. You can create a shape as complex as you need it to be, in the comfort of a graphics application and then use that to define the shape on your page. That said, there is another way to create our shapes, and that’s by using Basic Shapes.

CSS Shapes With Basic Shapes

The Basic Shapes are a set of predefined shapes which cover a lot of different types of shapes you might want to create. To use a basic shape, you use the basic shape type as a value for shape-outside. This type uses functional notation, so we have the name of the shape followed by brackets (inside which are some values for our shape).

The options that you have are the following:

  • inset()
  • circle()
  • ellipse()
  • polygon()

We will take a look at the circle() type first as we can use this to understand some useful things which apply to all shapes which use the basic shape type. We will also have a look at the new tools in Firefox for inspecting these shapes.

In the example below, I am creating the most simple of shapes: a circle using shape-outside: circle(50%). I’m using generated content again, and I have given the box a background color, and also added a margin, border, and padding to help highlight some of the concepts of using CSS Shapes. You can see in the example that the circle is created centered on the box; this is because I have given the circle a value of 50%. That value is the <shape-radius> which can be a length or a percentage. I’ve used a percentage so that the radius is half of the size of my box.

See the Pen Smashing Shapes: shape-outside: circle() by Rachel Andrew (@rachelandrew) on CodePen.

This is a really good to time have a look at the shape that has been created using the Firefox Shape Path Editor. You can inspect the shape by clicking on the generated content and then clicking the little shape icon next to the property shape-outside; your shape will now highlight.

The Shape Path Editor highlights the circle shape (Large preview)

You can see how the circle extends to the edge of the margin on our box. This is because the initial reference box used by our shape is margin-box. You already know something of reference boxes if you have ever added box-sizing: border-box to your CSS. When you do this, you are asking CSS to use the border-box and not the default content-box as the size of elements. In Shapes, we can also change which reference box is used. After any basic shape, add border-box to use the border to define the shape or content-box to use the edge of the content (inside the padding). For example:

.content::before { content: ""; width: 150px; height: 150px; margin: 20px; padding: 20px; border: 10px solid #FC466B; background: linear-gradient(90deg, #FC466B 0%, #3F5EFB 100%); float: left; circle(50%) content-box; }

You will see the circle appear to become much smaller. It is now using the width of the content — in this case the width of the box at 150px — rather than the margin box which includes the padding, border, and margin.

The content-box is the edge of the content of the square we created with our generated content (Large preview)

Inspecting your element in Firefox DevTools will also show you the reference boxes so you can choose which might give you the best result with your particular shape.

Reference boxes highlighted in Firefox (Large preview) The Position Value

A second value can be passed to circle() which is a position; if you do not pass this value, it defaults to center. However, you can use this value to pull your circle around. In the next example, I have positioned the circle by using shape-outside(50% at 30%); this changes where the center of the circle is positioned.

See the Pen Smashing Shapes: circle() with position by Rachel Andrew (@rachelandrew) on CodePen.

clip-path

Something useful to know is that the same <basic-shape> values can be used as a value for clip-path. This means that after creating a shape, you can clip away the image or background color that extends outside of the shape. In the example below, I am going to do this with our example gradient background, so that we end up with a circle that has text curved around from our square box.

See the Pen Smashing SHapes: circle() with clip-path by Rachel Andrew (@rachelandrew) on CodePen.

All of the above concepts can be applied to our other basic shapes. Now let’s have a quick look at how they work.

inset()

The inset() value defines a rectangle. This might not seem very useful as a float is a rectangle, however, this value means that you can inset the content wrapping your shape. It takes four values for top, right, bottom, and left plus a final value which defines a border radius.

In the example below, I am using the values to inset the content on the right and bottom of the floated image, plus adding a border radius around which my content will wrap using shape-outside: inset(0 30px 100px 0 round 40px). You can see how the content is now over the background color of the box:

See the Pen Smashing Shapes: inset() by Rachel Andrew (@rachelandrew) on CodePen.

ellipse()

An ellipse is a squashed circle and as such needs two radii for x and y (in that order). You can then push the ellipse around just as with circle using the position value. In the example below, I am creating an ellipse and then using clip-path with the same values to remove the content outside of my shape.

See the Pen Smashing Shapes: ellipse() by Rachel Andrew (@rachelandrew) on CodePen.

In the above example, I also used shape-margin to demonstrate how we can use this property as with our image generated shapes to push the content away.

polygon()

Creating polygon shapes gives us the most flexibility, as our shapes can be created with three or more points. The value passed to the polygon needs to be three or more pairs of values which represent coordinates.

It is here where the Firefox tools become really useful as we can use them to help create our polygon. In the below example, I have created a polygon with four points. In the Firefox DevTools, you can double-click on any line to create a new point, and double-click again to remove it. Once you have created a polygon that you are happy with, you can then copy the value out of DevTools for your CSS.

See the Pen Smashing Shapes: polygon() by Rachel Andrew (@rachelandrew) on CodePen.

Fallbacks

As CSS Shapes are applied to a float, in many cases the fallback is that instead of seeing the content wrap around a shape, the content will wrap around a floated element (in the way that content has always wrapped around floats). Browsers ignore properties they do not understand, so if they don’t understand Shapes, it doesn’t matter that the shape-outside property is there.

Where you should take care would be in any situation where not having shapes could mean that content overlaid an area which made it difficult to read. Perhaps you are using Shapes to push content away from a busy area of a background image, for example. In that case, you should first make sure that your content is usable for the non-Shapes people, then use Feature Queries to check for support of shape-outside and overwrite that CSS and apply the shape. For example, you could use a margin to push the content away for non-Shapes visitors and remove the margin inside your feature query.

.content { margin-left: 120px; } @supports (shape-outside: circle()) { .content { margin-left: 0; /* add the rest of your shapes CSS here */ } }

With Firefox releasing their support we now only have one main browser without support for Shapes — Edge. If you want to see Shapes support across the board you could go and vote for the feature here, and see if we can encourage the implementation of the feature in Edge.

Find Out More About CSS Shapes

In this article, I’ve tried to give a quick overview of some of the interesting things that are possible with CSS Shapes. For a more in-depth look at each feature, check out the Guides to CSS Shapes over at MDN. You can also read a guide to the Shape Path Editor in Firefox.

(il)
Categories: Around The Web

Get Your Mobile Site Ready For The 2018 Holiday Season

Smashing Magazine - Mon, 09/03/2018 - 8:30am
Get Your Mobile Site Ready For The 2018 Holiday Season Get Your Mobile Site Ready For The 2018 Holiday Season Suzanne Scacca 2018-09-03T14:30:43+02:00 2018-09-24T12:10:20+00:00

After reading the title of this article, it might seem like it’s jumping the gun, but with retailers turning on holiday music and putting out holiday-related displays earlier and earlier every year, your consumers are primed to start thinking about the holidays earlier, too. In fact, a study done by the Tampa Bay Times revealed that in-store shoppers were exposed to holiday music as early as October 22 in 2017.

Results from TBT’s survey on when holiday music starts (Source: Tampa Bay Times) (Large preview)

Of course, e-commerce handles the holiday season a bit differently than brick-and-mortar. It’s not really necessary to announce promotions or run sales in late October or early November. However, that doesn’t mean you should wait until the last minute to prepare your mobile website for the holidays.

In this article, I’m going to give you a quick rundown of what happened during the 2017 holiday sales season and, in particular, what role mobile played in it. Then, we’re going to dig into holiday design and marketing tactics you can use to boost sales through your mobile website for the 2018 holiday season.

Recommended reading: How Mobile Web Design Affects Local Search (And What To Do About It)

A Recap Of The 2017 Holiday Sales Season

Before we get started, I want to quickly add a disclaimer:

This particular section focuses on e-commerce statistics because this kind of data is readily available. Something like the total number of page visits, subscribed readers, and leads generated... well, it’s not.

So, although I only use data to express how important mobile was to 2017 holiday sales, keep in mind that the tips that follow pertain to all websites. Even if your site doesn’t expressly sell goods or services, blogs and other content-driven sites can take advantage of this, too!

Front-end is messy and complicated these days. That's why we publish articles, printed books and webinars with useful techniques to improve your work. Even better: Smashing Membership with a growing selection of front-end & UX goodies. So you get your work done, better and faster.

Explore Smashing Membership ↬

Now, let’s take a look at the numbers:

Total Retail Sales

The National Retail Federation calculated the total amount of retail sales--online and in-store--to be $691.9 billion between November and December, a 5.5% bump from 2016.

Total e-Commerce Sales

Adobe put the total amount of e-commerce sales during that same timeframe at $108.15 billion in 2017.

Adobe’s stats on 2016 and 2017 holiday e-commerce revenue (Source: Adobe) (Large preview) e-Commerce Sales By Device

Adobe takes it even further and breaks down the share of revenue by device:

Breakdown of desktop, smartphone and tablet sales for 2017 holiday season (Source: Adobe) (Large preview) e-Commerce Sales vs. Traffic

While smartphone and tablet sales still trail those on desktop, there are a couple interesting things to note here. For starters, desktop revenue has mostly flatlined year-over-year whereas mobile continues to grow. In addition, there’s an interesting disparity between how much traffic comes from each device and what percentage of revenue it generates:

Traffic vs. revenue for desktop, smartphone, tablet (Source: Adobe) (Large preview)

Pay close attention to desktop and smartphone. As you can see, more visits stem from smartphones than any other device and, yet, desktop leads the way in conversions:

Statista shows the breakdown between desktop, smartphone, and tablet conversions in Q1 2018 (Source: Statista) (Large preview)

Is this indicative of a lack of trust in smart devices to handle purchases?

In all likelihood, it probably isn’t. Data from other sources indicates that on holidays, in particular, mobile reigns supreme in terms of visits and conversions:

  • Thanksgiving Day: 62% of traffic / 46% of purchases.
  • Christmas Day: 68% of traffic / 50% of purchases.

Also, let’s not forget to take into account the strengths of mobile devices within the shopper’s experience. According to the four micro-moments as defined by Google, a large number of mobile users commonly search for the following:

  • “I want to know.”
  • “I want to go.”
  • “I want to do.”
  • “I want to buy.”

The second and third are clearly indicative of a searcher’s desire to find something outside their devices (and their homes) to spend money on. That might even be so for the fourth, though it could also be an indication that they want to do their research on mobile and complete the purchase on desktop.

Either way, we know that smartphones tend to be a primary facilitator in the customer’s journey and not something that’s putting an end to the shopping experience as a whole.

Recommended reading: Designing For Micro-Moments

5 Tips To Prepare Your Mobile Site For The 2018 Holiday Season

While the overall numbers indicate that desktop is the leading platform for holiday sales, it’s not a universal rule that can be applied to each and every day in November and December. This is why your own data will have to play a big role in the design choices you make for your mobile site this season.

You have to admit, no matter how stressed or unhappy you might feel around the holidays, there is something nice about encountering just the right hint of holiday “cheer”. And that’s one of the keys to doing this right: finding the right amount of holiday flavor to infuse into your website.

Before we get into what you can do to spruce up your mobile web design, I want to remind you that security and speed are critical elements to check off your list before November gets here. These might not be in your realm of responsibilities, but that doesn’t mean you shouldn’t keep an eye on them.

If you’re doing all this design work in anticipation of boosting conversions over the holidays, don’t let it all be for nothing by forgetting about performance and security essentials. To protect your site from potentially harmful traffic surges, start with this front-end performance checklist. With regards to security, you can use these security improvement tips.

Now, let’s talk about the five ways in which you can prepare your mobile website for the 2018 holiday season:

1. Study Last Year’s Data

If your website has been live and actively doing business for more than a year, you need to start with the data from 2017. Using Google Analytics and your CRM platform, locate answers to the following questions:

What was the prominent device that generated traffic? Sales?

Google Analytics allows you to divvy up traffic based on technology in a number of ways:

Under Browser & OS, you can sort visitors by browser:

Google Analytics shows which browsers users visited from (Source: Google Analytics) (Large preview)

There is a small tab at the top of the table for “Operating System”. Click that to reveal which OS were used:

Google Analytics breaks down traffic by operating system (Source: Google Analytics) (Large preview)

You can use the Mobile → Overview tab to look at the simple breakdown between desktop, mobile, and tablet users.

Google Analytics division between device traffic (Source: Google Analytics) (Large preview)

Really, your goal here is to weed out desktop users so you can focus strictly on mobile traffic as you assess the following data points.

When did your site experience an increase in traffic in November or December?

Every website’s holiday traffic history will look a little different. Take mine, for example:

An example of holiday traffic up and downs in Google Analytics (Source: Google Analytics) (Large preview)

My business really isn’t affected by the holidays at all... except that I know things are going to be super quiet on and around Thanksgiving and the major holidays in December. This is still important information for me to have.

For businesses that directly sell products or services through their site or content-based sites that plan publication schedules based on traffic, you’ll likely see a different trajectory in terms of highs and lows.

When did sales start to increase (if they don’t coincide with traffic)?

Again, for some of you, the matter of sales is irrelevant if you don’t offer any through your site. For everyone else, however, use the Google Analytics Conversions tab along with sales logged through your payment gateway or CRM to check this number.

Just remember that you have to activate the Conversions module in Google Analytics if you want it to track that data. If you didn’t remember last year, put it in place for this year.

Did the holiday uptick remain consistent until the end of the season or were there temporary dropoffs?

Much of this has to do with how you promote holiday-related events, promotional offers or content through your website. If you consistently market around the holidays from November 1 to the end of the year, you should see relatively steady traffic and sales.

Some days, of course, may be slower than others (like during workdays or earlier in the season), so it’s good to get a sense for the ebb and flow of your site’s holiday traffic. On the other hand, your website might be a major draw only on special sales days and the holidays themselves, so you can use this data to harness your energy for a big push on the days when it’ll have the greatest impact.

Try to identify patterns, so you can plan your design and marketing strategy accordingly.

When did traffic and sales return to their usual amount?

At some point, your site is going to see a dip in activity. There are some businesses that embrace this.

Let’s use Xfinity as an example. Around mid-November of last year, this is the holiday-centric message the top of the home page was pushing:

Xfinity promotes ways to make your home holiday ready (Source: Xfinity) (Large preview)

A month later, on December 9, any mention of the holidays was gone and replaced by a promotion of the upcoming Olympic Winter Games.

Xfinity stops promoting holidays in December (Source: Xfinity) (Large preview)

One can only assume that a major sporting event like the Olympics helps Xfinity sign more subscribers than trying to capture last-minute sales for the holidays.

Logically, this makes sense. December is a busy time for families. They’re planning travel, purchasing gifts and running around town in preparation for the upcoming celebrations. Most people probably don’t have time to set up a new cable or Internet package and wait around for Xfinity to configure it then.

Bottom line: it’s okay if your holiday-related traffic and sales drop off earlier than December 31. Study your data and let your user behavior guide you in your mobile design and promotion strategy.

What were the most popular sources for mobile traffic?

It’s actually not enough to identify the most popular sources of mobile traffic for your site. Sure, you want to know if organic SEO and social media promotional efforts worked to bring traffic to it… but it won’t really matter if those visitors abandoned the site without taking action.

When you start digging through the ways in which you acquired mobile visitors, make sure to review the sources and keywords used against other telling metrics, like:

  • Bounce rate
  • Time on site
  • Pages visited

This will give you a good sense for what sources — e.g. keywords, PPC ads, social media content, promotional backlinks from other sites — that attracted high-quality leads to it during the holiday season.

What were the most/least successful promotions?

One more thing to look at is what exactly performed the best between November and December with mobile visitors.

Did you run a pop-up promoting free shipping that was dismissed by most mobile visitors, but greatly taken advantage of by those on desktop? Did your custom home page banner touting an upcoming Black Friday sale get more clicks than the home page banner otherwise does at other times of the year? And what pathway resulted in the most conversions?

Dig into what exactly it was that appealed to your mobile visitors. Then, as you work on this year’s plan, focus on reproducing that success.

2. Assess The Navigation

The navigation plays two important roles on a website:

  1. High-level tabs inform visitors on what they’ll find on the site; essentially answering the question, “Is this of relevance to me?”
  2. The navigation itself provides visitors with shortcuts to parts of the site that matter most to them, simplifying their pathway to conversion.

When reviewing your navigation in the context of holiday traffic, you must ensure that it fulfills both of these roles.

Let’s look at two websites that provide relevant links during the holidays while also streamlining the visitors’ journey from entry to holiday-related pages.

Food52 is an online hub for people who enjoy cooking. You can buy kitchen gadgets from the site and peruse a whole bunch of content related to food and cooking.

I want to call out a number of things Food52 does especially well in terms of navigation:

The Food52 home page includes Thanksgiving-related categories (Source: Food52) (Large preview)
  1. The hamburger menu is prominently displayed in the top-left, which is exactly where visitors’ eyes will go as they follow the Z-shaped pattern for reading.
  2. The shopping cart, search bar shortcut and profile link are also displayed in the top header, making it easy to navigate to elements that support the shopping experience.
  3. If you scroll down on the home page (as I’ve done in the screenshot above), Food52 includes a good mix of Thanksgiving-related content along with its standard fare. In addition, it includes categories that help users filter through content that’s most relevant to them.

One other thing I’d like to point out is the navigation itself:

Simplified and customized navigation from Food52 for Thanksgiving (Source: Food52) (Large preview)

There are a number of things you’ll notice:

  • The mobile navigation is quite simplified. Despite how many categories and types of pages the site has, the navigation keeps this from being an overwhelming choice.
  • There are special tabs for Thanksgiving and Holiday. This will get users directly to content related to the holiday they’re cooking for.
  • The Hotline — which is its customer service forum — is also featured in the mobile navigation. This element is especially important around the holidays when visitors have questions they need answered quickly.

L.L.Bean is another website that handles mobile navigation well.

L.L.Bean puts the essentials in the navigation (Source: L.L.Bean) (Large preview)

As you can see, there are four buttons located within the mobile header:

  • Hamburger navigation icon: bolded and well-placed;
  • L.L.Bean logo for easy backtracking to the home page;
  • A shopping cart icon which will keep stored items top-of-mind with mobile users;
  • An ever-present search bar to speed up navigation even further.

Once a mobile user expands the hamburger navigation, they encounter this:

L.L.Bean prioritizes customer service and gifts around the holidays (Source: L.L.Bean) (Large preview)

As you can see, “Call Us” is the first option available within the mobile navigation. Again, with people in a rush and trying to get purchases done right over the holidays, having a direct line of communication to the company is important. The account link and “Ship To” personalization are also nice touches as these icons keep conversion top-of-mind.

Now, looking down the navigation, you’ll see this is a pretty standard mega menu. However, take note that at the very top of this category (as is the case for all others) appears a page for “Gifts”. This is not something you see the rest of the year, so that’s another holiday-related touch meant to streamline searches and sales.

3. Use Add-ons At Checkout

Here is everything you need to know to optimize conversions at mobile checkout. If I can add an additional two cents to this matter, though, I’d like to briefly talk about add-ons at checkout… but only around the holidays.

Typically, I believe that a fully streamlined checkout process is essential to capturing as many conversions as possible on mobile devices. It’s hard enough typing out all that information (if it doesn’t auto-populate) and trusting that devices and websites will keep payment information secure.

However…

When it comes to designing the checkout for holiday shoppers, I think it’s at least worth experimenting with add-ons. For example:

  • Promo codes
  • Free delivery options
  • Shorter, but more premium delivery or pick up in store options
  • Gift wrapping.

Nordstrom doesn’t even wait for visitors to get to the checkout to promote this.

Nordstrom promotes free shipping and returns right away (Source: Nordstrom) (Large preview)

The very top of the site has a sticky bar promoting the free shipping and returns offer. This way, visitors are already in the mindset that they can get their Black Friday purchases or holiday gifts for even cheaper than planned.

Fitbit has another example of this I really like:

Fitbit promotes sales and free expedited shipping (Source: Fitbit) (Large preview)

The top-half of the Fitbit homepage gets visitors into the mindset that there are cost savings galore here. Not only are items on sale, but certain orders come with free and expedited shipping. And the site clearly states when the sale ends, which will keep customers from getting upset if gifts don’t arrive on time. (It will also probably motivate them to get their shopping done sooner if they want to cash in on the sale.)

So all appropriate expectations regarding pricing and shipping are set right from the very get-go, making checkout go more smoothly.

I know that some may argue these will be bad for UX (and normally I’d join them), but I don’t see them as distractions during the holidays. This is an expensive and busy time of year.

Anything you can add to checkout that says, “Hey, we’re thinking about you and want to make this holiday season go just a little more smoothly” would go over well with your users.

4. Give Images A Seasonal Touch

Images are a tricky thing this time of year. You want to use them to appeal to holiday-minded visitors, but you don’t want to overdo it because images add a lot of pressure to your server. You need your site running fast, so be smart about what you do with them.

  1. Resize them before you ever add them to your site. There’s no need to use oversized images if they’re going to appear smaller online.
  2. Optimize your images with compression tools before and after they’re added to the design. This will free up some space they would otherwise take.
  3. If your users’ journey starts above-the-fold, you might want to consider lazy-loading images.

That said, images can go a long way in communicating to visitors that your site and business are ready to spread some holiday cheer without having to ever explicitly say it. This might be the ideal choice for those of you who design websites for global audiences. Perhaps you’d rather use an image that evokes a festive feeling because you don’t want to unintentionally offend anyone who doesn’t celebrate the holiday your copy calls express attention to.

Here is a great example from Uncommon Goods:

Uncommon Goods holiday home page (Source: Uncommon Goods) (Large preview)

I wouldn’t necessarily say the images used here are festive, but there are unique elements that evoke a certain association with the holidays. Like the color green used within the photos. Or the partial glances of what appear to be snow globes. They’re seasonal elements, but not necessarily relegated to Christmas, Hanukkah or Kwanzaa.

Then, there’s the United States Postal Service (USPS) website. Granted, this website targets visitors within the United States, but it remains mindful of the differences in religions practiced and holidays celebrated.

USPS uses a non-denominational image to promote the holidays (Source: USPS) (Large preview)

The message remains neutral as does the image itself. The USPS is simply trying to help people quickly and festively send holiday cards, gifts and other items to distant relatives and friends.

5. Review The Customer Journey

The factor of speed is a big one when it comes to designing the customer journey. While the navigation cuts down on any unnecessary steps that might be taken when visitors can afford a more leisurely pace, your design should expedite the rest.

In other words:

  • Start talking about holiday-related content, products, pages and links right on the home page.
  • Make sure you have at least one mention above-the-fold, whether it’s in the navigation, in a blog link or in a seasonal promo.
  • Use the data from last year to streamline the ideal pathway from the home page to conversion.
  • Walk through that pathway as a visitor on both desktop and mobile. Is it as clear, concise and direct as possible?
  • Check the responsiveness of the pathway. Your site, in general, needs to be responsive, but if you’re optimizing a certain journey for visitors and you want them to convert on mobile, then extra care needs to be taken.

Below is another example from the Food52 website from the holidays. As you can see in this snippet, two kinds of holiday-related content are promoted. What’s cool about them, though, is that it’s not necessarily in-your-face.

Food52 adds a holiday touch to its home page design and copy (Source: Food52) (Large preview)

The relish recipe could easily be used any time of the year. However, because pomegranates are often considered a winter food, this falls into the category of holiday-related content. The second post is more blatant about attracting holiday readers.

The final element in this screenshot is also worth taking note of. To start, it appears they’ve customized the copy specifically for this time of year. All it takes is one addition of the word “joyfully” to let visitors know that Food52 took time to make its site just a little more festive.

I also want to give them kudos for including a newsletter subscription box here and in other key areas of the site.

If the research from Adobe is right and only about half of mobile visitors convert, then this is a smart design choice. This way, Food52 can collect visitor information on mobile and contact them later. When interested visitors receive the reminder at a more convenient time and place, they can hop onto their desktop or other preferred device and finish the conversion process.

Another site which I think handles the customer journey optimization well is Cracker Barrel.

Cracker Barrel home page design (Source: Cracker Barrel) (Large preview)

Cracker Barrel doesn’t overdo it when it comes to designing for the holidays. Instead, it’s developed a series of calls-to-action that set certain types of visitors on the right path.

The first one features an image of what looks like a holiday feast with the CTA “Order Heat N’ Serve”. That’s brilliant. If people are taking the time to visit this site right before Thanksgiving, it’s probably to see if they can get help preparing their major feast… which it appears they can.

The second section sort of looks festive, though I’d still say they play it safe with choice of color, texture and gift card image. With a CTA of “Buy Gift Cards”, they’re now appealing to holiday shoppers. Not only can you get a whole feast conveniently prepared by Cracker Barrel, but you can buy gifts here, too.

Sometimes designing for the holidays isn’t about the blatant use of snowflake imagery or promoting recipes for cooking a turkey. Sometimes it’s about understanding what your users’ particular needs are at that time and helping setting them on that exact journey right away.

Wrap-Up

I understand that there are ways to add a dancing Santa to a site or to spruce up pop-ups with animated text and images, but I think subtler is better.

It’s kind of like the whole holiday music and decorations thing. How many times have you gone to your local drug store at the end of October for the purposes of getting Halloween candy, only to be met by an entire aisle full of holiday decorations? Or maybe you entered a department store like Macy’s in November, thinking you’ll beat the crazy holiday crowds. And, yet, holiday music is already playing. It’s overkill.

If you want to impress mobile visitors with your website around the holidays, focus on making this a worthwhile experience. Optimize your server for high volumes of traffic, put extra security in place, reorganize the navigation and add some small festive touches to your design that call attention to the most relevant parts of your site at this time of year.

(ra, yk, il)
Categories: Around The Web

Come Rain Or Come Shine: Inspiring Wallpapers For September 2018

Smashing Magazine - Fri, 08/31/2018 - 6:45am
Come Rain Or Come Shine: Inspiring Wallpapers For September 2018 Come Rain Or Come Shine: Inspiring Wallpapers For September 2018 Cosima Mielke 2018-08-31T12:45:54+02:00 2018-09-24T10:56:49+00:00

September is a time of transition. While some are trying to conserve the summer feeling just a bit longer, others are eager for fall to come with its colorful leaves and rainy days. But no matter how you feel about September or what the new month might be bringing along, this wallpaper collection sure has something to inspire you.

Just like every month since more than nine years already, artists and designers from across the globe once again challenged their creative skills and designed wallpapers to help you break out of your routine and give your desktop a fresh makeover. Each one of them comes in versions with and without a calendar for September 2018 and can be downloaded for free.

As a little extra goodie, we also went through our archives on the look for some timeless September wallpaper treasures which you’ll find assembled at the end of this post. Please note that these oldies, thus, don’t come with a calendar. Happy September!

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 Calendar series. We are regularly looking for creative designers and artists to be featured on Smashing Magazine. Are you one of them?
Further Reading on SmashingMag:

Meet Smashing Book 6 — our brand new book focused on real challenges and real front-end solutions in the real world: from design systems and accessible single-page apps to CSS Custom Properties, CSS Grid, Service Workers, performance, AR/VR and responsive art direction. With Marcy Sutton, Yoav Weiss, Lyza D. Gardner, Laura Elizabeth and many others.

Table of Contents → Cacti Everywhere

“Seasons come and go, but our brave cactuses still stand. Summer is almost over, and autumn is coming, but the beloved plants don’t care.” — Designed by Lívia Lénárt from Hungary.

Batmom

Designed by Ricardo Gimenes from Sweden.

Summer Is Not Over Yet

“This is our way of asking the summer not to go away. We were inspired by travel and exotic islands. In fact, it seems that September was the seventh month in the Roman calendar, dedicated to Vulcan, a god of fire. The legend has it that he was the son of Jupiter and Juno, and being an ugly baby with a limp, his mother tried to push him off a cliff into a volcano. Not really a nice story, but that’s where the tale took us. Anyway, enjoy September — because summer’s not over yet!” — Designed by PopArt Studio from Novi Sad, Serbia.

Summer Collapsed Into Fall

“The lands are painted gold lit with autumn blaze. And all at once the leaves of the trees started falling, but none of them are worried. Since, everyone falls in love with fall.” — Designed by Mindster from India.

Fresh Breeze

“I’m already looking forward to the fresh breezes of autumn, summer’s too hot for me!” — Designed by Bryan Van Mechelen from Belgium.

No More Inflatable Flamingos!

“Summer is officially over and we will no longer need our inflatable flamingos. Now, we’ll need umbrellas. And some flamingos will need an umbrella too!” — Designed by Marina Bošnjak from Croatia.

New Beginnings

“In September the kids and students go back to school.” — Designed by Melissa Bogemans from Belgium.

New Destination

“September is the beginning of the course. We see it as a never ending road because we are going to enjoy the journey.” — Designed by Veronica Valenzuela from Spain.

Good Things Come To Those Who Wait

“They say ‘patience is a virtue’, and so great opportunities and opulence in life come to those who are patient. Here we depicted a snail in the visual, one which longs to seize the shine that comes its way. It goes by the same watchword, shows no impulsiveness and waits for the right chances.” — Designed by Sweans from London.

Back To School

Designed by Ilse van den Boogaart from The Netherlands.

From The Archives

Some things are too good to be forgotten and our wallpaper archives are full of timeless treasures. So here’s a small selection of favorites from past September editions. Please note that these don’t come with a calendar.

Autumn Rains

“This autumn, we expect to see a lot of rainy days and blues, so we wanted to change the paradigm and wish a warm welcome to the new season. After all, if you come to think of it: rain is not so bad if you have an umbrella and a raincoat. Come autumn, we welcome you!” — Designed by PopArt Studio from Serbia.

Maryland Pride

“As summer comes to a close, so does the end of blue crab season in Maryland. Blue crabs have been a regional delicacy since the 1700s and have become Maryland’s most valuable fishing industry, adding millions of dollars to the Maryland economy each year. With more than 455 million blue crabs swimming in the Chesapeake Bay, these tasty critters can be prepared in a variety of ways and have become a summer staple in many homes and restaurants across the state. The blue crab has contributed so much to the state’s regional culture and economy, in 1989 it was named the State Crustacean, cementing its importance in Maryland history.” — Designed by The Hannon Group from Washington DC.

Summer Is Leaving

“It is inevitable. Summer is leaving silently. Let us think of ways to make the most of what is left of the beloved season.” — Designed by Bootstrap Dashboards from India.

Early Autumn

“September is usually considered as early autumn so I decided to draw some trees and leaves. However, nobody likes that summer is coming to an end, that’s why I kept summerish colours and style.” — Designed by Kat Gluszek from Germany.

Long Live Summer

“While September’s Autumnal Equinox technically signifies the end of the summer season, this wallpaper is for all those summer lovers, like me, who don’t want the sunshine, warm weather and lazy days to end.” — Designed by Vicki Grunewald from Washington.

Listen Closer… The Mushrooms Are Growing…

“It’s this time of the year when children go to school and grown-ups go to collect mushrooms.” — Designed by Igor Izhik from Canada.

Autumn Leaves

“Summer is coming to an end in the northern hemisphere, and that means Autumn is on the way!” — Designed by James Mitchell from the United Kingdom.

Festivities And Ganesh Puja

“The month of September starts with the arrival of festivals, mainly Ganesh Puja.” — Designed by Sayali Sandeep Harde from India.

Hungry

Designed by Elise Vanoorbeek from Belgium.

Sugar Cube

Designed by Luc Versleijen from the Netherlands.

Miss, My Dragon Burnt My Homework!

“We all know the saying ‘Miss, my dog ate my homework!’ Well, not everyone has a dog, so here’s a wallpaper to inspire your next excuse at school ;)” — Designed by Ricardo Gimenes from Sweden.

Meet The Bulbs!

“This summer we have seen lighting come to the forefront of design once again, with the light bulb front and center, no longer being hidden by lampshades or covers. Many different bulbs have been featured by interior designers including vintage bulbs, and oddly shaped energy-saving bulbs. We captured the personality of a variety of different bulbs in this wallpaper featuring the Bulb family.” — Designed by Carla Genovesio from the USA.

World Bat Night

“In the night from September 20th to 21st, the world has one of the most unusual environmental events — Night of the bats. Its main purpose: to draw public attention to the problems of bats and their protection, as well as to debunk the myths surrounding the animals, as many people experience unjustified superstitious fear, considering them vampires.” — Designed by cheloveche.ru from Russia.

Autumn Invaders

“Invaders of autumn are already here. Make sure you are well prepared!” Designed by German Ljutaev from Ukraine.

Hello Spring

“September is the start of spring in Australia so this bright wallpaper could brighten your day and help you feel energized!” — Designed by Tazi Design from Australia.

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.

Thank you to all designers for their participation. Join in next month!

Categories: Around The Web

A Brief Guide About Competitive Analysis

Smashing Magazine - Thu, 08/30/2018 - 8:00am
A Brief Guide About Competitive Analysis A Brief Guide About Competitive Analysis Mayur Kshirsagar 2018-08-30T14:00:57+02:00 2018-09-21T06:53:45+00:00

In this article, I will introduce the subject of competitive analysis, which is basically a method to determine how well your competitors are performing. My aim is to introduce the subject to those of you who are new to the concept. It should be useful if you are new to product design, UX, interaction or digital design, or if you have experience in these fields but have not performed a competitive analysis before.

No prior knowledge of the topic is needed because I’ll be explaining what the term means and how to perform a competitive analysis as we go. I am assuming some basic knowledge of the design process and UX research, but I’ll provide plenty of practical examples and reference links to help with any terms and concepts you might be unfamiliar with.

Note: If you are a beginner in UX and interaction design, it would be good to know the basics of the design process and to know what is UX research (and the methods used for UX research) before diving into the article’s main topic. Please read the next section carefully because I’ve added reference links to help you get started.

Recommended reading: Standing Out From The Crowd: Improving Your Mobile App With Competitive Analysis

Competitive Analysis, Service Design Cycle, Five-Stages Design Process

If you are a UX designer, then you might be aware of the service design cycle. This cycle contains four stages: discover, explore, test and listen. Each one of these stages has multiple research methods, and competitive analysis is part of the exploration. Susan Farrell has very helpfully distinguished different UX research methods and activities that can be performed for your project. (You can check this detailed segregation in her “UX Research Cheat Sheet”.)

The image below shows the four steps and the most commonly used methods in these steps.

(Large preview)

If you are new to this concept, you might first ask, “What is service design?” Shahrzad Samadzadeh explains it very well in her article, “So, Like, What Is Service Design?.”

Note: You can also learn more about service design in Sarah Gibbons’s article, “Service Design 101.”

Getting workflow just right ain’t an easy task. So are proper estimates. Or alignment among different departments. That’s why we’ve set up “this-is-how-I-work”-sessions — with smart cookies sharing what works well for them. A part of the Smashing Membership, of course.

Explore Smashing Membership ↬

Often, UX designers follow the five-stages design process in their projects:

  1. empathize,
  2. define,
  3. ideate,
  4. prototype,
  5. test.
The five-stages design process. (Large preview)

Please don’t confuse the five-stages design process with the service design cycle. Basically, they serve the same purpose in the design thinking process, but are explained in different styles. Here is a brief explanation of what these five stages contain:

  • Empathize
    This stage involves gaining a clear understanding of the problem you are trying to solve from the user’s point of view.
  • Define
    This stage involves defining the correct statement for the problem you are trying to solve, using the knowledge you gained in the first stage.
  • Ideate
    In this stage, you can generate different solution ideas for the problem.
  • Prototype
    Basically, a prototype is an attempt to give your solution some form so that it can be explained to others. For digital products, a prototype could be a wireframe set created using pen and paper or using a tool such as Balsamiq or Sketch, or it could be a visual design prototype created using a tool such as Sketch, Figma, Adobe XD or InVision.
  • Test
    Testing involves validating and evaluating all of your solutions with the users.

You can perform UX research at any stage. Many articles and books are available for you to learn more about this design process. “Five Stages in the Design Thinking Process” by Rikke Dam and Teo Siang is one of my favorite articles on the topic.

The most frequent methods used by UX professionals during the exploration stage of the design life cycle. (Nielsen Norman Group, “User Experience Careers” survey report) (Large preview)

According to Nielsen Norman Group’s “User Experience Careers” survey report, 61% of UX professionals prefer to do the competitive analysis for their projects. But what exactly is competitive analysis? In simple language, competitive analysis is nothing but a method to determine how your competitors are performing, what they are offering and how well they are doing it.

Sometimes, competitive analysis is referred as competitive usability evaluation.

Why Should You Do A Competitive Analysis?

There are many reasons to do a competitive analysis, but I think the most important reason is that it helps us to understand the rights and wrongs of our own product or service.

Using competitive analysis, you can make decisions based on knowledge of what is currently working well for your users, rather than based on guesses or intuition. In doing competitive analysis, you can also identify risks in your product or service and use those insights to add value to it.

Recently, I was working on a project in which I did a competitive analysis of a feature (collaborative meeting note-taking) that a client wanted to introduce in their web app. Note-taking is not exactly a new or highly innovative thing, so the biggest challenge I was facing was to make this functionality simpler and easier to handle, because the product I was working on was in the very early stages of development. The feature, in a nutshell, was to create a simple text document where some interactive action items could be added.

Because a ton of apps are out there that allow you to create simple text documents, I decided to do a competitive analysis for this functionality. (I’ll explain this process in more detail later in the section “Five Easy Steps to Do a Competitive Analysis”.)

How To Find The Right Competitors?

Basically, there are two types of competitors: direct and indirect. As a UX designer, your role is to study the designs of these competitors.

Jaime Levy gives very good definitions of direct and indirect competitors in her book UX Strategy. You can learn more about competitive analysis (and types of competitors) in chapter 4 of the book, “Conducting Competitive Research”.

Types of competitors. (Large preview)

Direct competitors are the ones who offer the same, or a very similar, set of features to your current or future customers, which means they are solving a similar problem to the one you are trying to solve, for a customer base that you are targeting as well.

Indirect competitors are the ones who offers a similar set of features but to a different customer segment; or, they target your exact customer base without offering the exact same set of features, which means indirect competitors are solving the same problem but for a different customer base, or are solving the same problem but offer a different solution.

You can search for these types of competitors online (by doing a simple web search), or you can directly ask your current and potential customers what they are using already. You can also look for your direct and indirect competitors on websites such as Crunchbase and Product Hunt, and you can search for them in the Google Play and the iOS App Store.

Five Easy Steps To Do A Competitive Analysis

You can perform a competitive analysis for your existing or new product using the following five-step process.

5 steps to do a competitive analysis. (Large preview) 1. Define And Understand The Goals

Defining and understanding the goal is an integral part of any UX research process. You must define an accurate goal (or set of goals) for your research; otherwise, there is a chance you’ll get the wrong outcome.

Draft all of your goals right before starting your process. When defining your goals, consider the following questions: Why are you doing this competitive analysis? What kind of outcome do you expect? Will this analysis affect UX decisions?

Remember: When setting up goals for any kind of UX research, be as specific as possible.

I mentioned earlier that I recently performed a competitive analysis for a collaborative meeting note-taking feature, to be introduced in the app that I was developing for a client. The goals for my research were very general because innumerable apps all provide this type of functionality, and the product I was working on was in the very early stages of development.

Even though your research goals might be simple, make them as specific as possible, and write them all down. Writing down your goals will help you stay on the right track.

The goals for my analysis were more like questions for which I was trying to find the answers. Here is the list of goals I set for this research:

  • Which apps do users prefer for note-taking? And why do they prefer them?
    Goal: To find out the user’s behavior with these apps, their preferences and their comfort zone.
  • What is the working mechanism of these apps?
    Goal: To find how out competitors’ apps work, so that we can identify their pros and cons.
  • What are the “star” features of these apps?
    Goal: To identify functionalities that we were trying to introduce as well, to see whether they already exist and, if they exist, how exactly they were implemented.
  • How comfortable does a user feel when using these apps?
    Goal: To identify user loyalty and engagement in the apps of our competitors.
  • How does collaborative editing work in these competitive apps?
    Goal: To identify how collaborative-editing functionality works and to study its technical aspects.
  • What is the visual structure and user interface of these apps?
    Goal: To check the visual look and feel of the apps (user interface and interaction).
2. Find The Right Competitors

After setting the goals, go on a search and make a list of both direct and indirect competitors. It’s not necessary to analyze all of the competitors you find. The number is completely up to you. Some people suggest analyzing at least two to four competitors, while others suggest five to ten or more.

Finding the right competitors for my research wasn’t a hard task because I already knew many apps that provided similar features, but I still did a quick search on Google, and the results were a bit surprising — surprising because most of the apps I knew turned out to be more like indirect competitors to the app I was working on; and later, after a bit more searching, I also found the apps that were our direct competitors.

Putting each competitor in the right list is a very important part of competitive analysis because the features and functionality in your competitors’ apps are based on exactly what users of those apps want. Let’s assume you put one indirect competitor, XYZ, under the “direct competitors” list and start doing your analysis. While doing the research, you might find some impressive feature in XYZ’s app and decide to add a similar feature in your own app; then, later it turns out that the feature you added is not useful for the users you are targeting. You might end up wasting a lot of energy, time and money building something that is not at all useful. So, be careful when sorting your competitors.

For my research, the competitors were as follows:

  • Direct competitors
    Quip, Cisco Spark Meeting Notes, Workboard, Lucid Meeting, Less Meeting, MeetingSense, Minute-it, etc.
    • All of the apps above provide the same type of functionality, which we were trying to introduce for almost the same type of user base.
  • Indirect competitors
    Evernote, Google Keep, Google Docs, Microsoft Word, Microsoft OneNote and other traditional note-taking apps and pen-paper note-taking methods.
    • The user base for all of the above is not exactly different from the user base we were targeting, but most of the users we were targeting were using these apps because they were unaware of the more convenient ways to take meeting notes.
3. Make A Competitive Analysis Matrix

A competitive analysis matrix is not complex, just a simple spreadsheet. You can use Microsoft Excel, Google Sheets, Apple Numbers or any other tool you are comfortable with.

First, divide all competitors you’ve found into two groups (direct and indirect) and put them in a spreadsheet. Jamie Levy suggests making the following columns:

  1. competitor’s name,
  2. URL,
  3. login credentials,
  4. purpose,
  5. year founded.
Example of competitive analysis matrix spreadsheet from UX Strategy, Jaime Levy’s book. (Large preview)

I would recommend digging a bit deeper and adding a few more columns, such as for “unique features”, “pros and cons”, etc. It would help to summarize your analysis. It’s not necessary to set your columns exactly as mentioned above. You can modify the columns to your own research goals and needs.

For my analysis, I created only four columns. My competitive analysis matrix looked as follows:

  • Competitor name
    In this column, I put the names of all of the competitors.
  • URL
    These are website links or app download links for these competitors.
  • Features/comments
    In this column, I put all of my comments, some ”star” features I needed to focus on, and the pros and cons of the competitor. I color-coded the cells so that later I (or anyone viewing the matrix) could easily identify the difference between them. For example, I used light yellow for features, light purple for comments, green for pros and red for cons.
  • Screenshots/video links
    In this column, I put all of the screenshots and videos related to the features and comments mentioned in the third column. This way, it became very easy and quick to understand what a particular comment or feature was all about.
(Large preview) 4. Write A Summary And An Analysis

Once you are done with the analysis matrix spreadsheet, move on and create a summary of your findings. Be as specific as possible, and try to answer all of your questions while setting up a goal or during the overall process.

This will help you and your team members and stakeholders make the right design and UX decisions. This summary will also help you find new design and UX opportunities in the product you’re building.

In writing the summary and the presentation for the competitive analysis that I did for this collaborative note-taking app, the competitive analysis matrix helped me a lot. I drafted a document with all of the high-level takeaways from this analysis and answered all of the questions that were set as goals. For the presentation, I shared the document with the client, which helped both the client and me to finalize the features, the flows and the end requirements for the product.

5. Presentation

The last step of your competitive analysis is the presentation. It’s not a typical slideshow presentation — rather, just share all of the data and information you collected throughout the process with your teammates, stakeholders and/or clients.

Getting feedback from everywhere you can and being open to this feedback is a very important part of the designer’s workflow. So, share all of your finding with your teammates, stakeholders and clients, and ask for their opinion. You might find some missing points in your analysis or discover something new and exciting from someone’s feedback.

Conclusion

We live in a data-driven world, and we should build products, services and apps based on data, rather than our intuition (or guesswork).

As UX designers, we should go out there and collect as much data as possible before building a real product. This data will help us to create a solid product that users will want to use, rather than a product we want or imagine. These kinds of products are more likely to succeed in the market. Competitive analysis is one of the ways to get this data and to create a user-friendly product.

Finally, no matter what kind of product you are building or research you are conducting, always try to put yourself in the users’ shoes every now and then. This way, you will be able to identify the users’ struggles and ultimately deliver a better solution.

I hope this article has helped you plan and make your first competitive analysis for your next project!

Further Reading

If you want to become a better UX, interaction, visual (UI) or product designer, there are a lot of sources from which you can learn — articles, books, online courses. I often check the following few: Smashing Magazine, InVision blog, Interaction Design Foundation, NN Group and UX Mastery. These websites have a very good collection of articles on the topics of UI and UX design and UX research.

Here are some additional resources:

(mb, ra, al, yk, il)
Categories: Around The Web

Building A Room Detector For IoT Devices On Mac OS

Smashing Magazine - Wed, 08/29/2018 - 8:20am
Building A Room Detector For IoT Devices On Mac OS Building A Room Detector For IoT Devices On Mac OS Alvin Wan 2018-08-29T14:20:53+02:00 2018-09-20T07:08:46+00:00

Knowing which room you’re in enables various IoT applications — from turning on the light to changing TV channels. So, how can we detect the moment you and your phone are in the kitchen, or bedroom, or living room? With today’s commodity hardware, there are a myriad of possibilities:

One solution is to equip each room with a bluetooth device. Once your phone is within range of a bluetooth device, your phone will know which room it is, based on the bluetooth device. However, maintaining an array of Bluetooth devices is significant overhead — from replacing batteries to replacing dysfunctional devices. Additionally, proximity to the Bluetooth device is not always the answer: if you’re in the living room, by the wall shared with the kitchen, your kitchen appliances should not start churning out food.

Another, albeit impractical, solution is to use GPS. However, keep in mind hat GPS works poorly indoors in which the multitude of walls, other signals, and other obstacles wreak havoc on GPS’s precision.

Our approach instead is to leverage all in-range WiFi networks — even the ones your phone is not connected to. Here is how: consider the strength of WiFi A in the kitchen; say it is 5. Since there is a wall between the kitchen and the bedroom, we can reasonably expect the strength of WiFi A in the bedroom to differ; say it is 2. We can exploit this difference to predict which room we’re in. What’s more: WiFi network B from our neighbor can only be detected from the living room but is effectively invisible from the kitchen. That makes prediction even easier. In sum, the list of all in-range WiFi gives us plentiful information.

This method has the distinct advantages of:

  1. not requiring more hardware;
  2. relying on more stable signals like WiFi;
  3. working well where other techniques such as GPS are weak.

The more walls the better, as the more disparate the WiFi network strengths, the easier the rooms are to classify. You will build a simple desktop app that collects data, learns from the data, and predicts which room you’re in at any given time.

Further Reading on SmashingMag: Prerequisites

For this tutorial, you will need a Mac OSX. Whereas the code can apply to any platform, we will only provide dependency installation instructions for Mac.

Front-end is messy and complicated these days. That's why we publish articles, printed books and webinars with useful techniques to improve your work. Even better: Smashing Membership with a growing selection of front-end & UX goodies. So you get your work done, better and faster.

Explore Smashing Membership ↬ Step 0: Setup Work Environment

Your desktop app will be written in NodeJS. However, to leverage more efficient computational libraries like numpy, the training and prediction code will be written in Python. To start, we will setup your environments and install dependencies. Create a new directory to house your project.

mkdir ~/riot

Navigate into the directory.

cd ~/riot

Use pip to install Python’s default virtual environment manager.

sudo pip install virtualenv

Create a Python3.6 virtual environment named riot.

virtualenv riot --python=python3.6

Activate the virtual environment.

source riot/bin/activate

Your prompt is now preceded by (riot). This indicates we have successfully entered the virtual environment. Install the following packages using pip:

  • numpy: An efficient, linear algebra library
  • scipy: A scientific computing library that implements popular machine learning models
pip install numpy==1.14.3 scipy ==1.1.0

With the working directory setup, we will start with a desktop app that records all WiFi networks in-range. These recordings will constitute training data for your machine learning model. Once we have data on hand, you will write a least squares classifier, trained on the WiFi signals collected earlier. Finally, we will use the least squares model to predict the room you’re in, based on the WiFi networks in range.

Step 1: Initial Desktop Application

In this step, we will create a new desktop application using Electron JS. To begin, we will instead the Node package manager npm and a download utility wget.

brew install npm wget

To begin, we will create a new Node project.

npm init

This prompts you for the package name and then the version number. Hit ENTER to accept the default name of riot and default version of 1.0.0.

package name: (riot) version: (1.0.0)

This prompts you for a project description. Add any non-empty description you would like. Below, the description is room detector

description: room detector

This prompts you for the entry point, or the main file to run the project from. Enter app.js.

entry point: (index.js) app.js

This prompts you for the test command and git repository. Hit ENTER to skip these fields for now.

test command: git repository:

This prompts you for keywords and author. Fill in any values you would like. Below, we use iot, wifi for keywords and use John Doe for the author.

keywords: iot,wifi author: John Doe

This prompts you for the license. Hit ENTER to accept the default value of ISC.

license: (ISC)

At this point, npm will prompt you with a summary of information so far. Your output should be similar to the following.

{ "name": "riot", "version": "1.0.0", "description": "room detector", "main": "app.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "keywords": [ "iot", "wifi" ], "author": "John Doe", "license": "ISC" }

Hit ENTER to accept. npm then produces a package.json. List all files to double-check.

ls

This will output the only file in this directory, along with the virtual environment folder.

package.json riot

Install NodeJS dependencies for our project.

npm install electron --global # makes electron binary accessible globally npm install node-wifi --save

Start with main.js from Electron Quick Start, by downloading the file, using the below. The following -O argument renames main.js to app.js.

wget https://raw.githubusercontent.com/electron/electron-quick-start/master/main.js -O app.js

Open app.js in nano or your favorite text editor.

nano app.js

On line 12, change index.html to static/index.html, as we will create a directory static to contain all HTML templates.

function createWindow () { // Create the browser window. win = new BrowserWindow({width: 1200, height: 800}) // and load the index.html of the app. win.loadFile('static/index.html') // Open the DevTools.

Save your changes and exit the editor. Your file should match the source code of the app.js file. Now create a new directory to house our HTML templates.

mkdir static

Download a stylesheet created for this project.

wget https://raw.githubusercontent.com/alvinwan/riot/master/static/style.css?token=AB-ObfDtD46ANlqrObDanckTQJ2Q1Pyuks5bf79PwA%3D%3D -O static/style.css

Open static/index.html in nano or your favorite text editor. Start with the standard HTML structure.

<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Riot | Room Detector</title> </head> <body> <main> </main> </body> </html>

Right after the title, link the Montserrat font linked by Google Fonts and stylesheet.

<title>Riot | Room Detector</title> <!-- start new code --> <link href="https://fonts.googleapis.com/css?family=Montserrat:400,700" rel="stylesheet"> <link href="style.css" rel="stylesheet"> <!-- end new code --> </head>

Between the main tags, add a slot for the predicted room name.

<main> <!-- start new code --> <p class="text">I believe you’re in the</p> <h1 class="title" id="predicted-room-name">(I dunno)</h1> <!-- end new code --> </main>

Your script should now match the following exactly. Exit the editor.

<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Riot | Room Detector</title> <link href="https://fonts.googleapis.com/css?family=Montserrat:400,700" rel="stylesheet"> <link href="style.css" rel="stylesheet"> </head> <body> <main> <p class="text">I believe you’re in the</p> <h1 class="title" id="predicted-room-name">(I dunno)</h1> </main> </body> </html>

Now, amend the package file to contain a start command.

nano package.json

Right after line 7, add a start command that’s aliased to electron .. Make sure to add a comma to the end of the previous line.

"scripts": { "test": "echo \"Error: no test specified\" && exit 1", "start": "electron ." },

Save and exit. You are now ready to launch your desktop app in Electron JS. Use npm to launch your application.

npm start

Your desktop application should match the following.

Home page with “Add New Room” button available (Large preview)

This completes your starting desktop app. To exit, navigate back to your terminal and CTRL+C. In the next step, we will record wifi networks, and make the recording utility accessible through the desktop application UI.

Step 2: Record WiFi Networks

In this step, you will write a NodeJS script that records the strength and frequency of all in-range wifi networks. Create a directory for your scripts.

mkdir scripts

Open scripts/observe.js in nano or your favorite text editor.

nano scripts/observe.js

Import a NodeJS wifi utility and the filesystem object.

var wifi = require('node-wifi'); var fs = require('fs');

Define a record function that accepts a completion handler.

/** * Uses a recursive function for repeated scans, since scans are asynchronous. */ function record(n, completion, hook) { }

Inside the new function, initialize the wifi utility. Set iface to null to initialize to a random wifi interface, as this value is currently irrelevant.

function record(n, completion, hook) { wifi.init({ iface : null }); }

Define an array to contain your samples. Samples are training data we will use for our model. The samples in this particular tutorial are lists of in-range wifi networks and their associated strengths, frequencies, names etc.

function record(n, completion, hook) { ... samples = [] }

Define a recursive function startScan, which will asynchronously initiate wifi scans. Upon completion, the asynchronous wifi scan will then recursively invoke startScan.

function record(n, completion, hook) { ... function startScan(i) { wifi.scan(function(err, networks) { }); } startScan(n); }

In the wifi.scan callback, check for errors or empty lists of networks and restart the scan if so.

wifi.scan(function(err, networks) { if (err || networks.length == 0) { startScan(i); return } });

Add the recursive function’s base case, which invokes the completion handler.

wifi.scan(function(err, networks) { ... if (i <= 0) { return completion({samples: samples}); } });

Output a progress update, append to the list of samples, and make the recursive call.

wifi.scan(function(err, networks) { ... hook(n-i+1, networks); samples.push(networks); startScan(i-1); });

At the end of your file, invoke the record function with a callback that saves samples to a file on disk.

function record(completion) { ... } function cli() { record(1, function(data) { fs.writeFile('samples.json', JSON.stringify(data), 'utf8', function() {}); }, function(i, networks) { console.log(" * [INFO] Collected sample " + (21-i) + " with " + networks.length + " networks"); }) } cli();

Double check that your file matches the following:

var wifi = require('node-wifi'); var fs = require('fs'); /** * Uses a recursive function for repeated scans, since scans are asynchronous. */ function record(n, completion, hook) { wifi.init({ iface : null // network interface, choose a random wifi interface if set to null }); samples = [] function startScan(i) { wifi.scan(function(err, networks) { if (err || networks.length == 0) { startScan(i); return } if (i <= 0) { return completion({samples: samples}); } hook(n-i+1, networks); samples.push(networks); startScan(i-1); }); } startScan(n); } function cli() { record(1, function(data) { fs.writeFile('samples.json', JSON.stringify(data), 'utf8', function() {}); }, function(i, networks) { console.log(" * [INFO] Collected sample " + i + " with " + networks.length + " networks"); }) } cli();

Save and exit. Run the script.

node scripts/observe.js

Your output will match the following, with variable numbers of networks.

* [INFO] Collected sample 1 with 39 networks

Examine the samples that were just collected. Pipe to json_pp to pretty print the JSON and pipe to head to view the first 16 lines.

cat samples.json | json_pp | head -16

The below is example output for a 2.4 GHz network.

{ "samples": [ [ { "mac": "64:0f:28:79:9a:29", "bssid": "64:0f:28:79:9a:29", "ssid": "SMASHINGMAGAZINEROCKS", "channel": 4, "frequency": 2427, "signal_level": "-91", "security": "WPA WPA2", "security_flags": [ "(PSK/AES,TKIP/TKIP)", "(PSK/AES,TKIP/TKIP)" ] },

This concludes your NodeJS wifi-scanning script. This allows us to view all in-range WiFi networks. In the next step, you will make this script accessible from the desktop app.

Step 3: Connect Scan Script To Desktop App

In this step, you will first add a button to the desktop app to trigger the script with. Then, you will update the desktop app UI with the script’s progress.

Open static/index.html.

nano static/index.html

Insert the “Add” button, as shown below.

<h1 class="title" id="predicted-room-name">(I dunno)</h1> <!-- start new code --> <div class="buttons"> <a href="add.html" class="button">Add new room</a> </div> <!-- end new code --> </main>

Save and exit. Open static/add.html.

nano static/add.html

Paste the following content.

<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Riot | Add New Room</title> <link href="https://fonts.googleapis.com/css?family=Montserrat:400,700" rel="stylesheet"> <link href="style.css" rel="stylesheet"> </head> <body> <main> <h1 class="title" id="add-title">0</h1> <p class="subtitle">of <span>20</span> samples needed. Feel free to move around the room.</p> <input type="text" id="add-room-name" class="text-field" placeholder="(room name)"> <div class="buttons"> <a href="#" id="start-recording" class="button">Start recording</a> <a href="index.html" class="button light">Cancel</a> </div> <p class="text" id="add-status" style="display:none"></p> </main> <script> require('../scripts/observe.js') </script> </body> </html>

Save and exit. Reopen scripts/observe.js.

nano scripts/observe.js

Beneath the cli function, define a new ui function.

function cli() { ... } // start new code function ui() { } // end new code cli();

Update the desktop app status to indicate the function has started running.

function ui() { var room_name = document.querySelector('#add-room-name').value; var status = document.querySelector('#add-status'); var number = document.querySelector('#add-title'); status.style.display = "block" status.innerHTML = "Listening for wifi..." }

Partition the data into training and validation data sets.

function ui() { ... function completion(data) { train_data = {samples: data['samples'].slice(0, 15)} test_data = {samples: data['samples'].slice(15)} var train_json = JSON.stringify(train_data); var test_json = JSON.stringify(test_data); } }

Still within the completion callback, write both datasets to disk.

function ui() { ... function completion(data) { ... fs.writeFile('data/' + room_name + '_train.json', train_json, 'utf8', function() {}); fs.writeFile('data/' + room_name + '_test.json', test_json, 'utf8', function() {}); console.log(" * [INFO] Done") status.innerHTML = "Done." } }

Invoke record with the appropriate callbacks to record 20 samples and save the samples to disk.

function ui() { ... function completion(data) { ... } record(20, completion, function(i, networks) { number.innerHTML = i console.log(" * [INFO] Collected sample " + i + " with " + networks.length + " networks") }) }

Finally, invoke the cli and ui functions where appropriate. Start by deleting the cli(); call at the bottom of the file.

function ui() { ... } cli(); // remove me

Check if the document object is globally accessible. If not, the script is being run from the command line. In this case, invoke the cli function. If it is, the script is loaded from within the desktop app. In this case, bind the click listener to the ui function.

if (typeof document == 'undefined') { cli(); } else { document.querySelector('#start-recording').addEventListener('click', ui) }

Save and exit. Create a directory to hold our data.

mkdir data

Launch the desktop app.

npm start

You will see the following homepage. Click on “Add room”.

(Large preview)

You will see the following form. Type in a name for the room. Remember this name, as we will use this later on. Our example will be bedroom.

“Add New Room” page on load (Large preview)

Click “Start recording,” and you will see the following status “Listening for wifi…”.

“Add New Room” starting recording (Large Preview)

Once all 20 samples are recorded, your app will match the following. The status will read “Done.”

“Add New Room” page after recording is complete (Large preview)

Click on the misnamed “Cancel” to return to the homepage, which matches the following.

“Add New Room” page after recording is complete (Large preview)

We can now scan wifi networks from the desktop UI, which will save all recorded samples to files on disk. Next, we will train an out-of-box machine learning algorithm-least squares on the data you have collected.

Step 4: Write Python Training Script

In this step, we will write a training script in Python. Create a directory for your training utilities.

mkdir model

Open model/train.py

nano model/train.py

At the top of your file, import the numpy computational library and scipy for its least squares model.

import numpy as np from scipy.linalg import lstsq import json import sys

The next three utilities will handle loading and setting up data from the files on disk. Start by adding a utility function that flattens nested lists. You will use this to flatten a list of list of samples.

import sys def flatten(list_of_lists): """Flatten a list of lists to make a list. >>> flatten([[1], [2], [3, 4]]) [1, 2, 3, 4] """ return sum(list_of_lists, [])

Add a second utility that loads samples from the specified files. This method abstracts away the fact that samples are spread out across multiple files, returning just a single generator for all samples. For each of the samples, the label is the index of the file. e.g., If you call get_all_samples('a.json', 'b.json'), all samples in a.json will have label 0 and all samples in b.json will have label 1.

def get_all_samples(paths): """Load all samples from JSON files.""" for label, path in enumerate(paths): with open(path) as f: for sample in json.load(f)['samples']: signal_levels = [ network['signal_level'].replace('RSSI', '') or 0 for network in sample] yield [network['mac'] for network in sample], signal_levels, label

Next, add a utility that encodes the samples using a bag-of-words-esque model. Here is an example: Assume we collect two samples.

  1. wifi network A at strength 10 and wifi network B at strength 15
  2. wifi network B at strength 20 and wifi network C at strength 25.

This function will produce a list of three numbers for each of the samples: the first value is the strength of wifi network A, the second for network B, and the third for C. In effect, the format is [A, B, C].

  1. [10, 15, 0]
  2. [0, 20, 25]
def bag_of_words(all_networks, all_strengths, ordering): """Apply bag-of-words encoding to categorical variables. >>> samples = bag_of_words( ... [['a', 'b'], ['b', 'c'], ['a', 'c']], ... [[1, 2], [2, 3], [1, 3]], ... ['a', 'b', 'c']) >>> next(samples) [1, 2, 0] >>> next(samples) [0, 2, 3] """ for networks, strengths in zip(all_networks, all_strengths): yield [strengths[networks.index(network)] if network in networks else 0 for network in ordering]

Using all three utilities above, we synthesize a collection of samples and their labels. Gather all samples and labels using get_all_samples. Define a consistent format ordering to one-hot encode all samples, then apply one_hot encoding to samples. Finally, construct the data and label matrices X and Y respectively.

def create_dataset(classpaths, ordering=None): """Create dataset from a list of paths to JSON files.""" networks, strengths, labels = zip(*get_all_samples(classpaths)) if ordering is None: ordering = list(sorted(set(flatten(networks)))) X = np.array(list(bag_of_words(networks, strengths, ordering))).astype(np.float64) Y = np.array(list(labels)).astype(np.int) return X, Y, ordering

These functions complete the data pipeline. Next, we abstract away model prediction and evaluation. Start by defining the prediction method. The first function normalizes our model outputs, so that the sum of all values totals to 1 and that all values are non-negative; this ensures that the output is a valid probability distribution. The second evaluates the model.

def softmax(x): """Convert one-hotted outputs into probability distribution""" x = np.exp(x) return x / np.sum(x) def predict(X, w): """Predict using model parameters""" return np.argmax(softmax(X.dot(w)), axis=1)

Next, evaluate the model’s accuracy. The first line runs prediction using the model. The second counts the numbers of times both predicted and true values agree, then normalizes by the total number of samples.

def evaluate(X, Y, w): """Evaluate model w on samples X and labels Y.""" Y_pred = predict(X, w) accuracy = (Y == Y_pred).sum() / X.shape[0] return accuracy

This concludes our prediction and evaluation utilities. After these utilities, define a main function that will collect the dataset, train, and evaluate. Start by reading the list of arguments from the command line sys.argv; these are the rooms to include in training. Then create a large dataset from all of the specified rooms.

def main(): classes = sys.argv[1:] train_paths = sorted(['data/{}_train.json'.format(name) for name in classes]) test_paths = sorted(['data/{}_test.json'.format(name) for name in classes]) X_train, Y_train, ordering = create_dataset(train_paths) X_test, Y_test, _ = create_dataset(test_paths, ordering=ordering)

Apply one-hot encoding to the labels. A one-hot encoding is similar to the bag-of-words model above; we use this encoding to handle categorical variables. Say we have 3 possible labels. Instead of labelling 1, 2, or 3, we label the data with [1, 0, 0], [0, 1, 0], or [0, 0, 1]. For this tutorial, we will spare the explanation for why one-hot encoding is important. Train the model, and evaluate on both the train and validation sets.

def main(): ... X_test, Y_test, _ = create_dataset(test_paths, ordering=ordering) Y_train_oh = np.eye(len(classes))[Y_train] w, _, _, _ = lstsq(X_train, Y_train_oh) train_accuracy = evaluate(X_train, Y_train, w) test_accuracy = evaluate(X_test, Y_test, w)

Print both accuracies, and save the model to disk.

def main(): ... print('Train accuracy ({}%), Validation accuracy ({}%)'.format(train_accuracy*100, test_accuracy*100)) np.save('w.npy', w) np.save('ordering.npy', np.array(ordering)) sys.stdout.flush()

At the end of the file, run the main function.

if __name__ == '__main__': main()

Save and exit. Double check that your file matches the following:

import numpy as np from scipy.linalg import lstsq import json import sys def flatten(list_of_lists): """Flatten a list of lists to make a list. >>> flatten([[1], [2], [3, 4]]) [1, 2, 3, 4] """ return sum(list_of_lists, []) def get_all_samples(paths): """Load all samples from JSON files.""" for label, path in enumerate(paths): with open(path) as f: for sample in json.load(f)['samples']: signal_levels = [ network['signal_level'].replace('RSSI', '') or 0 for network in sample] yield [network['mac'] for network in sample], signal_levels, label def bag_of_words(all_networks, all_strengths, ordering): """Apply bag-of-words encoding to categorical variables. >>> samples = bag_of_words( ... [['a', 'b'], ['b', 'c'], ['a', 'c']], ... [[1, 2], [2, 3], [1, 3]], ... ['a', 'b', 'c']) >>> next(samples) [1, 2, 0] >>> next(samples) [0, 2, 3] """ for networks, strengths in zip(all_networks, all_strengths): yield [int(strengths[networks.index(network)]) if network in networks else 0 for network in ordering] def create_dataset(classpaths, ordering=None): """Create dataset from a list of paths to JSON files.""" networks, strengths, labels = zip(*get_all_samples(classpaths)) if ordering is None: ordering = list(sorted(set(flatten(networks)))) X = np.array(list(bag_of_words(networks, strengths, ordering))).astype(np.float64) Y = np.array(list(labels)).astype(np.int) return X, Y, ordering def softmax(x): """Convert one-hotted outputs into probability distribution""" x = np.exp(x) return x / np.sum(x) def predict(X, w): """Predict using model parameters""" return np.argmax(softmax(X.dot(w)), axis=1) def evaluate(X, Y, w): """Evaluate model w on samples X and labels Y.""" Y_pred = predict(X, w) accuracy = (Y == Y_pred).sum() / X.shape[0] return accuracy def main(): classes = sys.argv[1:] train_paths = sorted(['data/{}_train.json'.format(name) for name in classes]) test_paths = sorted(['data/{}_test.json'.format(name) for name in classes]) X_train, Y_train, ordering = create_dataset(train_paths) X_test, Y_test, _ = create_dataset(test_paths, ordering=ordering) Y_train_oh = np.eye(len(classes))[Y_train] w, _, _, _ = lstsq(X_train, Y_train_oh) train_accuracy = evaluate(X_train, Y_train, w) validation_accuracy = evaluate(X_test, Y_test, w) print('Train accuracy ({}%), Validation accuracy ({}%)'.format(train_accuracy*100, validation_accuracy*100)) np.save('w.npy', w) np.save('ordering.npy', np.array(ordering)) sys.stdout.flush() if __name__ == '__main__': main()

Save and exit. Recall the room name used above when recording the 20 samples. Use that name instead of bedroom below. Our example is bedroom. We use -W ignore to ignore warnings from a LAPACK bug.

python -W ignore model/train.py bedroom

Since we’ve only collected training samples for one room, you should see 100% training and validation accuracies.

Train accuracy (100.0%), Validation accuracy (100.0%)

Next, we will link this training script to the desktop app.

Step 5: Link Train Script

In this step, we will automatically retrain the model whenever the user collects a new batch of samples. Open scripts/observe.js.

nano scripts/observe.js

Right after the fs import, import the child process spawner and utilities.

var fs = require('fs'); // start new code const spawn = require("child_process").spawn; var utils = require('./utils.js');

In the ui function, add the following call to retrain at the end of the completion handler.

function ui() { ... function completion() { ... retrain((data) => { var status = document.querySelector('#add-status'); accuracies = data.toString().split('\n')[0]; status.innerHTML = "Retraining succeeded: " + accuracies }); } ... }

After the ui function, add the following retrain function. This spawns a child process that will run the python script. Upon completion, the process calls a completion handler. Upon failure, it will log the error message.

function ui() { .. } function retrain(completion) { var filenames = utils.get_filenames() const pythonProcess = spawn('python', ["./model/train.py"].concat(filenames)); pythonProcess.stdout.on('data', completion); pythonProcess.stderr.on('data', (data) => { console.log(" * [ERROR] " + data.toString()) }) }

Save and exit. Open scripts/utils.js.

nano scripts/utils.js

Add the following utility for fetching all datasets in data/.

var fs = require('fs'); module.exports = { get_filenames: get_filenames } function get_filenames() { filenames = new Set([]); fs.readdirSync("data/").forEach(function(filename) { filenames.add(filename.replace('_train', '').replace('_test', '').replace('.json', '' )) }); filenames = Array.from(filenames.values()) filenames.sort(); filenames.splice(filenames.indexOf('.DS_Store'), 1) return filenames }

Save and exit. For the conclusion of this step, physically move to a new location. There ideally should be a wall between your original location and your new location. The more barriers, the better your desktop app will work.

Once again, run your desktop app.

npm start

Just as before, run the training script. Click on “Add room”.

Home page with “Add New Room” button available (Large preview)

Type in a room name that is different from your first room’s. We will use living room.

“Add New Room” page on load (Large preview)

Click “Start recording,” and you will see the following status “Listening for wifi…”.

“Add New Room” starting recording for second room (Large preview)

Once all 20 samples are recorded, your app will match the following. The status will read “Done. Retraining model…”

“Add New Room” page after recording for second room complete (Large preview)

In the next step, we will use this retrained model to predict the room you’re in, on the fly.

Step 6: Write Python Evaluation Script

In this step, we will load the pretrained model parameters, scan for wifi networks, and predict the room based on the scan.

Open model/eval.py.

nano model/eval.py

Import libraries used and defined in our last script.

import numpy as np import sys import json import os import json from train import predict from train import softmax from train import create_dataset from train import evaluate

Define a utility to extract the names of all datasets. This function assumes that all datasets are stored in data/ as <dataset>_train.json and <dataset>_test.json.

from train import evaluate def get_datasets(): """Extract dataset names.""" return sorted(list({path.split('_')[0] for path in os.listdir('./data') if '.DS' not in path}))

Define the main function, and start by loading parameters saved from the training script.

def get_datasets(): ... def main(): w = np.load('w.npy') ordering = np.load('ordering.npy')

Create the dataset and predict.

def main(): ... classpaths = [sys.argv[1]] X, _, _ = create_dataset(classpaths, ordering) y = np.asscalar(predict(X, w))

Compute a confidence score based on the difference between the top two probabilities.

def main(): ... sorted_y = sorted(softmax(X.dot(w)).flatten()) confidence = 1 if len(sorted_y) > 1: confidence = round(sorted_y[-1] - sorted_y[-2], 2)

Finally, extract the category and print the result. To conclude the script, invoke the main function.

def main() ... category = get_datasets()[y] print(json.dumps({"category": category, "confidence": confidence})) if __name__ == '__main__': main()

Save and exit. Double check your code matches the following (source code):

import numpy as np import sys import json import os import json from train import predict from train import softmax from train import create_dataset from train import evaluate def get_datasets(): """Extract dataset names.""" return sorted(list({path.split('_')[0] for path in os.listdir('./data') if '.DS' not in path})) def main(): w = np.load('w.npy') ordering = np.load('ordering.npy') classpaths = [sys.argv[1]] X, _, _ = create_dataset(classpaths, ordering) y = np.asscalar(predict(X, w)) sorted_y = sorted(softmax(X.dot(w)).flatten()) confidence = 1 if len(sorted_y) > 1: confidence = round(sorted_y[-1] - sorted_y[-2], 2) category = get_datasets()[y] print(json.dumps({"category": category, "confidence": confidence})) if __name__ == '__main__': main()

Next, we will connect this evaluation script to the desktop app. The desktop app will continuously run wifi scans and update the UI with the predicted room.

Step 7: Connect Evaluation To Desktop App

In this step, we will update the UI with a “confidence” display. Then, the associated NodeJS script will continuously run scans and predictions, updating the UI accordingly.

Open static/index.html.

nano static/index.html

Add a line for confidence right after the title and before the buttons.

<h1 class="title" id="predicted-room-name">(I dunno)</h1> <!-- start new code --> <p class="subtitle">with <span id="predicted-confidence">0%</span> confidence</p> <!-- end new code --> <div class="buttons">

Right after main but before the end of the body, add a new script predict.js.

</main> <!-- start new code --> <script> require('../scripts/predict.js') </script> <!-- end new code --> </body>

Save and exit. Open scripts/predict.js.

nano scripts/predict.js

Import the needed NodeJS utilities for the filesystem, utilities, and child process spawner.

var fs = require('fs'); var utils = require('./utils'); const spawn = require("child_process").spawn;

Define a predict function which invokes a separate node process to detect wifi networks and a separate Python process to predict the room.

function predict(completion) { const nodeProcess = spawn('node', ["scripts/observe.js"]); const pythonProcess = spawn('python', ["-W", "ignore", "./model/eval.py", "samples.json"]); }

After both processes have spawned, add callbacks to the Python process for both successes and errors. The success callback logs information, invokes the completion callback, and updates the UI with the prediction and confidence. The error callback logs the error.

function predict(completion) { ... pythonProcess.stdout.on('data', (data) => { information = JSON.parse(data.toString()); console.log(" * [INFO] Room '" + information.category + "' with confidence '" + information.confidence + "'") completion() if (typeof document != "undefined") { document.querySelector('#predicted-room-name').innerHTML = information.category document.querySelector('#predicted-confidence').innerHTML = information.confidence } }); pythonProcess.stderr.on('data', (data) => { console.log(data.toString()); }) }

Define a main function to invoke the predict function recursively, forever.

function main() { f = function() { predict(f) } predict(f) } main();

One last time, open the desktop app to see the live prediction.

npm start

Approximately every second, a scan will be completed and the interface will be updated with the latest confidence and predicted room. Congratulations; you have completed a simple room detector based on all in-range WiFi networks.

Recording 20 samples inside the room and another 20 out in the hallway. Upon walking back inside, the script correctly predicts “hallway” then “bedroom.” (Large preview) Conclusion

In this tutorial, we created a solution using only your desktop to detect your location within a building. We built a simple desktop app using Electron JS and applied a simple machine learning method on all in-range WiFi networks. This paves the way for Internet-of-things applications without the need for arrays of devices that are costly to maintain (cost not in terms of money but in terms of time and development).

Note: You can see the source code in its entirety on Github.

With time, you may find that this least squares does not perform spectacularly in fact. Try finding two locations within a single room, or stand in doorways. Least squares will be large unable to distinguish between edge cases. Can we do better? It turns out that we can, and in future lessons, we will leverage other techniques and the fundamentals of machine learning to better performance. This tutorial serves as a quick test bed for experiments to come.

(ra, il)
Categories: Around The Web

Best Practices For Mobile Form Design

Smashing Magazine - Tue, 08/28/2018 - 10:00am
Best Practices For Mobile Form Design Best Practices For Mobile Form Design Nick Babich 2018-08-28T16:00:09+02:00 2018-09-19T09:23:28+00:00

(This article is kindly sponsored by Adobe.) Forms are the linchpin of all mobile interactions; it stands between the person and what they're looking for. Every day, we use forms for essential online activities. Recall the last time you bought a ticket, booked a hotel room or made a purchase online — most probably those interactions contained a step with filling out a form.

Forms are just a means to an end. Users should be able to complete them quickly and without confusion. In this article, you’ll learn practical techniques that will help you design an effective form.

What Makes For An Effective Form

The primary goal with every form is completion. Two factors have a major impact on completion rate:

  • Perception of complexity
    The first thing users do when they see a new form is estimate how much time is required to complete it. Users do this by scanning the form. Perception plays a crucial role in the process of estimation. The more complex a form looks, the more likely users will abandon the process.
  • Interaction cost
    Interaction cost is the sum of efforts — both cognitive and physical — that the users put into interacting with an interface in order to reach their goal. Interaction cost has a direct connection with form usability. The more effort users have to make to complete a form, the less usable the form is. A high interaction cost could be the result of data that is difficult to input, an inability to understand the meaning of some questions, or confusion about error messages.
The Components Of Forms

A typical form has the following five components:

  • Input fields
    These include text fields, password fields, checkboxes, radio buttons, sliders and any other fields designed for user input.
  • Field labels
    These tell users what the corresponding input fields mean.
  • Structure
    This includes the order of fields, the form’s appearance on the page, and the logical connections between different fields.
  • Action buttons
    The form will have at least one call to action (the button that triggers data submission).
  • Feedback
    Feedback notifies the user about the result of an operation. Feedback can be positive (for example, indicating that the form was submitted successfully) or negative (saying something like, “The number you’ve provided is incorrect”).

This article covers many aspects related to structure, input fields, labels, action buttons and validation. Most points mentioned in this article have visual do and don’t examples; all such examples were created using Adobe XD.

Input Fields

When it comes to form design, the most important thing a designer can do is to minimize the need for typing. Reducing input effort is essential. Designers can achieve this goal by focusing on form field design.

Minimize The Total Number Of Fields

Every field you ask users to fill out requires some effort. The more effort is needed to fill out a form, the less likely users will complete the form. That’s why the foundational rule of form design is shorter is better — get rid of all inessential fields.

Baymard Institute analyzed checkout forms and found that a too long or too complicated checkout process is one of the top reasons for abandonment during checkout. The study found that the average checkout contains almost 15 form fields. Most online services could reduce the number of fields displayed by default by 20 to 60%.

Top reasons for abandonment during checkout. (Image: Baymard Institute) (Large preview)

Many designers are familiar with the “less is more” rule; still, they ask additional questions in an attempt to gather more data about their users. It might be tempting to collect more data about your users during the initial signup, but resist that temptation. Think about it this way: With every additional field you add to your form, you increase the chance of losing a prospective user. Is the information you gain from a field worth losing new users? Remember that, as long as you’ve collected a user’s contact information, you can always follow up with a request for more data.

Clearly Distinguish All Optional Fields

Before optimizing optional fields, ask yourself whether you really need to include them in your form. Think about what information you really need, not what you want. Ideally, the number of optional fields in your form should be zero.

If after a brainstorming session, you still want to include a few optional questions in your form, make it clear for users that those fields are optional:

  • Mark optional fields instead of mandatory ones.
    If you ask as little as possible, then the vast majority of fields in your form will be mandatory. Therefore, mark only those fields in the minority. For instance, if five out of six fields are mandatory, then it makes sense to mark only one field as optional.
  • Use the “Optional” label to denote optional fields.
    Avoid using the asterisk (*) to mean “optional.” Not all users will associate the asterisk with optional information, and some users will be confused by the meaning (an asterisk is often used to denote mandatory fields).
Clearly distinguish all optional fields. (Large preview) Size Fields Accordingly

When possible, use field length as an affordance. The length of an input field should be in proportion to the amount of information expected in the field. The size of the field will act as a visual constraint — the user will know how much text is expected to be entered just by looking at the field. Generally, fields such as ones for area codes and house numbers should be shorter than ones for street addresses.

The size of a field is used as a visual constraint. (Large preview) Offer Field Focus

Auto-focus the first input field in your form. Auto-focusing a field gives the user an indication and a starting point, so that they are able to quickly start filling out the form. By doing that, you reduce the interaction cost — saving the user one unnecessary tap.

Make the active input field prominent and focused. The field focus itself should be crystal clear — users should be able to understand at a glance where the focus is. It could be an accented border color or a fade-in of the box.

Amazon puts strong visual focus on the input field. (Large preview) Don’t Ask Users To Repeat Their Email Address

The reason why an extra field for the email address is so popular among product developers is apparent: Every company wants to minimize the risk of hard bounces (non-deliverables caused by invalid email addresses). Unfortunately, following this approach doesn’t guarantee that you’ll get a valid address. Users often copy and paste their address from one field to another.

Avoid asking users to retype their email address. (Large preview) Provide “Show Password” Option

Duplicating the password input field is another common mistake among product designers. Designers follow this approach because they believe it will prevent users from mistyping a password. In reality, a second field for a password not only increases interaction cost, but also doesn't guarantee that users will proceed without mistakes. Because users don’t see what they’ve entered in the field, they can make the same mistake twice (in both fields) and will face a problem when they try to log in using a password. As Jakob Nielsen summarized:

Usability suffers when users type in passwords and the only feedback they get is a row of bullets. Typically, masking passwords doesn’t even increase security, but it does cost you business due to login failures.

Instead of duplicating the password field, provide an option that allows users to view the password they have chosen to create. Have an icon or checkbox that unmasks the password when clicked. A password preview can be an opportunity for users to check their data before sending.

Not being able to see what you're typing is a huge issue. Providing a 'Show password' option next to the password field will help to solve this problem. (Large preview) Don’t Slice Data Fields

Do not slice fields when asking for a full name, phone number or date of birth. Sliced fields force the user to make additional taps to move to the next field. For fields that require some formatting (such as phone numbers or a date of birth), it’s also better to have a single field paired with clear formatting rules as its placeholder.

Avoid splitting input fields; don’t make people jump between fields. Instead of asking for a first name and last name in two separate fields, have a single 'Full name' field. (Large preview) Avoid Dropdown Menus

Luke Wroblewski famously said that dropdowns should be the UI of last resort. Dropdowns are especially bad for mobile because collapsed elements make the process of data input harder on a small screen: Placing options in a dropdown requires two taps and hides the options.

If you’re using a dropdown for selection of options, consider replacing it with radio buttons. They will make all options glanceable and also reduce the interaction cost — users can tap on the item and select at once.

(Large preview) Use Placeholders And Masked Input

Formatting uncertainty is one of the most significant problems of form design. This problem has a direct connection with form abandonment — when users are uncertain of the format in which they should provide data, they can quickly abandon the form. There are a few things you can do to make the format clear.

Placeholder Text

The text in an input field can tell users what content is expected. Placeholder text is not required for simple fields such as “Full name”, but it can be extremely valuable for fields that require data in a specific format. For example, if you design search functionality for tracking a parcel, it would be good to provide a sample tracking number as a placeholder for the tracking-number field.

(Large preview)

It’s vital that your form should have a clear visual distinction between the placeholder text and the actual value entered by the user. In other words, placeholder text shouldn’t look like a preset value. Without clear visual distinction, users might think that the fields with placeholders already have values.

Masked Input

Field masking is a technique that helps users format inputted text. Many designers confuse field masking with placeholder text — they are not the same thing. Unlike placeholders, which are basically static text, masks automatically format the data provided by the user. In the example below, the parentheses, spaces and dashes appear on the screen automatically as a phone number is entered.

Masked input also makes it easy for users to validate information. When a phone number is displayed in chunks, it makes it easier to find and correct a typo.

Masked input for a phone number. (Image: Josh Morony) Provide Matching Keyboard

Mobile users appreciate apps and websites that provide an appropriate keyboard for the field. This feature prevents them from doing additional actions. For example, when users need to enter a credit card number, your app should only display the dialpad. It’s essential to implement keyboard matching consistently throughout the app (all forms in your app should have this feature).

Set HTML input types to show the correct keypad. Seven input types are relevant to form design:

  • input type="text" displays the mobile device’s normal keyboard.
  • input type="email" displays the normal keyboard and '@' and '.com'.
  • input type="tel" displays the numeric 0 to 9 keypad.
  • input type="number" displays a keyboard with numbers and symbols.
  • input type="date" displays the mobile device’s date selector.
  • input type="datetime" displays the mobile device’s date and time selector.
  • input type="month" displays the mobile device’s month and year selector.
When users tap into a field with credit card number, they should see a numerical dialpad — all numbers, no letters. (Large preview) Use A Slider When Asking For A Specific Range

Many forms ask users to provide a range of values (for example, a price range, distance range, etc.). Instead of using two separate fields, “from” and “to”, for that purpose, use a slider to allow users to specify the range with a thumb interaction.

Sliders are good for touch interfaces because they allow users to specify a range without typing. (Large preview) Clearly Explain Why You’re Asking For Sensitive Information

People are increasingly concerned about privacy and information security. When users see a request for information they consider as private, they might think, “Hm, why do they need this?” If your form asks users for sensitive information, make sure to explain why you need it. You can do that by adding support text below relevant fields. As a rule of thumb, the explanation text shouldn’t exceed 100 characters.

A request for a phone number in a booking form might confuse users. Explain why you are asking for it. (Large preview) Be Careful With Static Defaults

Unlike smart defaults, which are calculated by the system based on the information the system has about users, static defaults are preset values in forms that are the same for all users. Avoid static defaults unless you believe a significant portion of your users (say, 95%) would select those values — particularly for required fields. Why? Because you’re likely to introduce errors — people scan forms quickly, and they won’t spend extra time parsing all of the questions; instead, they’ll simply skip the field, assuming it already has a value.

Protect User Data

Jef Raskin once said, “The system should treat all user input as sacred.” This is absolutely true for forms. It’s great when you start filling in a web form and then accidentally refresh the page but the data remains in the fields. Tools such as Garlic.js help you to persist a form’s values locally until the form is submitted. This way, users won’t lose any precious data if they accidentally close the tab or browser.

Automate Actions

If you want to make the process of data input as smooth as possible, it's not enough to minimize the number of input fields — you should also pay attention to the user effort required for the data input. Typing has a high interaction cost — it’s error-prone and time-consuming, even with a physical keyboard. But when it comes to mobile screens, it becomes even more critical. More typing increases the user’s chance of making errors. Strive to prevent unnecessary typing, because it will improve user satisfaction and decrease error rates.

Here are a few things you can do to achieve this goal:

Autocomplete

Most users experience autocompletion when typing a question in Google’s search box. Google provides users with a list of suggestions related to what the user has typed in the field. The same mechanism can be applied to form design. For example, a form could autocomplete an email address.

This form suggests the email host and saves users from typing a complete address. (Image: GitHub) Autocapitalize

Autocapitalizing makes the first letter a capital automatically. This feature is excellent for fields like names and street addresses, but avoid it for password fields.

Autocorrect

Autocorrection modifies words that appear to be misspelled. Turn this feature off for unique fields, such as names, addresses, etc.

Auto-filling of personal details

Typing an address is often the most cumbersome part of any online signup form. Make this task easier by using the browser function to fill the field based on previously entered values. According to Google’s research, auto-filling helps people fill out forms 30% faster.

Address prefill. Image: Google Use The Mobile Device’s Native Features To Simplify Data Input

Modern mobile devices are sophisticated devices that have a ton of amazing capabilities. Designers can use a device’s native features (such as camera or geolocation) to streamline the task of inputting data.

Below are just a few tips on how to make use of sensors and device hardware.

Location Services

It’s possible to preselect the user’s country based on their geolocation data. But sometimes prefilling a full address can be problematic due to accuracy issues. Google’s Places API can help solve this problem. It uses both geolocation and address prefilling to provide accurate suggestions based on the user’s exact location.

Address lookup using Google Places API. (Image: Chromatic HQ) (Large preview)

Using location services, it’s also possible to provide smart defaults. For example, for a “Find a flight” form, it’s possible to prefill the “From” field with the nearest airport to the user based on the user’s geolocation.

Biometric Authorization

The biggest problem of using a text password today is that most people forget passwords. 82% of people can’t remember their passwords, and 5 to 10% of sessions require users to reset a password. Password recovery is a big deal in e-commerce. 75% of users wouldn't complete a purchase if they had to attempt to recover their password while checking out.

The future of passwords is no passwords. Even today, mobile developers can take advantage of biometric technologies. Users shouldn’t need to type a password; they should be able to use biometric readers for authentication — signing in using a fingerprint or face scanning.

eBay took advantage of the biometrics functionality on smartphones. Users can use their thumbprint to login into their eBay account. (Large preview) Camera

If your form asks users to provide credit card details or information from their driver’s license, it’s possible to simplify the process of data input by using the camera as a scanner. Provide an option to take a photo of the card and fill out all details automatically.

Let users scan their identity card, instead of having to fill out their credit card information manually. (Image: blinkid)

But remember that no matter how good your app fills out the fields, it’s essential to leave them available for editing. Users should be able to modify the fields whenever they want.

Voice

Voice-controlled devices, such as Apple HomePod, Google Home and Amazon Echo, are actively encroaching on the market. The number of people who prefer to use voice for common operations has grown significantly. According to ComScore, 50% of all searches will be voice searches by 2020.

How people in the US use smart speakers (according to comScore) (Large preview)

As users get more comfortable and confident using voice commands, they will become an expected feature of mobile interactions. Voice input provides a lot of advantages for mobile users — it’s especially valuable in situations when users can’t focus on a screen, for example, while driving a car.

When designing a form, you can provide voice input as an alternative method of data input.

Google Translate provides an option to enter the text for translation using voice. (Large preview) Field Labels Write Clear And Concise Labels

The label is the text that tells users what data is expected from them in a particular input field. Writing clear labels is one of the best ways to make a form more accessible. Labels should help the user understand what information is required at a glance.

Avoid using complete sentences to explain. A label is not help text. Write succinct and crisp labels (a word or two), so that users can quickly scan your form.

Place The Label And Input Close Together

Put each label close to the input field, because the eye will visually know they’re tied together.

A label and its field should be visually grouped, so that users can understand which label belongs to which field. (Large preview) Don’t Use Disappearing Placeholder Text As Labels

While inline labels look good and save valuable screen estate, these benefits are far outweighed by the significant usability drawbacks, the most critical of which is the loss of context. When users start entering text in a field, the placeholder text disappears and forces people to recall this information. While it might not be a problem for simple two-field forms, it could be a big deal for forms that have a lot of fields (say, 7 to 10). It would be tough for users to recall all field labels after inputting data. Not surprisingly, user testing continually shows that placeholders in form fields often hurt usability more than help.

Don’t use placeholder text that disappears when the user interacts with the field. (Large preview)

There’s a simple solution to the problem of disappearing placeholders: the floating (or adaptive) label. After the user taps on the field with the label placeholder, the label doesn’t disappear, it moves up to the top of the field and makes room for the user to enter their data.

Floating labels assure the user that they’ve filled out the fields correctly. (Image: Matt D. Smith) Top-Align Labels

Putting field labels above the fields in a form improves the way users scan the form. Using eye-tracking technology for this, Google showed that users need fewer fixations, less fixation time and fewer saccades before submitting a form.

Another important advantage of top-aligned labels is that they provide more space for labels. Long labels and localized versions will fit more easily in the layout. The latter is especially suitable for small mobile screens. You can have form fields extend the full width of the screen, making them large enough to display the user’s entire input.

(Large preview) Sentence Case Vs. Title Case

There are two general ways to capitalize words:

  • Title case: Capitalize every word. “This Is Title Case.”
  • Sentence case: Capitalize the first word. “This is sentence case.”

Using sentence case for labels has one advantage over title case: It is slightly easier (and, thus, faster) to read. While the difference for short labels is negligible (there’s not much difference between “Full Name” and “Full name”), for longer labels, sentence case is better. Now You Know How Difficult It Is to Read Long Text in Title Case.

Avoid Using Caps For Labels

All-caps text  —  meaning text with all of the letters cap­i­tal­ized  —  is OK in contexts that don’t involve substantive reading (such as acronyms and logos), but avoid all caps otherwise. As mentioned by Miles Tinker in his work Legibility of Print, all-capital print dramatically slows the speed of scanning and reading compared to lowercase type.

All-capitalized letters are hard to scan and read. (Large preview) Layout

You know by now that users scan web pages, rather than read them. The same goes for filling out forms. That’s why designers should design a form that is easy to scan. Allowing for efficient, effective scanning is crucial to making the process of the filling out a form as quick as possible.

Use A Single-Column Layout

A study by CXL Institute found that single-column forms are faster to complete than multi-column forms. In that study, test participants were able to complete a single-column form an average of 15.4 seconds faster than a multi-column form.

Multiple columns disrupt a user’s vertical momentum; with multiple columns, the eyes start zigzagging. This dramatically increases the number of eye fixations and, as a result, the completion time. Moreover, multiple-column forms might raise unnecessary questions in the user, like “Where should I begin?” and “Are questions in the right column equal in importance to questions in the left one?”

In a one-column design, the eyes move in a natural direction, from top to bottom, one line at a time. This helps to set a clear path for the user. One column is excellent for mobile because the screens are longer vertically, and vertical scrolling is a natural motion for mobile users.

There are some exceptions to this rule. It’s possible to place short and logically related fields on the same row (such as for the city and area code).

If a form has horizontally adjacent fields, the user has to scan the form following a Z pattern. When the eyes start zigzagging, it slows the speed of comprehension and increases completion time. (Large preview) (Large preview) Create A Flow With Your Questions

The way you ask questions also matters. Questions should be asked logically from the user’s perspective, not according to the application or database’s logic, because it will help to create a sense of conversation with the user. For example, if you design a checkout form and asks for details such as full name, phone number and credit card, the first question should be for the full name. Changing the order (for example, starting with a phone number instead of a name) leads to discomfort. In real-world conversations, it would be unusual to ask for someone’s phone number before asking their name.

Defer In-Depth Questions To The End

When it comes to designing a flow for questions you want to ask, think about prioritization. Follow the rule “easy before difficult” and place in-depth or personal questions last. This eases users into the process; they will be more likely to answer complex and more intrusive questions once they’ve established a rapport. This has a scientific basis: Robert Cialdini’s principle of consistency stipulates that when someone takes a small action or step towards something, they feel more compelled to finish.

Group Related Fields Together

One of the principles of Gestalt psychology, the principle of proximity, states that related elements should be near each other. This principle can be applied to the order of questions in a form. The more related questions are, the closer they should be to each other.

Designers can group related fields into sections. If your form has more than six questions, group related questions into logical sections. Don’t forget to provide a good amount of white space between sections to distinguish them visually.

Generally, if your form has more than six questions, it’s better to group related questions into logical sections. Put things together that make sense together. (Large preview) Make A Long Form Look Simpler

How do you design a form that asks users a lot of questions? Of course, you could put all of the questions on one screen. But this hinder your completion rate. If users don’t have enough motivation to complete a form, the form’s complexity could scare them away. The first impression plays a vital role. Generally, the longer or more complicated a form seems, the less likely users will be to start filling in the blanks.

Minimize the number of fields visible at one time. This creates the perception that the form is shorter than it really is.

There are two techniques to do this.

Progressive Disclosure

Progressive disclosure is all about giving users the right thing at the right time. The goal is to find the right stuff to put on the small screen at the right time:

  • Initially, show users only a few of the most important options.
  • Reveal parts of your form as the user interacts with it.
Using progressive disclosure to reduce cognitive load and keep the user focused on a task. (Image: Ramotion) Chunking

Chunking entails breaking a long form into steps. It’s possible to increase the completion rate by splitting a form into a few steps. Chunking can also help users process, understand and remember information. When designing multi-step forms, always inform users of their progress with a completeness meter.

Progress tracker for e-commerce form. (Image: Murat Mutlu) (Large preview)

Designers can use either a progress tracker (as shown in the example above) or a “Step # out of #” indicator both to tell how many steps there are total and to show how far along the user is at the moment. The latter approach could be great for mobile forms because step indication doesn’t take up much space.

Action Buttons

A button is an interactive element that direct users to take an action.

Make Action Buttons Descriptive

A button’s label should explain what the button does; users should be able to understand what happens after a tap just by looking at the button. Avoid generic labels such as “Submit” and “Send”, using instead labels that describe the action.

Label should help users finish the sentence, 'I want to…' For example, if it’s a form to create an account, the call to action could be 'Create an account'. (Large preview) Don’t Use Clear Or Reset Buttons

Clear or reset buttons allow users to erase their data in a form. These buttons almost never help users and often hurt them. The risk of deleting all of the information a user has entered outweighs the small benefit of having to start again. If a user fills in a form and accidentally hits the wrong button, there’s a good chance they won’t start over.

Use Different Styles For Primary And Secondary Buttons

Avoid secondary actions if possible. But if your form has two calls to action (for example, an e-commerce form that has “Apply discount” and “Submit order”) buttons, ensure a clear visual distinction between the primary and secondary actions. Visually prioritize the primary action by adding more visual weight to the button. This will prevent users from tapping on the wrong button.

Ensure a clear visual distinction between primary and secondary buttons. (Large preview) Design Finger-Friendly Touch Targets

Tiny touch targets create a horrible user experience because they make it challenging for users to interact with interactive objects. It’s vital to design finger-friendly touch targets: bigger input fields and buttons.

The image below shows that the width of the average adult finger is about 11 mm.

People often blame themselves for having “fat fingers”. But even baby fingers are wider than most touch targets. (Image: Microsoft) (Large preview)

According to material design guidelines, touch targets should be at least 48 × 48 DP. A touch target of this size results in a physical size of about 9 mm, regardless of screen size. It might be appropriate to use larger touch targets to accommodate a wider spectrum of users.

Not only is target size important, but sufficient space between touch targets matters, too. The main reason to maintain a safe distance between touch targets is to prevent users from touching the wrong button and invoking the wrong action. The distance between buttons becomes extremely important when binary choices such as “Agree” and “Disagree” are located right next to each other. Material design guidelines recommend separating touch targets with 8 DP of space or more, which will create balanced information density and usability.

(Large preview) Disable Buttons After Tap

Forms actions commonly require some time to be processed. For example, data calculation might be required after a submission. It’s essential not only to provide feedback when an action is in progress, but also to disable the submit button to prevent users from accidentally tapping the button again. This is especially important for e-commerce websites and apps. By disabling the button, you not only prevent duplicate submissions, which can happen by accident, but you also provide a valuable acknowledgment to users (users will know that the system has received their submission).

This form disables the button after submission. (Image: Michaël Villar) Assistance And Support Provide Success State

Upon successful completion of a form, it’s critical to notify users about that. It’s possible to provide this information in the context of an existing form (for example, showing a green checkmark above the refreshed form) or to direct users to a new page that communicates that their submission has been successful.

Example of success state. (Image: João Oliveira Simões) Errors And Validation

Users will make mistakes. It’s inevitable. It’s essential to design a user interface that supports users in those moments of failures.

While the topic of errors and validation deserves its own article, it’s still worth mentioning a few things that should be done to improve the user experience of mobile forms.

Use Input Constraints for Each Field

Prevention is better than a cure. If you’re a seasoned designer, you should be familiar with the most common cases that can lead to an error state (error-prone conditions). For example, it’s usually hard to correctly fill out a form on the first attempt, or to properly sync data when the mobile device has a poor network connection. Take these cases into account to minimize the possibility of errors. In other words, it’s better to prevent users from making errors in the first place by utilizing constraints and offering suggestions.

For instance, if you design a form that allows people to search for a hotel reservation, you should prevent users from selecting check-in dates that are in the past. As shown in the Booking.com example below, you can simply use a date selector that allows users only to choose today’s date or a date in the future. Such a selector would force users to pick a date range that fits.

You can significantly decrease the number of mistakes or incorrectly inputted data by putting constraints on what can be inputted in the field. The date picker in Booking.com’s app displays a full monthly calendar but makes past dates unavailable for selection. (Large preview) Don’t Make Data Validation Rules Too Strict

While there might be cases where it’s essential to use strict validation rules, in most cases, strict validation is a sign of lazy programming. Showing errors on the screen when the user provides data in a slightly different format than expected creates unnecessary friction. And this would have a negative impact on conversions.

It’s very common for a few variations of an answer to a question to be possible; for example, when a form asks users to provide information about their state, and a user responds by typing their state’s abbreviation instead of the full name (for example, CA instead of California). The form should accept both formats, and it’s the developer job to convert the data into a consistent format.

Clear Error Message

When you write error messages, focus on minimizing the frustration users feel when they face a problem in interacting with a form. Here are a few rules on writing effective error messages:

  • Never blame the user.
    The way you deliver an error message can have a tremendous impact on how users perceive it. An error message like, “You’ve entered a wrong number” puts all of the blame on the user; as a result, the user might get frustrated and abandon the app. Write copy that sounds neutral or positive. A neutral message sounds like, “That number is incorrect.”
  • Avoid vague or general error messages.
    Messages like “Something went wrong. Please, try again later” don’t say much to users. Users will wonder what exactly went wrong. Always try to explain the root cause of a problem. Make sure users know how to fix errors.
  • Make error messages human-readable.
    Error messages like “User input error: 0x100999” are cryptic and scary. Write like a human, not like a robot. Use human language, and explain what exactly the user or system did wrong, and what exactly the user should do to fix the problem.
Display Errors Inline

When it comes to displaying error messages, designers opt for one of two locations: at the top of the form or inline. The first option can make for a bad experience. Javier Bargas-Avila and Glenn Oberholzer conducted research on online form validation and discovered that displaying all error messages at the top of the form puts a high cognitive load on user memory. Users need to spend extra time matching error messages with the fields that require attention.

Avoid displaying errors at the top of the form. (Image: John Lewis) (Large preview)

It’s much better to position error messages inline. First, this placement corresponds with the user’s natural top-to-bottom reading flow. Secondly, the errors will appear in the context of the user’s input.

eBay uses inline validation. (Large preview) Use Dynamic Validation

The time at which you choose to display an error message is vital. Seeing an error message only after pressing the submit button might frustrate users. Don’t wait until users finish the form; provide feedback as data is being entered.

Use inline validation with real-time feedback. This validation instantly tells people whether the information they’ve typed is compatible with the form’s requirements. In 2009, Luke Wroblewski tested inline validation against post-submission validation and found the following results for the inline version:

  • 22% increase in success rate,
  • 22% decrease in errors made,
  • 31% increase in satisfaction rating,
  • 42% decrease in completion times,
  • 47% decrease in the number of eye fixations.

But inline validation should be implemented carefully:

  • Avoid showing inline validation on focus.
    In this case, as soon as the user taps a field, they see an error message. The error appears even when the field is completely empty. When an error message is shown on focus, it might look like the form is yelling at the user before they’ve even started filling it out.
  • Don’t validate after each character typed.
    This approach not only increases the number of unnecessary validation attempts, but it also frustrates users (because users will likely see error messages before they have completed the field). Ideally, inline validation messages should appear around 500 to 1000 milliseconds after the user has stopped typing or after they’ve moved to the next field. This rule has a few exceptions: It’s helpful to validate inline as the user is typing when creating a password (to check whether the password meets complexity requirements), when creating a user name (to check whether a name is available) and when typing a message with a character limit.
Reward early, punish late is a solid validation  approach. (Image: Mihael Konjević) Accessibility

Users of all abilities should be able to access and enjoy digital products. Designers should strive to incorporate accessibility needs as much as they can when building a product. Here are a few things you can do to make your forms more accessible.

Ensure The Form Has Proper Contrast

Your users will likely interact with your form outdoors. Ensure that it is easy to use both in sun glare and in low-light environments. Check the contrast ratio of fields and labels in your form. The W3C recommends the following contrast ratios for body text:

  • Small text should have a contrast ratio of at least 4.5:1 against its background.
  • Large text (at 14-point bold, 18-point regular and up) should have a contrast ratio of at least 3:1 against its background.

Measuring color contrast can seem overwhelming. Fortunately, some tools make the process simple. One of them is Web AIM Color Contrast Checker, which helps designers to measure contrast levels.

Do Not Rely On Color Alone To Communicate Status

Color blindness (or color vision deficiency) affects approximately 1 in 12 men (8%) and 1 in 200 women in the world. While there are many types of color blindness, the most common two are protanomaly, or reduced sensitivity to red light, and deuteranomaly, or reduced sensitivity to green light. When displaying validation errors or success messages, don’t rely on color alone to communicate the status (i.e. by making input fields green or red). As the W3C guidelines state, color shouldn’t be used as the only visual means of conveying information, indicating an action, prompting a response or distinguishing a visual element. Designers should use color to highlight or complement what is already visible. Support colorblind people by providing additional visual cues that help them understand the user interface.

Use icons and supportive text to show which fields are invalid. This will help colorblind people fix the problems. (Large preview) Allow Users To Control Font Size

Allow users to increase font size to improve readability. Mobile devices and browsers include features to enable users to adjust the font size system-wide. Also, make sure that your form has allotted enough space for large font sizes.

WhatsApp provides an option to change the font size in the app’s settings. (Large preview) Test Your Design Decisions

All points mentioned above can be considered as industry best practices. But just because something is called a “best practice” doesn’t mean it is always the optimal solution for your form. Apps and websites largely depend on the context in which they are used. Thus, it’s always essential to test your design decisions; make sure that the process of filling out a form is smooth, that the flow is not disrupted and that users can solve any problems they face along the way. Conduct usability testing sessions on a regular basis, collect all valuable data about user interactions, and learn from it.

Conclusion

Users can be hesitant to fill out forms. So, our goal as designers is to make the process of filling out a form as easy as possible. When designing a form, strive to create fast and frictionless interactions. Sometimes a minor change — such as properly writing an error message — can significantly increase the form’s usability.

This article is part of the UX design series sponsored by Adobe. Adobe XD 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.

(al, yk, il)
Categories: Around The Web

UX And HTML5: Let’s Help Users Fill In Your Mobile Form (Part 2)

Smashing Magazine - Mon, 08/27/2018 - 8:00am
UX And HTML5: Let’s Help Users Fill In Your Mobile Form (Part 2) UX And HTML5: Let’s Help Users Fill In Your Mobile Form (Part 2) Stéphanie Walter 2018-08-27T14:00:31+02:00 2018-09-18T09:48:16+00:00

In this second part, I want to focus more on mobile-specific capabilities. HTML5, for instance, has brought us a lot of really cool features to help users fill in mobile forms and format their data. We will see in detail how HTML5 attributes can help you with that. Then, we will go beyond “classic” form elements and see how to use mobile capabilities such as the camera, geolocation and fingerprint scanners to really take your mobile form experience to the next level on websites and in native applications.

Helping The User Format Content With HTML5

In the first part of this series, we saw some general advice on how to display fields. Now it’s time to go a bit deeper and look at how a few well-crafted lines of HTML5 code can improve your mobile forms.

HTML5 Mobile-Optimized Goodness

HTML5 opens a whole world of possibilities for optimizing forms for mobile and touch devices. A lot of interesting new input types can trigger different keyboards to help users. We can also do some interesting things with capturing media directly in the browser.

Entering Numerical Data

input type= number

The HTML5 <input type=number> attribute restricts an input field to numbers. It has a built-in validation system that rejects anything that is not a number.

In some desktop browsers, this input is presented with little arrows on the right that the user can click to increment the number. On mobile, it opens a keyboard with numbers, which decreases typos and form-validation errors. The input’s look and feel depend on the operating system.

On the left, Android’s keyboard, and on the right, the iOS keyboard with numbers. (Large preview)

The input should allow for decimals and negative numbers (but few keyboards respect that). As explained in the W3C’s specifications, “a simple way of determining whether to use type=number is to consider whether it would make sense for the input control to have a spinbox interface (e.g. with ‘up’ and ‘down’ arrows)”. This means that the input is not supposed to be used for credit cards or area codes.

Meet SmashingConf New York 2018 (Oct 23–24), focused on real challenges and real front-end solutions in the real world. From progressive web apps, Webpack and HTTP/2 to serverless, Vue.js and Nuxt — all the way to inclusive design, branding and machine learning. With Sarah Drasner, Sara Soueidan and many other speakers.

Check all topics and speakers ↬

The pattern And inputmode Attributes

To add some restrictions to your number inputs, you could use the pattern attribute to specify a regular expression against which you want to control values.

This is what it looks like:

<input type="number" id="quantity" name="quantity" pattern="[0-9]*" inputmode="numeric" />

You can use this pattern to bring up the big-button numeric keyboard on the iPhone (but not the iPad). This keyboard does not have the minus sign or comma, so users lose the ability to use negative numbers and decimals. Also, they can’t switch back to another keyboard here, so be careful when using this.

Also, note that patterns can be applied to any other type of inputs.

Using only this pattern won’t work on most Android phones. You’ll still need a combination of input type=number and the attribute to make this work.

Android and iOS demo with input type=number, pattern and inputmode. (Large preview)

inputmode

If you only want to trigger the mobile numeric keyboard but don’t want to deal with the type=number and pattern mess, you could use a text input and apply the inputmode=numeric attribute. It would look like this:

<input type="text" id="quantity" name="quantity" inputmode="numeric" />

Unfortunately (at the time of writing), only Chrome 67 mobile supports this, but it should be arriving in Chrome desktop 66 without a flag.

To learn more about how to enter numbers in a form, read “I Wanted to Type a Number”.

input type=tel

If you want users to enter a phone number, you can use the input type=tel. As you can see in the screenshot below, it triggers the same digits on iOS’ keyboard as the pattern attribute described above. Due to the complexity of phone numbers across the world, there is no automatic validation with this input type.

input type=tel on Android and iOS (Large preview) Entering Dates

Even if they are technically numerical data, dates deserve their own section. There are a few HTML5 input types for entering dates. The most used is input type=date. It will trigger a date-picker in supported browsers. The appearance of the date-picker depends on the browser and OS. To learn more on how browsers render input type="date", I recommend you read “Making input type=date complicated.”

A date-picker based on input type=date on Android and iOS (Large preview)

There’s also type=week to pick a week, type=time to enter a time (up to the hour and minute), and type=datetime-local to pick a date and a time (using the user’s local time). So many choices!

Example of date-picker with more options on Android (week, date and time, etc.) (Large preview)

input type=date works well for booking interfaces, for example. You might have some needs that require you to build your own date-picker, though (as we’ve already seen in the section on sensible defaults). But input type=date is always a nice option if you need a date-picker and don’t want to bring a whole JavaScript library into the website for the job.

Yet, sometimes not using type=date for dates is better. Let’s take the example of a birth date. If I was born in 1960 (I’m not — this is just an example), it would take me many taps to pick my birth date if I was starting from 2018. On Android, I discovered recently that if I press on the year in the picker, I get a sort of dropdown wheel with all of the years. A bit better, but it still requires a fair amount of scrolling.

A user told me on Twitter:

"I’m born in 1977 and can confirm the annoyance. The more time it takes to scroll, the older you feel :-("

So, maybe birth dates are not the best candidate for date-pickers.

With Android’s date-picker, even though you can press and hold the year to get a year-picker, picking a birth date is still tedious. (Large preview) URL, Email, Tel And Search

Mobile phones hide some other keyboard and input-optimization goodness that enhance the user’s experience when filling in a form. The devil is in the details, as they say.

Using the input type=url field will bring up an optimized keyboard on mobile, with / (the slash key) directly accessible. Depending on the OS, you can also give quick access to commons top-level domains, like the .fr in the screenshot below. If you long-press this button, shortcuts to other top-level domains will appear. This also comes with automatic browser validation that checks that the URL’s format is valid.

input type=url keyboard on Android and iOS (Large preview)

The input type=emailfield brings up an email-optimized keyboard giving quick access to the @ symbol. This input requires the presence of @ somewhere in the field in order to be valid. That’s the only verification it does.

input type=email keyboard on Android and iOS (Large preview)

The input type=search field brings up a search-optimized keyboard. The user can directly launch the search from a button on the keyboard. There’s also a little cross to clear the field and type a new query.

input type=search keyboard on Android and iOS (Large preview) Range And Color

The last two input types we looked at are not particularly optimized for mobile, but by using them, we can avoid having to load heavy custom JavaScript libraries, which is a good idea for mobile users.

input type=range provides a visual UI slider to input a number. The UI for this control is browser-dependent.

input type=color provides an easy way for the user to enter a color value. In many browser implementations, this comes with a color-picker.

input type=range and input type=color on Android and iOS (Large preview) HTML Media Capture: Taking And Uploading Pictures And Recording Sound

I remember the time of the iPhone 3, when Apple would not even allow a simple input type=file to be used on a website, for security reasons. Those times are long gone. With the HTML media capture API, it’s now possible to access different sensors of a device. We can capture photos and videos, and we can even record voice directly in the browser.

The accept attribute lets you specify what kind of media to accept in the input: audio, image, video. The user can give the browser direct access to their camera, for example.

The code looks like this:

<input type="file" id="take-picture" accept="image/*"> The accept attribute is set to image. The browser asks whether I want to access the camera directly or the files on the device. (Large preview)

The capture attribute lets you specify the preferred mode of capture. If you add the capture attribute on top of the accept attribute, you can make the browser open the camera or voice recorder directly.

<input type="file" accept="image/*" capture> // opens the camera> <input type="file" accept="video/*" capture> // opens the camera in video mode <input type="file" accept="audio/*" capture> // opens the voice recorder The mobile browser directly opens the capture mechanism: on the left, the camera, on the right, the video recorder. (Large preview)

For more details on how to use media directly in the browser, read the section “Accessing and Handling Images, Video and Audio Directly in the Browser” in my article on the secret powers of mobile browsers.

HTML5 Autos: Autocorrect, Autocomplete, Autofill, Autocapitalize And Autofocus

HTML5 comes with a slew of automatic attributes. To enhance the mobile experience, you will want to be smart about what can be automated and what can’t. Here are some general rules of thumb:

  • Disable autocorrect on things for which the dictionary is weak: email addresses, numbers, names, addresses, cities, regions, area codes, credit card numbers.
  • Disable autocapitalize for email fields and other fields where appropriate (for example, website URLs). Note that type=email does the job for you in recents version of iOS and Android, but disable it anyway for older versions or if type=email is not supported.
  • You can set the autocapitalize attribute to words to automatically uppercase the first letter of each word the user types. This can be useful for names, places and the like, but, again, be careful with it, and test it.
Use input type=email for email addresses. If you don’t, at least deactivate auto-capitalization. No email address starts with a capital letter. (Large preview)
  • For input type=tel, set autocomplete="tel".
  • You could use autofocus to give the focus to a control element when the user loads the page. But just because the user opens the “contact” page, it does not mean they are ready to jump right to the first field of your form. So, again, use it wisely.
In this example, we could use autofocus to take the user directly to the first field once they’ve clicked on the button. (Large preview)

If you want more autocomplete options, a whole list is on the WhatWG Wiki. Just make sure you use the right ones. Implement, test, and test again.

HTML5 Form Validation

I won’t get into the technical details here, but you should know that HTML5 has a built-in form-validation API for many fields. It’s nice if you don’t want to use a JavaScript library to display inline validation messages. Here are the main things you need to know as a UX designer about HTML5 form validation:

HTML native form validation in an Android browser (Large preview)

In “Native Form Validation, Part 1,” Peter-Paul Koch goes into detail on why HTML and CSS form validation doesn’t really make forms better at this time.

Offline Support To Save User Data

A lot of things can go wrong, especially on mobile. Mistakes happen. A user could mistap the back button in the browser and lose all of their data.

If the user comes back to the page, it would be nice to display their data again. The same goes for if the browser crashes or the user closes the tab. You can store the user’s data in local or session storage to ensure nothing gets lost if something goes wrong. Geoffrey Crofte has written a JavaScript library to help you with that.

If the connection is lost as the user is submitting the form, they might also lose the data. To avoid this, you could use a combination of the** HTML5 offline API** and the Service Workers API to:

  • store the data in the cache,
  • try to automatically send it again when the connection comes back.

To learn how to code this, check out the article on “Offline-Friendly Forms”.

Mobile Device Capabilities Can Take the Experience To The Next Level

In part 1, we stuck to the basic common HTML form elements and attributes for enhancing mobile forms. But mobile devices capabilities now go far beyond displaying HTML, CSS and JavaScript web pages. Those little devices come equipped with a lot of sensors. And we will be able to use many of those in native apps and on the web to make our users’ lives so much easier.

Detecting The User’s Location

In the previous section, I wrote about pre-filling information for places and addresses. That’s a good start. We can go one step further. Instead of asking users to type a location, we can detect it. Meet the geolocation API for the web. There are also native iOS, Android and Windows Phone geolocation APIs.

Citymapper is a website and an app that helps users plan their travels. When the user goes into the first field, they see the “Use current location” option. If they select it, they are asked to allow the browser to access their geolocation data. This is the geolocation API. The browser then autocompletes the location it found and, the user can proceed to the destination field. The native app works pretty much the same way.


Citymapper proposes the user’s current location as the starting point for the journey. Be Smart When Asking For The User’s Permission

You might have noticed in the previous video that I had to agree to give access to my position to the Citymapper website. In the browser, the user handles permissions website by website, API by API.

You also need to be careful how you ask for permission. The user might refuse access to the geolocation, notification or other API if you ask too soon. They also might refuse if they don’t understand why you need the permission. You get one chance; use it wisely. After that, it will be almost impossible to recover. I’m an Android power user, and even I have to search around for the options in my browser when I want to reset the permissions I’ve given to a website. Imagine the trouble your users will have.

Here is some general advice on asking for permissions on the web:

  • Don’t be the creepy geolocation or notification stalker: Don’t ask for permission as soon as the user arrives on your website. They might not know about you or your service yet.
  • Let the user discover your website and service. Then, ask for permission in context. If you want to access their location, ask them only when you need it (Citymapper is a good example).
  • Explain why you need permission and what you will do with it.
Citymapper asks for access to the user’s location only when it needs it. Clearing permissions after the user refuses it can get really complicated because the user will need to search through their settings for that website. (Large preview)

If you want to go further, Luke Wroblewski (yes, him again) has created a nice video to help you with the permission-asking process.

A Better Checkout Experience

A big area of improvement for forms is the whole checkout payment experience. Here again, sensors on the device can make this an almost painless experience. The only pain will be the amount of money the user spends.

iOS Credit Card Scanner

In the previous section, I wrote about autodetection of credit cards and autocompletion features based on the user’s previous input. This still means that the user has to type their credit card data at least once.

Apple has taken this to the next level with its credit card scanner. Since iOS 8 in Safari, users can use their camera to scan and autocomplete their credit card information. To perform this magic, you will need to add the autocomplete cc-number attribute and some name to identify this as a credit card field. Apple doesn’t have much official information on it, but some people did some testing and put the results on StackOverflow.

Safari also has autofill options that users can use to add their credit card, allowing them reuse it on multiple websites.

The credit card scanning option appears when Safari detects a field that matches the credit card format. If the user already has a card registered on the phone, they can use the autofill option. (Large preview) Take Checkout One Step Further With Google Pay API

Google launched something similar: the Google Pay API. When implemented on a website, the API eliminates the need to manually enter payment information. It goes one step further: It can store billing and shipping addresses as well.

The user gets a dialog in Chrome that displays the various payment information they’ve stored. They can choose which one to use and can pay directly through the dialog.

The Google Pay API pop-up triggered on an e-commerce website (Source) (Large preview)

A standardized version of the Payment Request API is currently a W3C candidate recommendation. If this gets implemented in browsers, it would allow users to check out with a single button, which would request the API. Every step thereafter would be handled by native browser dialogs.

Making Authentication Easier

Mobile phones are, in most cases, personal devices that people don’t usually share with others. This opens up some interesting opportunities for authentication.

Magic Link

I use a password manager. I don’t know 99% of my passwords. They are all randomly generated. In order to log into a new Slack workspace, I must:

  1. open my password manager,
  2. enter my master password,
  3. search for the workspace,
  4. copy and paste the password into the Slack app.

It’s a tedious process, but Slack was smart enough to provide a better option.

Many users have they mail synchronized on their phone. Slack understood that. When you add a new Slack workspace in the app, you can either log in using the password or ask for the “magic link” option. If you opt for the latter, Slack sends a magic link to your mailbox. Open the mail, click on the big green button, and — ta-da! — you’re logged in.

Behind the scenes, this magic link contains an authentication token. The Slack app catches this and authenticates you without requiring the password.

When using the magic link option, Slack sends you an email with a link that lets you connect to your slack without having to enter your password. (Large preview) Fingerprint For Smart Identification

I do almost all of my banking on my mobile device. And when it comes to logging into my bank accounts, there’s a world of difference between my French Societe General bank app and the German N26 app.

With Société Générale, I have a login string and a passphrase. I can ask the app to remember the login string, which is 10 random digits. I’m not able to remember that one; I use a password manager for it. I must still remember and enter the six-digit passphrase on a custom-built keypad. Of course, the numbers’ positions change every time I log in. Security — yeah, I know. Also, I must change this passphrase every three months. The last time I was forced to change the passphrase, I did what most people do: choose almost the same passphrase, because I don’t want to have to remember yet another six-digit number. And of course, I was damn sure I would remember it, so I did not enter it in my password manager. Rookie mistake. Two weeks later, I tried to log in. Of course, I forgot it. I made three failed attempts, and then my account was blocked. Fortunately, I only use this account for savings. In the app, you can ask for a new passcode. It took almost one week for the bank to send me a new six-digit passphrase by paper mail to my home address in Luxembourg. Yeah.

N26, on the other hand, uses my email address as the login string. I can remember that without a password manager. When I want to log in, I put my finger on the start button of my Xperia phone, and that’s it. In the background, my phone scans my fingerprint and authenticates me. If that does not work, I can fall back to a password.

Same device, two apps, two totally different experiences.

Dropbox has another example of fingerprint authentication. (Large preview)

More and more apps on both Android and iOS now offer user the possibility to authenticate with a fingerprint. No more passwords — it’s an interesting and elegant solution.

Of course, people have expressed some security concerns about this. For the National Institute of Standards and Technology (NIST), biometrics is not considered secure enough. It advises combining biometrics with a second factor of authentication.

Fingerprint sensors can also be tricked — yes, like in spy movies. Did you hear about the plane that was forced to land because a woman learned of her husband’s infidelity after using his thumb to unlock his phone while he was sleeping?

Facial Recognition And Face ID

In 2018, Apple launched the iPhone X with the brand new face ID. Users can unlock their iPhone X using their face. Of course, some other Android phones and Windows tablets and computers had proposed this feature earlier. But when Apple launches something, it tends to become “a thing”. For the moment, this technology is mostly used as authentication to unlock phones and computer.

There are some pretty big challenges with facial-recognition technology. First, some algorithms can be fooled by a picture of the person, which is easily hackable. Another bigger concern is diversity. Facial-recognition algorithms tend to have difficulty recognizing people of color. For instance, a black researcher had to wear a white mask to test her own project. The researcher is Joy Buolamwini, and she gave a TED talk about the issue.

Some facial-recognition software is also used by some customs services to speed up border processing. It is used in New Zealand and will be used in Canada.

Most of us have seen enough science fiction to see the potential problems and consequences of systems that use facial recognition at scale. This kind of technology used outside of the private space of unlocking phones can get controversial and scary.

Google: One-Tap Sign-Up

If a user has a Google account, they can benefit from Google’s one-tap sign-up. When visiting a website and prompted to create an account in an inline dialog, the user doesn’t need to enter a password. Google provides a secure token-based password-less account, linked to the user’s Google account. When the user returns, they are automatically signed in. If they store their passwords in the Smart Lock, they get automatically signed in on other devices as well.

Google’s one-tap sign-up dialog (Source) (Large preview)

Note: This is an interesting password-less solution. Of course, by using it, users are linked to Google, which not everyone will feel comfortable with.

Conclusion

You can do a lot of really cool things when you start using mobile capabilities to help users fill in forms. We need a mobile-first mindset when building forms; otherwise, we’ll get stuck on the desktop capabilities we are familiar with.

Again, be careful with the device’s capabilities: always have a fallback solution in case a sensor fails or the user refuses access. Avoid making those capabilities the only options for those functions (unless you are building a map app that relies on geolocation).

This is the end of a series of two really long articles in which I’ve given you some general UX and usability advice and best practices. In the end, what matter are your form and your users. Some things described here might not even work specifically for your users — who knows? So, whatever you do, don’t take my (or Luke’s) word for it. Test it, with real users, on real devices. Measure it. And test again. Do some user research and usability testing. User experience is not only about best practices and magic recipes that you copy and paste. You need to adapt the recipe to make it work for you.

So, in short: Test it. Test it on real devices. Test it with real users.

(lf, ra, al, il)
Categories: Around The Web
Syndicate content