When working in a team, we focus so much on the work, that we often forget that we all have something in common. Something that is so obvious that we underestimate it: we all are human beings. And well, if we want to grow as a team and get better at what we do, we should embrace this fact more. In fact, I just came back from a week-long team retreat where we had team activities, team games, and sessions and discussions about how we can achieve just that.
We figured out how much we value diversity, we realized how different the English language and its words are perceived by people from different countries, and we’ve seen short talks on various topics like work-life-balance but also on technical stuff like Docker or intercepting any computer’s traffic with a Raspberry Zero. So if you have the chance to work in a team, use the opportunity and exchange views and share information with your co-workers. Work is part of your life, so why not make it a lovely part?
Say hello to Firefox 511. It ships unprefixed ::placeholder, broader ES2015 support, WebGL 2, IndexedDB v2, and tabindex for SVG. Scripts served with an image/*, video/*, audio/* or text/csv MIME type are now blocked.
Rachel Andrew explains the new display property value flow-root17 that was added to Chrome and Firefox (both Nightly/Canary only) and why it will finally replace the old clearfix hacks that we’re currently using to fix parent box sizes when floating inner elements.
So, you want to give your projects some extra love? With Valentine’s Day coming up soon, we’ve got a fresh new set that consists of a delicious selection — just like a good box of chocolates. Take a peek, and you’ll find icons especially tailored to e-commerce1 projects (such as shopping carts and price tags), but also some more versatile motifs like a love letter, calendar, and even a WiFi sign that sends off some lovely vibes.
2 Sugar-sweet icons dedicated to special designers and websites (Large preview3)
This catchy icon set is available in two different styles — each available in AI, SVG, EPS, Sketch, CSH and PNG formats. Thanks to the creative minds behind Roundicons104 who created these 30 sugar-sweet icons dedicated just for you to use for all things valentine. Perfect to spread some love, and hopefully, conquer the hearts of your users.
Please note that the set is released under a Creative Commons Attribution 3.0 Unported8. This means that you may modify the size, color and shape of the icons (more details in the readme.txt file). No attribution is required, however, reselling of bundles or individual pictograms is not cool. If you would like to spread the word in blog posts or anywhere else, please also remember to credit the designers and provide a link to this article.
“We’re proud to share this icon set: it’s part of a 4-year-old project that is being used by thousands of designers around the world, and will keep growing. We hope you like each one, and don’t forget to spread the love!”
A big thank you to Roundicons — we sincerely appreciate your time and efforts. Keep up the brilliant work!
When the Russian ruble’s exchange rate slumped two years ago, it drove us to think of cutting hardware and hosting costs for the Mail.Ru email service. To look at ways to save money, let’s first take a look at what email consists of.
Indexes and bodies account for only 15% of the storage size, whereas 85% is taken up by files. So, optimization of files (that is, attachments) is worth exploring in more detail. At the time, we didn’t have file deduplication in place, but we estimated that it could shrink the total storage size by 36%, because many users receive the same messages, such as price lists from online stores and newsletters from social networks that contain images2 and so on. In this article, I’ll describe how we implemented a deduplication system under the guidance of PSIAlt3.
We’re dealing with a stream of files. When we receive a message, we must deliver it to the user as soon as possible. We need to be able to quickly recognize duplicates. An easy solution would be to name files based on their contents. We’re using SHA-1 for this purpose. The initial name of the file is stored in the email itself, so we don’t need to worry about it.
Once a new email arrives, we retrieve the files, compute their hashes and add the result to the email. It’s a necessary step to be able to easily locate the files belonging to a particular email in our future storage when this email is being sent.
Now, let’s upload a file to our storage and find out whether another file with the same hash already exists there. This means we’ll need to store all hashes in memory. Let’s call this storage for hashes “FileDB.”
The counter increments with every new file uploaded. About 40% of all files are deleted, so if a user deletes an email containing files uploaded to the cloud, the counter must be decremented. If the counter reaches zero, the file can be deleted.
Here we face the first issue: Information about an email (indexes) is stored in one system, whereas information about a file is stored in another. This could lead to an error. For example, consider the following workflow:
In this case, the email stays in the system, but the counter gets decremented by 1. When the system receives a second request to delete this email, the counter gets decremented again — and we could encounter a situation in which the file is still attached to an email but the counter is already at 0.
Not losing data is critical. We can’t have a situation in which a user opens an email and discovers no attachment there. That being said, storing some redundant files on disks is no big deal. All we need is a mechanism to unambiguously determine whether the counter is correctly set to 0. That’s why we have one more field — magic.
The algorithm is simple. Along with the hash of a file, we store a randomly generated number in an email. All requests to upload or delete a file take this random number into account: In case of an upload request, this number is added to the current value of the magic number; if it’s a delete request, this random number is subtracted from the current value of the magic number.
Thus, if all emails have incremented and decremented the counter the correct number of times, then the magic number will also equal 0. Otherwise, the file must not be deleted.
Let’s consider an example. We have a file named sha1. It’s uploaded once, and the email generates a random (magic) number for it, which is equal to 345.
Then a new email arrives with the same file. It generates its own magic number (123) and uploads the file. The new magic number is added to the current value of the magic number (345), and the counter gets incremented by 1. As a result, what we have in FileDB is the magic number with the value of 468 and the counter set to 2.
After the user deletes the second email, the magic number generated for this email is subtracted from the current value of the magic number (468), and the counter gets decremented by 1.
Let’s first look at the normal course of events. The user deletes the first email, and the magic number and the counter both become 0. This means the data is consistent and the file can be deleted.
Now, suppose something goes wrong: The second email sends two delete requests. The counter being equal to 0 means there are no more links to the file, but the magic number, which equals 222, signals a problem: The file can’t be deleted until the data is consistent.
Let’s develop the situation a little more. Suppose the first email also gets deleted. In this case, the magic number (-123) still signals an inconsistency.
As a safety measure, once the counter reaches 0 but the magic number doesn’t (in our case, the magic number is 222 and the counter is 0), the file is assigned a “Do not delete” flag. This way, even if — after a series of deletions and uploads — both the magic number and the counter somehow become 0, we’ll still know that this file is problematic and must not be deleted. The system isn’t allowed to generate a magic peer 0. If you send 0 as the magic number, you’ll receive an error.
Back to FileDB. Every entity has a set of flags. Whether you plan to use them or not, you’re going to need them (if, say, a file needs to be marked as undeletable).
We have all of the file attributes, except for where the file is physically located. This place is identified by a server (IP) and a disk. There should be two such servers and two such disks. We store two copies of each file.
But one disk stores a lot of files (in our case, about 1 million), which means these records will be identified by the same disk pair in FileDB, so storing this information in FileDB would be wasteful. Let’s put it in a separate table, PairDB, linked to FileDB via a disk pair ID.
I guess it goes without saying that, apart from a disk pair ID, we’ll also need a flags field. I’ll jump ahead a bit and mention that this field signals whether the disks are locked (say, one disk has crashed and the other is being copied, so no new data can be written to either of them).
To make sure everything works fast, both FileDB and PairDB must be RAM-resident. We were using Tarantool 1.5, but now the latest version should be used. FileDB has five fields (20, 4, 4, 4 and 4 bytes long), which add up to 36 bytes. Also, each record has a 16-byte header, plus a 1-byte length pointer per field, which brings the total record size to 57 bytes.
Tarantool allows you to specify the minimum allocation size, so memory-associated overhead can be kept close to zero. We’ll be allocating the exact amount of memory needed for one record. We have 12 billion files.
(57 * 12 * 10^9) / (1024^3) = 637 GB
But that’s not all, we’ll also need an index on the sha1 field, which adds 12 more bytes to the total record size.
(12 * 12 * 10^9) / (1024^3) = 179 GB
All in all, 800 GB of RAM are needed. And let’s not forget about replication, which doubles the amount of RAM required.
If we buy machines with 256 GB of RAM on board, we’d need eight of them.
We can assess the size of PairDB. The average file size is 1 MB and disk capacity is 1 TB, which allows storage of about 1 million files on a single disk; so, we’d need some 28,000 disks. One PairDB record describes two disks. Therefore, PairDB contains 14,000 records — negligible compared to FileDB.
Now that we’ve got the database structure out of the way, let’s turn to the API for interacting with the system. At first glance, we need the upload and delete methods. But don’t forget about deduplication: Chances are good that the file we’re trying to upload is already in storage, and uploading it a second time wouldn’t make sense. So, the following methods are necessary:
inc(sha1, magic) increments the counter. If a file doesn’t exist, it returns an error. Recall that we also need a magic number that helps to prevent incorrect file deletion.
upload(sha1, magic) should be called if inc has returned an error, which means this file doesn’t exist and must be uploaded.
dec(sha1, magic) should be called if a user deletes an email. The counter is decremented first.
GET /sha1 downloads a file via HTTP.
Let’s take a closer look at what happens during uploading. For the daemon that implements this interface, we chose the IProto protocol. Daemons must scale well to any number of machines, so they don’t store states. Suppose we receive a request via a socket:
The command name tells us the header’s length, so we read the header first. Now, we need to know the length of the origin-len file. It’s necessary to choose a couple of servers to upload it. We just retrieve all of the records (a few thousand) from PairDB and use the standard algorithm to find the needed pair: Take a segment with the length equal to the sum of free spaces on all pairs, randomly pick a point on this segment, and choose whatever pair this point belongs to.
However, choosing a pair this way is risky. Suppose all of our disks are 90% full — and then we add a new empty disk. It’s highly likely that all new files will be uploaded to this disk. To avoid this problem, we should sum not the free space of a disk pair, but the nth root of this free space.
So, we’ve chosen a pair, but our daemon is a streaming one, and if we start uploading a file to storage, there’s no turning back. That being said, before uploading a real file, we’ll upload a small test file first. If the test upload is successful, we’ll read filecontent from the socket and upload it to storage; otherwise, another pair is chosen. SHA-1 hash can be read on the fly, so it is also checked during uploading.
Let’s now examine a file upload from a loader to a chosen disk pair. On machines that contain the disks, we set up nginx and use the WebDAV protocol. An email arrives. FileDB doesn’t have this file yet, so it needs to be uploaded to a disk pair via a loader.
But nothing prevents another user from receiving the same email — suppose two recipients are specified. Remember that FileDB doesn’t have this file yet, so one more loader will be uploading this very file and might pick the same disk pair for uploading.
The part of the name in red is where each loader puts a random number. Thus, the two PUT methods won’t overlap and upload two different files. Once nginx responds with 201 (OK), the first loader performs an atomic MOVE operation, which specifies the final name of the file.
When the second loader is done uploading the file and also performs MOVE, the file will get overwritten, but it’s no big deal because the file is one and the same. Once the file is on the disks, a new record needs to be added to FileDB. Our version of Tarantool is divided into two spaces. We’ve only been using space0 so far.
However, instead of simply adding a new record to FileDB, we’re using a stored procedure that either increments the file counter or adds a new record to FileDB. Why? In the time that has passed since the loader made sure the file doesn’t exist in FileDB, uploaded it and proceeded to add a new record to FileDB, someone else could have uploaded this file and added the corresponding record. We’ve considered this very case: Two recipients are specified for one email, so two loaders start uploading the file; once the second loader finishes the upload, it also proceeds to add a new record to FileDB.
In this case, the second loader just increments the file counter.
Let’s now look at the dec method. Our system has two high-priority tasks: to reliably write a file to disk and to quickly give it back to a client from this disk. Physically deleting a file generates a certain workload and slows down these two tasks. That’s why we perform deletions offline. The dec method itself decrements the counter. If the latter becomes 0, just like the magic number, then it means nobody needs the file anymore, so we move the corresponding record from space0 to space1 in Tarantool.
Each storage has a Valkyrie daemon that monitors data integrity and consistency — and it works with space1. There’s one daemon instance per disk. The daemon iterates over all of the files on a disk and checks whether space1 contains a record corresponding to a particular file, which would mean that this file should be deleted.
But after the dec method is called and a file is moved to space1, Valkyrie might take a while to find this file. This means that, in the time between these two events, the file may be reuploaded and, thus, moved to space0 again.
That’s why Valkyrie also checks whether a file exists in space0. If this is the case and the pair_id of the corresponding record points to a pair of disks that this Valkyrie instance is running on, then the record is deleted from space1.
If no record is found in space0, then the file is a potential candidate for deletion. However, between a request to space0 and the physical deletion of a file, there’s still a window of time in which a new record corresponding to this file might appear in space0. To deal with this, we put the file in quarantine.
Instead of deleting the file, we append deleted and a timestamp to its name. This means we’ll physically delete the file at timestamp plus some time specified in the config file. If a crash occurs and the file is deleted by mistake, the user will come to reclaim it. We’ll be able to restore it and resolve the issue without losing any data.
Now, recall that there are two disks, with a Valkyrie instance running on each. The two instances are not synced. Hence the question: When should the record be deleted from space1?
We’ll do two things. First, for the file in question, let’s make one of the Valkyrie instances the master. This is easily done by using the first bit of the file name: If it equals zero, then disk0 is the master; otherwise, disk1 is the master.
Let’s introduce a processing delay. Recall that when a record sits in space0, it contains the magic field for checking consistency. When the record is moved to space1, this field is not used, so we’ll put there a timestamp corresponding to the time that this record appeared in space1. This way, the master Valkyrie instance will start processing records in space1 at once, whereas the slave will add some delay to the timestamp and will process and delete records from space1 a little later.
This approach has one more advantage. If a file was mistakenly put in quarantine on the master, it’ll be evident from the log once we query the master. Meanwhile, the client that requested the file will fall back to the slave — and the user will receive the needed file.
So, we have considered the situation in which the Valkyrie daemon locates a file named sha1, and this file (being a potential candidate for deletion) has a corresponding record in space1. What other variants are possible?
Suppose a file is on a disk, but FileDB doesn’t have any corresponding record. If, in the case considered above, the master Valkyrie instance, for some reason, hasn’t been working for some time, it would mean the slave’s had enough time to put the file in quarantine and to delete the corresponding record from space1. In this case, we would also put the file in quarantine by using sha1.deleted.timestamp.
Another situation: A record exists but points to a different disk pair. This could happen during uploading if two recipients are specified for one email. Recall this scheme:
What happens if the second loader uploads the file to a different pair than the first one? It will increment the counter in space0, but the disk pair where the file was uploaded would contain some junk files. What we need to do is make sure these files can be read and that they match sha1. If everything’s fine, such files can be deleted at once.
Also, Valkyrie might encounter a file that has been put in quarantine. If the quarantine is over, this file will get deleted.
Now, imagine that Valkyrie encounters a good file. It needs to be read from disk, checked for integrity and compared to sha1. Then, Valkyrie needs to query the second disk to see if it has this same file. A simple HEAD method is enough here: The daemon running on the second disk will itself check the file’s integrity. If the file is corrupt on the first disk, it’s immediately copied over from the second disk. If the second disk doesn’t have the file, its copy is uploaded from the first disk.
We’re left with the last situation, which has to do with disk problems. If any problem with a disk is identified in the course of system monitoring, the problematic disk is put in service (read-only) mode, while on the second disk, the UNMOVE operation is run. This effectively distributes all of the files on the second disk among other disk pairs.
As of now, there are no known examples of SHA-1 collisions. There exist collision examples for its internal compression function (SHA-1 freestart collision), though. Given 12 billion files, the probability of a hash collision is less than 10^-38.
But let’s assume it’s possible. In this case, when a file is requested by its hash value, we check whether it has the correct size and CRC32 checksum that were saved in the indexes of the corresponding email during upload. That is to say, the requested file will be provided if and only if it was uploaded along with this email.
Color is arguably the second most important aspect of your app, after functionality. The human to computer interaction is heavily based on interacting with graphical UI elements, and color plays a critical role in this interaction. It helps users see and interpret your app’s content, interact with the correct elements, and understand actions. Every app has a color scheme, and it uses the primary colors for its main areas.
When designing a new app, it’s often difficult to decide on a color scheme that works well, as there are an infinite number of possible color combinations out there. In this article, we’ll go over the most important points related to color in apps. We’ll cover traditional color scheme patterns (monochrome, analogous, complementary), custom color combinations that aren’t based strictly on any one pattern, and we’ll also learn how to choose colors and contrasts for your app that support usability. If you’d like to hone your own color usage skills, you can download and test Adobe XD1for free, and get started right away.
Keeping your color combinations simple will help you improve the user experience6. A simple color scheme isn’t overwhelming to the eye and makes your content easier to understand. Conversely, having too many colors in too many places is an easy way to mess up a design.
Monochromatic schemes are the simplest color schemes to create, as each color is taken from the same base color. Monochromatic colors go well together, producing a soothing effect.
11 Monochromatic colors are a single color, and its tints, shades, and tones. (Large preview12)
The monochromatic scheme is very easy on the eyes, especially with blue or green hues.
Analogous color schemes are created from related colors that don’t stand out from one another; one color is used as a dominant color while others are used to enrich the scheme.
18 Analogous schemes are created by using three colors that are next to each other on the 12-spoke color wheel. (Large preview19)
While this scheme is relatively easy to pull off, the trick is in deciding which vibrancy of color to use, as it will be exaggerated. For example, Clear20, a gesture-driven21 to-do app, uses the analogous colors to visually prioritize current set of tasks.
22 Image credit: Adobe Color CC36282314. (Large preview24)25 The default color scheme in Clear is reminiscent of a heat map, where the hotter items are displayed in bright red.
While Calm26, a meditation app, uses the analogous colors blue and green to help users feel relaxed and peaceful.
Colors aren’t always at odds with each other; complementary colors are opposite colors.
32 Complementary colors are opposite of each other on the color wheel. (Large preview33)
They contrast strongly, and they can be used to attract the viewer’s attention. When using a complementary scheme, it is important to choose a dominant color and use its complementary color for accents. For example, when the human eye sees an object full of different hues of greens, a bit of red is going to stand out very well.
34 Using complementary colors is the easiest way to make something to stand out.
However, you have to use complementary colors carefully to keep your content from being visually jarring.
Creating your own color schemes is not as complicated as many people think. Adding a bright accent color into an otherwise neutral palette is one of the easiest color schemes to create, and it’s also one of the most visually striking.
Adobe Color CC41, previously known as Kuler, makes color selection extremely easy. Every color on the palette can be individually modified or chosen as the base color with a few simple clicks.
42 Under each color, the export codes are provided (including hexadecimal). (Large preview43)44
Palettes can be saved and added directly to a library. In addition, there are a number of great color schemes created by the community available on the site.
Typically, a colored object or area on a UI is not displayed in isolation, but is adjacent to or superimposed on another colored object or area. This creates contrast effects. Contrast is how one color stands apart from another. Properly used, it reduces eyestrain and focuses user attention by clearly dividing elements on a screen.
47 High contrast is when colors easily stand apart from each other. Low contrast is when they don’t. (Large preview48)
Color contrast is one area where color theory is crucial to the usability of a design. Designers often like to use low contrast techniques because low contrast makes things look beautiful and harmonious. However, beautiful isn’t always the best for readability. When you’re using colors in text, be aware that placing two colors with low-value contrast next to each other can make your copy very difficult to read. This is especially true on mobile screens, where users are often on devices outdoors or in bright places that cause screen glare.
49 These lines of text are difficult to read against their background colors.
Make sure you have a fair amount of contrast between elements. It’s really not that hard — all you need to do is to check the contrast ratio. Contrast ratios represent how different a color is from another color (commonly written as 1:1 or 21:1). The higher the difference between the two numbers in the ratio, the greater the difference in relative luminance between the colors. The W3C50 recommends51 the following contrast ratios for body text and image text:
Small text should have a contrast ratio of at least 4.5:1 against its background.
Large text (at 14 pt bold/18 pt regular and up) should have a contrast ratio of at least 3:1 against its background.
This guideline also helps users with low vision, color blindness, or worsening vision see and read the text on your screen.
52 These lines of text follow the color contrast ratio recommendations and are legible against their background colors.
Icons or other critical elements should also use the above-recommended contrast ratios.
53 Left: Icons don’t follow the color contrast ratio recommendations. Right: Icons follow the color contrast ratio recommendations and are legible against their backgrounds. Image credit: Material Design54. (Large preview55)
There are several free tools available to give you meaningful feedback about the levels of contrast in your chosen palette. One of them is WebAIM’s Color Contrast Checker56 which let you test colors you have already chosen.
Along with establishing readable text, contrast can also draw the user’s attention towards specific elements on a screen. Generally, high-contrast is the best choice for important content or key elements. So, if you want users to see or click something, make it stand out! For example, users are much more likely to click a call-to-action button that strongly contrasts with its background.
57 Contrast makes the area look different than the rest of the screen.
Have you thought about your app appears to users who have visual impairments?
When people talk about color blindness58, they usually refer to the inability of perceiving certain colors. Approximately 8% of men and 0.5% of women are affected by some form of color blindness. Red and green colors are a common problematic combination.
59 Colors, as seen with normal vision, and same colors, as seen with red-green color deficiency (Deuteranopia and Protanopia) (Large preview60)
Since colorblindness takes different forms (including red-green, blue-yellow, and monochromatic), it’s important to use multiple visual cues to communicate important states in your app. Never rely on a color solely to indicates system status. Instead, use elements such as strokes, indicators, patterns, texture, or text to describe actions and content.
Avocode lets you visually compare revisions of designs.
Also, Photoshop61 has really useful tools to help, and can simulate color blindness. This feature allows the designer to see what the app’s screen will look like to people with different types of color blindness.
We’ve barely covered the fundamentals of how color theory can enhance your app UI design. Honing your color usage skills is an ongoing endeavor. If you want to learn how to create beautiful, functional color schemes, all it takes is practice, determination, and lots of user testing.
This article is part of the UX design series sponsored by Adobe. The newly introduced Experience Design app65 is made for a fast and fluid UX design process, creating interactive navigation prototypes, as well as testing and sharing them — all in one place.
You can check out more inspiring projects created with Adobe XD on Behance66, and also visit the Adobe XD blog to stay updated and informed. Adobe XD is being updated with new features frequently, and since it’s in public Beta, you can download and test it for free67.
Email is one of the best ways to engage with your users, especially during the holiday season. However, if you want to stand out, no matter how beautiful your emails are, you need to make sure they render correctly in your reader’s inbox, regardless of what email client they’re using. Creating responsive email is not an easy task, and there are various reasons for that.
First, there is no standard in the way email clients render HTML. This is true for email clients from different companies, such as Outlook and Apple Mail, but not only. Even different versions of Outlook, such as Outlook 2003, Outlook 2013 and Outlook.com, render HTML differently.
Then, while email clients render HTML, many of them have very limited support of it. Some email clients will just strip the head of your HTML file, including media queries, which is why inline styles are heavily recommended. On a good note, this is moving in the right direction with the Gmail update1.
Now, there are a few techniques out there to help email developers. You might be familiar with some of them, such as the hybrid approach2, the mobile-first approach3 or even the Fab Four technique4 by HTeuMeuLeu5. But because of the reasons stated earlier, and especially the lack of a standard, none of these techniques will enable you to tame all email clients at once.
Abstracting Away The Complexity Of Responsive Email With MJML Link
MJML is an open-source framework that abstracts away the complexity of responsive email. The idea behind it is pretty simple. Just as jQuery normalizes the DOM and abstracts low-level interactions and animations, MJML abstracts the low-level hacks for responsive emails with an easy syntax. MJML is responsive by design. This means you can forget about nested tables and conditional comments and, more generally, about making your email responsive. MJML does it for you.
Leveraging a semantic syntax and high-level components such as the carousel6 (yes, you can display an interactive image gallery within an email!), MJML is really easy to learn for anyone. Responsive emails are no longer only accessible to a handful of experts anymore.
Being easy to use doesn’t mean that MJML is not powerful. It just enables experts to streamline their development workflow, while still giving them the flexibility they need with lower-level components such as tables8.
MJML is built in React12, a JavaScript library developed and maintained by Facebook, and it leverages the power of React’s components. The component names are semantic, starting with mj-, so that they are straightforward as well as easy to recognize and understand: mj-text, mj-image, mj-button, etc.
MJML will transpile to responsive HTML, following a mix of the mobile-first and hybrid coding approaches. Going mobile-first enables you to make sure that the most readable version is displayed by default in email clients that do not change the layout according to the device used.
For example, in Outlook.com, the mobile version will be displayed on both desktop and mobile (which is far more readable than a desktop version being displayed on mobile). The hybrid approach then enables the layout to change according to the device’s size wherever possible, using a mix of fallbacks, conditional comments, nested tables and media queries to target as many clients as possible. The layout degrades nicely, with multi-column layouts on desktop turning into single-column layouts on mobile.
13 Two-column layout, desktop view14 Two-column layout, mobile view
Before we start the tutorial, let’s get ready to code in MJML. We have different ways to use MJML, such as running it locally15 or using the online editor2316. By choosing the online editor, you’ll be able to start immediately, but running it locally enables you to use MJML with your favorite code editor (with plugins for Atom17, Sublime Text18 and Vim19), task runners such as gulp-mjml20 and grunt-mjml21 and a lot more22.
For this tutorial, the online editor2316 is recommended because it doesn’t require any setup.
If you still want to use it locally, open your terminal and run npm install mjml -g (requires to have Node.js and npm24 installed).
Once MJML is installed, create a file named example.mjml (or any name you like) with some MJML and run mjml -r example.mjml in your terminal (make sure to be in the same folder as the file you’re rendering). It will render your MJML file in a file named example.html, with the responsive HTML inside. You can find all available options for the command line in the documentation25.
(Brand names, logos and trademarks used herein remain the property of their respective owners, and their use does not imply any endorsement by or affiliation with Thrive Market.)
First, here is what the basic layout30 of an MJML document looks like:
<mjml> <mj-head> <!-- Head components go here: https://mjml.io/documentation/#standard-head-components --> </mj-head> <!-- All of the content of our email will go in mj-body --> <mj-body> <!-- mj-container defines the default styling of our email, including the default width, set to 600px but overwritable --> <mj-container> <!-- Body components go here (https://mjml.io/documentation/#standard-body-components) --> </mj-container> </mj-body> </mjml>
While inlining is the norm in HTML to ensure responsiveness, MJML also allows you to create custom MJML classes and MJML styles, which will then automatically be inlined from the head of your MJML file31. In MJML, styles come as component attributes.
<mj-text font-size="20px" color="#F45E43" font-family="helvetica"> Hello World </mj-text>
To start, we’ll set a default sans-serif font family for text components, because sans-serif is used for most text here. Then, we’ll create classes for elements used repeatedly, so that we don’t have to manually set styles over and over again. We could have created more custom classes and styles, but the most useful styles will be for:
Set a default padding of 0 for every component, using <mj-all />. This default padding can be overridden by manually specifying a padding directly on the components we are using.
Override the default font family of <mj-text>, using <mj-text /> in the head. Each time we use <mj-text>, the default font family will be sans-serif. We can still manually override this new default font by specifying a new one directly on the component.
Create classes using <mj-class /> and, more specifically, using the following mj-classes:
pill
This is to design a nice button. Attributes worth noting are the background-color set to transparent and the inner-padding, used to size the button as we want.
desc
This is to style the descriptions of the images in the two-column layout.
ico
This is to style the text below the six icons just before the footer.
(As you may have noticed, we have omitted the units on some attributes, such as padding. If you do so, MJML will output the attributes with px by default.)
Now that the styles are defined in the head (you can see here33 what your code should look like now), let’s start adding content to our email! MJML layouts are based on <mj-section>34 to create rows and <mj-column>3835 to create columns inside rows, which is very practical for email design. Note that, except for high-level components such as <mj-hero>36 and <mj-navbar>37, content should always be wrapped in a <mj-column>3835, which itself should go in a <mj-section>39, even when there is only one column in a section.
Let’s see this with two examples, the preheader and the header of the email.
There’s nothing very fancy here. We’re just creating a text preheader using the <mj-text>40 component, wrapped in a column, and giving it some MJML styles.
Hack: <mj-text> enables you to use HTML directly inside MJML, granting you full control over the content and allowing you to use the <span> and <a> tags you’re used to, for example.
<mj-section padding="0" background-color="#eeebe7"> <mj-column> <mj-text padding="0 2" align="center" font-size="10px"> The latest tips, trends, recipes, and more </mj-text> </mj-column> </mj-section>
Three-Column Layout for Blog, Logo and Referral Link Link
The header is a bit fancier but very easy to achieve with MJML. All we have to do is create a section that we’ll split into three equal columns (because columns are equal, we don’t even have to manually set the width). We’ll use images as in the original email, leveraging the explicit component <mj-image>42, which comes with the common attributes you would expect, including src, padding and border.
By default, columns will stack in the mobile version of our email. Here, because we want those three columns to stay side by side even on mobile, we’ll wrap them in an <mj-group>43 component, which will prevent the columns from stacking.
Hack: As noted in the documentation, due to a bug in iOS, you might have to use a minifier, or else the columns could stack on iPhone even if they’re wrapped in <mj-group>. The MJML command-line interface44 comes with a built-in minifier45 that you can use to run the -m option when rendering MJML.
We’ll create another section in which we’ll simply add an image, some text and a button. The only new component here is <mj-button>46, which should be clear enough and which comes with the standard attributes. Please note that you must specify an href, or else the text of the button might not display in some email clients.
<mj-section padding="20"> <mj-column> <mj-image padding="5 0 23 0" width="200px" src="http://i1044.photobucket.com/albums/b447/ngarnier/Thrive%20Market/566f6a67e871e_zpskalhjefi.gif" /> <mj-text align="center" font-size="16px"> Your daily destination for healthy living </mj-text> <mj-button padding="20 0 10 0" mj-class="pill" href="https://thrivemarket.com/blog?uid=5019850&uaexptime=1778637862&uatoken=1462b977c1fa70b09b585f3a8943d79a7079ab314393fe89852fd83fd05b631e&utm_content=lead_welcome&utm_medium=lifecycle&utm_campaign=day8&utm_source=sailthru"> Read more </mj-button> </mj-column> </mj-section>
Yes, there’s a component for that, too! It’s a good practice to split different rows into different sections, instead of dumping everything into the same section, because that gives you more control over styling (especially through padding), and it also makes it easier to isolate any problems that occur.
Here, we’ll create a section for each two-column row. Each column will consist of an image, a piece of text and a button. The good news is that, thanks to MJML’s hybrid approach, we don’t have to do anything to make the images stack on mobile. It’s responsive by default!
Regarding the styling, we don’t have much to do because we’re leveraging the mj-classes pill and desc, which we created earlier. All we need to do is add some padding to match the style of the original email.
Hack: Due to an issue with Outlook 2000, 2002 and 2003 ignoring the set width, it’s a good practice in MJML to set images to the sizes you want them to display at in those clients.
Here, we can see that the default HTML style for links is applied. In addition to <mj-attributes>, you can also inline CSS right into MJML using <mj-style>49. Let’s do just that by updating the head to overwrite the default style of links once and for all. We’ll also create a CSS class to apply to the <a> tags to give them the right color (we’re creating a class because the links in the email shouldn’t all have the same color).
To create this section, we’ll use the components that we’re getting familiar with: <mj-section>, <mj-column> and <mj-button>.
First, we’ll add a background-color to our section and some padding so that it looks as expected. Then, we just have to create two columns, one wider than the other, leveraging the width attribute with percentages. As usual, columns will stack on mobile. Because the button is different from the others here, we won’t use the pill class, but rather will manually create a new style.
Hack: Because of poor support for shorthand HEX colors in Internet Explorer, we recommend using six-digit HEX colors. This is a hack that we’ll reintegrate in MJML at some point to make sure that three-digit HEX codes are turned into six-digit codes.
<mj-section background-color="#6d8be1" padding="15 40 10 40"> <mj-column width="60%"> <mj-text font-weight="bold" color="#ffffff" font-size="16px" padding="0 0 10 0"> Get all your healthy groceries at Thrive Market! </mj-text> </mj-column> <mj-column width="40%"> <mj-button background-color="#ffffff" color="#45495d" font-weight="800" font-family="sans-serif" font-size="16px" border-radius="2px" inner-padding="15 60"> Shop Now </mj-button> </mj-column> </mj-section>
To design the title, we’ll create a three-column layout. The columns will consist of the following, respectively:
the dark blue line to the left of the title,
the title "Want More Tips, Tricks, and Delicious Recipes?",
the dark blue line to the right of the title.
Then, we will wrap the three columns in an <mj-group> so that it doesn’t stack on mobile.
We’ll start creating the lines, leveraging the <mj-divider> component, setting its border-width to 2px and adding some padding so that it looks the way we want. By default, the divider will fill the column it’s contained in, so that it looks consistent across devices. Therefore, we don’t need to explicitly set the width of the divider.
Then, we’re just using <mj-text> to add our title, leveraging the desc mj-class (because we want to inherit some of the styles set in this class) and overriding the font-family and align properties that are different from this class. We could have also manually set the style without using the desc mj-class.
Finally, we just have to use our button with the pill mj-class as we did before. We’re overriding the inner-padding because, according to the original design, this button is not as wide as the others.
We’re wrapping our title in a section and a column, as we’ve seen before, and we’re using the desc style that we created earlier. We need to alter only a few styles by manually setting a different align, font-size and font-style from our mj-class.
This section is made up of six icons, with accompanying text below. The icons display side by side on desktop and wrap to two lines of three icons on mobile. By now, you probably know that creating such layouts is easy if we leverage the <mj-column> component. To make the icons stack onto two lines, all we have to do is wrap the columns in two groups of three columns in an <mj-group>.
To design the text below the icons, we just have to use the ico mj-class that we created before. We’ll also create a CSS class named ico to apply to the a tags, like we did in the two-column layout section.
Once again, this section is easy to achieve by leveraging the <mj-column> component, using one column per social network icon and wrapping all of the icons in an <mj-group> so that they don’t stack on mobile. The only trick here is to fine-tune the width of the images and the padding so that the result is consistent with the original design.
Because this part is pretty simple, it’s OK to wrap the divider and the text in the same column and section, even though we could have separated the divider from the text. As we did before when styling the links, we’ll create a footer class so that our links have the proper color.
<mj-section background-color="#EEEBE7" padding="25 40"> <mj-column> <mj-divider /> <mj-text padding="30 0 0 0" align="center" font-size="14"><a href="https://thrivemarket.com/blog?uid=5019850&uaexptime=1778637862&uatoken=1462b977c1fa70b09b585f3a8943d79a7079ab314393fe89852fd83fd05b631e&ccode=KG6OCD3H&utm_content=lead_welcome&utm_medium=lifecycle&utm_campaign=day8&utm_source=sailthru">Read Our Blog</a> <a href="https://thrivemarket.com/">View Email Online</a></mj-text> <mj-text align="center" color="#45495d" font-size="10px" line-height="14px"> <p>Please don't hit 'reply' to this email—we won't be able to email you back from this address and help you thrive! If you need anything, visit our <a href="https://thrivemarket.com/faq?uid=5019850&uaexptime=1778637862&uatoken=1462b977c1fa70b09b585f3a8943d79a7079ab314393fe89852fd83fd05b631e&ccode=KG6OCD3H&utm_content=lead_welcome&utm_medium=lifecycle&utm_campaign=day8&utm_source=sailthru">FAQ</a> or contact <a href="https://thrivemarket.com/faq/contact?uid=5019850&uaexptime=1778637862&uatoken=1462b977c1fa70b09b585f3a8943d79a7079ab314393fe89852fd83fd05b631e&ccode=KG6OCD3H&utm_content=lead_welcome&utm_medium=lifecycle&utm_campaign=day8&utm_source=sailthru">Member Services</a> anytime, and we'll be happy to help!</p> <p>We don't want to see you go, but if you no longer wish to receive promotional emails from us, you can <a href="https://thrivemarket.com/">unsubscribe here</a> or <a href="https://thrivemarket.com/">change your email preferences</a> anytime.</p> <p>4509 Glencoe Ave, Marina Del Rey, CA 90292 <br />@2016 Thrive Market All Rights Reserved</p> </mj-text> </mj-column> </mj-section>
You should now have fewer than 240 lines of MJML (you can check the full code54), whereas the original file was a bit less than 800 lines of HTML. Congrats! You’ve just created your first responsive email using MJML! How easy was that?
Testing how an email renders in different email clients is always a good practice, so let’s do just that using Litmus55 (Email on Acid56 is another great platform for email testing).
Go to Litmus57 (create an account if you don’t have one already), create a new project, and paste the HTML that we generated earlier in the code area. You’ll be able to see the results in various email clients by clicking “Instant Previews” in the right pane. You can see58 the results for major email clients, from Outlook 2003 to Inbox by Gmail.
Now that you know how to use MJML to easily create a responsive email, why not try to create your own component? My tutorial59 will guide you through this step by step.
What did you think about your first experience with MJML? Feel free to reach out on Twitter60 and join the MJML community now by signing up to the Slack61 channel. You can also subscribe to the newsletter62 to keep up to date on the latest news.
Will the resources spent implementing app indexing for Google search be a boon or a bust for your app’s traffic? In this article, I’ll take you through a case study for app indexing at our company, the results of which may surprise you.
App indexing is one of the hottest topics in SEO right now, and in some sense for good reason. Google has only been indexing apps for everyone1 for a little more than two years, and with only 30% of apps being indexed2 there is huge potential for websites to draw additional search traffic to their apps.
What’s more, Google has given not one but two ranking boosts3 to websites that use app indexing and the app indexing API4; so, implementing app indexing for your website is likely to increase your search traffic.
However, when we did it, it was a bust. We got a lot more app traffic from Google search when we implemented app indexing, but it was so little traffic compared to web search at that point that it was almost not worth the effort. Read on to learn more about what we did and what effect it had on our overall traffic.
If you’re not familiar with app indexing5, it is basically the process by which your app appears in Google search results alongside relevant web results. By supporting HTTP URLs in your app and adding the App Indexing SDK, you allow Google to crawl and index your app as it would a web page, and you enable users to install or launch your app from search results when they search with relevant keywords.
If the app is already installed, you’ll see a button to launch it in the relevant search results:
6 View of an indexed app on a Nexus 6P running Android 7.0 when the app is installed on the device. (Image: Bryson Meunier) (View large version7)
If the searcher doesn’t have the app installed yet, they will see an “Install” button in search results:
8 View of an indexed app on a Nexus 6P running Android 7.0 when the app is not installed on the device. (Image: Bryson Meunier) (View large version9)
Theoretically, this is great for users because they can find relevant authoritative content in Google regardless of whether they prefer websites or apps, and it’s great for app developers and marketers because it allows apps to be exposed to a whole new audience outside of the app store, potentially increasing app usage and downloads. But “theoretically” doesn’t necessarily mean that app indexing brings a lot of real traffic from search.
While I have seen a lot of great info on how10 and why11 to implement app indexing, I haven’t yet seen a case study on the benefits of app indexing in terms of traffic (though Google does highlight several other benefits12). So, I looked at our app indexing traffic at Vivid Seats so that marketers, developers and webmasters can get a better sense of how much traffic, realistically, they can expect from getting their app indexed.
I want to start the case study with a small caveat: Vivid Seats13 is the largest independent ticket marketplace, and the number-three resale marketplace behind StubHub and Ticketmaster, according to Bloomberg14. As such, we get a lot of web traffic. A website that doesn’t get as much web traffic as we do or an app that has no equivalent website will probably have different results than ours — especially if it’s in a different industry. That said, a lot of large websites might see similar results and might want to adjust their strategy accordingly.
This is also an Android-only case study, because we haven’t yet been given access to the iOS app-indexing beta in Google’s Search Console15, and we don’t have the same kind of visibility into our iOS app’s indexing and ranking.
Vivid Seats has had an Android app16 indexed since September of 2015. However, Google had a difficult time finding the equivalent app URI for our web pages at first, and in February of this year we had about 18 app URIs indexed and more than 35,000 pages with the “Intent URI not supported” error17. We had had different URIs for our app than for our website at the time, which was making it difficult for Google to find equivalent pages.
Initially, we tried to add alternate tags to our web pages pointing to the equivalent app URIs, as instructed by Google’s help section on the subject18.
For example, Adele’s Vivid Seats page19 — http://www.vividseats.com/concerts/adele-tickets.html — had the following rel="alternate" tag, which was dynamically served to mobile user agents and which pointed to the equivalent app URI:
20 Mobile view of Adele’s tickets page. (Image: Fawaad Ahmad)21 View of the code for the same page with the alternate tag highlighted. (Image: Fawaad Ahmad)
We were initially hopeful that this solution would be all that was necessary, because Google recommended it in its help section as a solution to this problem. Unfortunately, weeks after implementation, it was clear that Google was still having a difficult time figuring it out, and it didn’t index many more app URIs.
And the crawl errors persisted because Google was assuming that a lot of web pages on our website had equivalent app views, which at the time wasn’t the case.
We supported universal links22 in our iOS app and HTTP URLs in Android23 in April, which reduced the number of errors from 40,000 at its apex to about 85 today. As a result, we have seen the number of app URIs indexed go from 18 in February to about 35,000 today.
24 Screenshot of Search Console’s “Crawl Status” report from 31 May 2016, which shows the effect of implementing HTTP URLs in Android on pages with errors and pages indexed. (Image: Bryson Meunier) (View large version25)
We made sure that each type of link on our website had an equivalent view and corresponding URI in our Android app. To do this, we designed templates for page types that were not included in our app previously, and we built them in our Android app. The unique information on each page is dynamically served from our RESTful endpoint, so it’s only necessary to design and code the templates, not individual pages.
We verified our website in Search Console and associated it with our website, since our website isn’t in SSL, as required by Digital Asset Links.
Predictably, clicks and impressions grew exponentially from December, when 18 app URIs were indexed, to September, when 40,000 app URIs were indexed. Overall, clicks grew 919%, with clicks from non-brand queries (i.e. informational queries that don’t mention Vivid Seats, like “packers tickets”) growing 5,500%. The clickthrough rate (CTR) went down, predictably, as a result of the increase in impressions, specifically non-brand ones.
28 Traffic to the app from Google search grew 919% after getting additional URLs indexed, with non-brand traffic growing 5500%. (Image: Bryson Meunier) (View large version29)
While app traffic (defined in Search Console as “clicks”) grew exponentially as a result of the increase in app URIs getting indexed, relative to the website traffic, app traffic has been underwhelming to date.
Even with an additional 40,000 app URIs indexed, 99.82% of our traffic from search currently goes to web pages, with just 0.23% of total search traffic going to our app URIs.
A few reasons why this might be so low:
Android traffic is a lower percentage of our mobile traffic than iOS, which isn’t included in this study.
We also have fewer app pages indexed than web pages — more than three times fewer, in fact. Because we grew traffic exponentially by having more app URIs indexed, there’s probably more traffic out there to be had that we will see when Google finally indexes all of our app URIs.
But the biggest reason is that CTRs vary dramatically for app listings and web listings. Our brand term, which we usually rank in position 1 and for which we usually get around a 40% CTR on the web, has a CTR of less than 1% for the app equivalent. This suggests that, though the app buttons are prominent in Google for navigational terms, most people still prefer to click through to the website.
This last point could just be a matter of this being fairly new technology and searchers not fully understanding the new layout, and we could imagine this trend reversing sometime in the future. For now, however, it’s important that this point is understood by all who are looking to index their app pages in search results. It’s tempting to think that the presence of a large colorful button in search results will increase the CTR and traffic, but our research hasn’t found any evidence to support this.
In fact, we found just the opposite: The CTR to app content is less than half of what it is to web content, with our Android app pages getting a CTR of 1.55%, at an average position of 5.1, compared to our web content CTR of 4.67%, two positions below our app content, at 7.6.
30 Breakdown of the CTR across all content types, as reported by Search Console. (Image: Bryson Meunier) (View large version31)
Though app content in general has a lower CTR than web content, we found that navigational (or branded) search terms actually have a lower CTR for us than informational terms, which is the opposite of how it works for web content.
32 Branded navigational terms drove much less traffic to apps than to web pages. (Image: Bryson Meunier)
56% of the app traffic we received came from branded queries, compared to just 40% of our web traffic.
33 The CTR varies significantly for web and app traffic by query type. (Image: Bryson Meunier) (View large version34)
Looking deeper into query type, we broke down queries into two distinct types: first, navigational queries that mention our brand (for example, “vivid seats”) and informational queries that don’t (for example, “packer tickets”), and secondly, queries that indicate the searcher is looking for a website (for example, “www.vividseats.com”) or an app (for example, “download vivid seats app”) specifically.
If the searcher hadn’t indicated in their query that they were looking for an app or a website, we recorded that the query was branded or not, and that the website or app preference was “Not Specified.”
35 In this chart of app and web impressions and traffic to Vivid Seats from Google search, 93% of web impressions came from non-brand queries that didn’t specify an app or website preference, compared to just 12% for the same category in app impressions. (Image: Bryson Meunier) (View large version36)
4% of total app traffic specified that they’re looking for an app, compared to less than 1% for web traffic. This is important traffic to be aware of, because it doesn’t have an equivalent on the desktop, and it could be a new query type to optimize for, but it’s not representative of app traffic. The great majority of queries for both web (99%) and app (96%) do not use qualifiers to describe whether the searchers are looking for an app or website specifically.
The traffic to app content from search has so far been underwhelming, but the real reason most developers would index their app content would be to drive downloads.
Fortunately, with Search Console, we can see installations from search as well. It’s kind of hidden in the Search Console reports; to see it, go to “Search analytics” → “Search appearance” → “Filter search appearance” → “Install app button.”
37 View of “Install app button” filter in Search Console’s “Search Analytics” report. (Image: Bryson Meunier) (View large version38)
When we did that, we found that just 0.03% of our total search traffic led to an app installation from search in the last 90 days.
But when you take the total number of installations from the last 90 days and compare it to the installations we’ve gotten from search, it’s clear that about 2% of our total Android downloads came from users installing the downloads in search results. This isn’t terribly impressive, but when you consider that this represents many app installations from search that we may not have had otherwise, it justifies for us the little bit of work it took to implement it.
If your resources are limited and you’re wondering if app indexing would deliver enough traffic and installations to justify the effort, our experience would suggest you should focus on web content instead. Even after growing our traffic from app indexing by 919%, web content still brings in more than 99.8% of the total traffic from search to our website. If you’re considering other high-value projects, you might want to do those instead.
Still, if you only have an app to index, or if you have resources on your team, then app indexing does bring traffic that you wouldn’t get otherwise, and it might be worth the long-term benefits to your website and to Google users.
Have you implemented app indexing with similar (or dissimilar) results? I’d love to hear about it in the comments.
Many thanks to the UX design and development group at Vivid Seats, including Fawaad Ahmad, who made a lot of this happen.
What fuels your work? What fuels your mind? What do you do on a non-productive day or when you’re sad? Nowadays, I try to embrace these times. I try to relax and not be angry at myself for not being productive.
And the fun fact about it? Well, most of the times when I could convince my mind that not being productive is nothing to feel bad about, things take a sudden turn: I get my ideas back, my productivity rises and, in effect, I even achieve more work than on an average day. It’s important to try to be human.
I recently mentioned that most major browsers are blocking certificates from StartCom and WoSign entirely or plan to do so in the future. However, it seems that these certificate authorities still sell certificates1. Don’t buy from them, their certificates will be useless by next month.
Chart.js15 is a nice library that uses subtle animations to draw canvas charts on a page. Mixed chart types are available.
Stefan Judis wrote about the global object in JavaScript16, variables and the issues around it. This is not only useful for people with beginner or intermediate JavaScript knowledge but also for advanced users who want to understand the topic better.
Todd Motto published an “Angular 2+ Fundamentals17” video course in which he explains Angular, Typescript, component architecture, and other modern programming concepts.
This visual introduction to machine learning22 explains how computers apply statistical learning techniques to automatically identify patterns in data. If you’re not familiar with how machine learning works, this will give you a rough idea.
As we’ve seen in statistics and data from the NASA before, this is, unfortunately, the truth: 2016 was the hottest year on record23. The consequences: Nearly a quarter of the Great Barrier Reef died, Canada had to deal with the costliest wildfires ever, and the Arctic sea ice has been at its smallest winter maximum for two years now. And do you remember Hurricane Matthew? Such weather events are mostly driven by the climate change that we’re facing right now, with no trend of change over the upcoming years. Fortunately, there’s something everyone of us can do: The UN shows how we can take action, even from the couch at home24.
First of all, let’s define some vocabulary. “Internationalization” is a long word, and there are at least two widely used abbreviations: “intl,” “i18n”. “Localization” can be shortened to “l10n”.
Internationalization can be generally broken down into the following challenges:
detecting the user’s locale;
translating UI elements, titles and hints;
serving locale-specific content such as dates, currencies and numbers.
Note: In this article, I am going to focus only on front-end part. We’ll develop a simple universal React application with full internationalization support.
Let’s use my boilerplate repository1 as a starting point. Here we have the Express web server for server-side rendering, webpack for building client-side JavaScript, Babel for translating modern JavaScript to ES5, and React for the UI implementation. We’ll use better-npm-run to write OS-agnostic scripts, nodemon to run a web server in the development environment and webpack-dev-server to serve assets.
Our entry point to the server application is server.js. Here, we are loading Babel and babel-polyfill to write the rest of the server code in modern JavaScript. Server-side business logic is implemented in src/server.jsx. Here, we are setting up an Express web server, which is listening to port 3001. For rendering, we are using a very simple component from components/App.jsx, which is also a universal application part entry point.
Our entry point to the client-side JavaScript is src/client.jsx. Here, we mount the root component component/App.jsx to the placeholder react-view in the HTML markup provided by the Express web server.
So, clone the repository, run npm install and execute nodemon and webpack-dev-server in two console tabs simultaneously.
In the first console tab:
git clone https://github.com/yury-dymov/smashing-react-i18n.git cd smashing-react-i18n npm install npm run nodemon
There are two possible solutions to this requirement. For some reason, most popular websites, including Skype’s and the NBA’s, use Geo IP to find the user’s location and, based on that, to guess the user’s language. This approach is not only expensive in terms of implementation, but also not really accurate. Nowadays, people travel a lot, which means that a location doesn’t necessarily represent the user’s desired locale. Instead, we’ll use the second solution and process the HTTP header Accept-Language on the server side and extract the user’s language preferences based on their system’s language settings. This header is sent by every modern browser within a page request.
The Accept-Language request header provides the set of natural languages that are preferred as a response to the request. Each language range may be given an associated “quality” value, which represents an estimate of the user’s preference for the languages specified by that range. The quality value defaults to q=1. For example, Accept-Language: da, en-gb;q=0.8, en;q=0.7 would mean, “I prefer Danish, but will accept British English and other types of English.” A language range matches a language tag if it exactly equals the tag or if it exactly equals a prefix of the tag such that the first tag character following the prefix is -.
(It is worth mentioning that this method is still imperfect. For example, a user might visit your website from an Internet cafe or a public computer. To resolve this, always implement a widget with which the user can change the language intuitively and that they can easily locate within a few seconds.)
Here is a code example for a Node.js Express web server. We are using the accept-language package, which extracts locales from HTTP headers and finds the most relevant among the ones supported by your website. If none are found, then you’d fall back to the website’s default locale. For returning users, we will check the cookie’s value instead.
Here, we are importing the accept-language package and setting up English and Russian locales as supported. We are also implementing the detectLocale function, which fetches a locale value from a cookie; if none is found, then the HTTP Accept-Language header is processed. Finally, we are falling back to the default locale (en in our example). After the request is processed, we add the HTTP header Set-Cookie for the locale detected in the response. This value will be used for all subsequent requests.
I am going to use the React Intl3 package for this task. It is the most popular and battle-tested i18n implementation of React apps. However, all libraries use the same approach: They provide “higher-order components” (from the functional programming design pattern4, widely used in React), which injects internationalization functions for handling messages, dates, numbers and currencies via React’s context features.
First, we have to set up the internationalization provider. To do so, we will slightly change the src/server.jsx and src/client.jsx files.
So, now all IntlProvider child components will have access to internationalization functions. Let’s add some translated text to our application and a button to change the locale (for testing purposes). We have two options: either the FormattedMessage component or the formatMessage function. The difference is that the component will be wrapped in a span tag, which is fine for text but not suitable for HTML attribute values such as alt and title. Let’s try them both!
Here is our src/components/App.jsx file:
import { FormattedMessage } from 'react-intl'; … --- <h1>Hello World!</h1> <h1><FormattedMessage defaultMessage="Hello World!" description="Hello world header greeting" /></h1>
Please note that the id attribute should be unique for the whole application, so it makes sense to develop some rules for naming your messages. I prefer to follow the format componentName.someUniqueIdWithInComponent. The defaultMessage value will be used for your application’s default locale, and the description attribute gives some context to the translator.
Restart nodemon and refresh the page in your browser. You should still see the “Hello World” message. But if you open the page in the developer tools, you will see that text is now inside the span tags. In this case, it isn’t an issue, but sometimes we would prefer to get just the text, without any additional tags. To do so, we need direct access to the internationalization object provided by React Intl.
We’ve had to write a lot more code. First, we had to use injectIntl, which wraps our app component and injects the intl object. To get the translated message, we had to call the formatMessage method and pass a message object as a parameter. This message object must have unique id and defaultValue attributes. We use defineMessages from React Intl to define such objects.
The best thing about React Intl is its ecosystem. Let’s add babel-plugin-react-intl to our project, which will extract FormattedMessages from our components and build a translation dictionary. We will pass this dictionary to the translators, who won’t need any programming skills to do their job.
Restart nodemon and you should see that a build/messages folder has been created in the project’s root, with some folders and files inside that mirror your JavaScript project’s directory structure. We need to merge all of these files into one JSON. Feel free to use my script5. Save it as scripts/translate.js.
You should see an en.json file in the build/lang folder with the following content:
{ "app.hello_world": "Hello World!", "app.hello_world2": "Hello World 2!" }
It works! Now comes interesting part. On the server side, we can load all translations into memory and serve each request accordingly. However, for the client side, this approach is not applicable. Instead, we will send the JSON file with translations once, and a client will automatically apply the provided text for all of our components, so the client gets only what it needs.
Let’s copy the output to the public/assets folder and also provide some translation.
Note: If you are a Windows user, symlinks are not available to you, which means you have to manually copy the command below every time you rebuild your translations:
cp ../../build/lang/en.json public/assets/en.json
In public/assets/ru.json, we need the following:
{ "app.hello_world": "Привет мир!", "app.hello_world2": "Привет мир 2!" }
Now we need to adjust the server and client code.
For the server side, our src/server.jsx file should look like this:
--- import { IntlProvider } from 'react-intl'; import { addLocaleData, IntlProvider } from 'react-intl'; import fs from 'fs'; import path from 'path'; import en from 'react-intl/locale-data/en'; import ru from 'react-intl/locale-data/ru'; addLocaleData([…ru, …en]); const messages = {}; const localeData = {}; ['en', 'ru'].forEach((locale) => { localeData[locale] = fs.readFileSync(path.join(__dirname, `../node_modules/react-intl/locale-data/${locale}.js`)).toString(); messages[locale] = require(`../public/assets/${locale}.json`); }); --- function renderHTML(componentHTML) { function renderHTML(componentHTML, locale) { … <script type="application/javascript" src="${assetUrl}/public/assets/bundle.js"></script> <script type="application/javascript">${localeData[locale]}</script> … --- <IntlProvider locale={locale}> <IntlProvider locale={locale} messages={messages[locale]}> … --- return res.end(renderHTML(componentHTML)); return res.end(renderHTML(componentHTML, locale)); ```
Here we are doing the following:
caching messages and locale-specific JavaScript for the currency, DateTime and Number formatting during startup (to ensure good performance);
extending the renderHTML method so that we can insert locale-specific JavaScript into the generated HTML markup;
providing the translated messages to IntlProvider (all of those messages are now available to child components).
For the client side, first we need to install a library to perform AJAX requests. I prefer to use isomorphic-fetch because we will very likely also need to request data from third-party APIs, and isomorphic-fetch can do that very well in both client and server environments.
We also need to tweak src/server.jsx, so that Express serves the translation JSON files for us. Note that in production, you would use something like nginx instead.
After the JavaScript is initialized, client.jsx will grab the locale from the cookie and request the JSON file with the translations. Afterwards, our single-page application will work as before.
Time to check that everything works fine in the browser. Open the “Network” tab in the developer tools, and check that JSON has been successfully fetched by our client.
import LocaleButton from './LocaleButton'; … <h1>{this.props.intl.formatMessage(messages.helloWorld2)}</h1> <LocaleButton locale={this.props.intl.locale} />
Note that once the user changes their locale, we’ll reload the page to ensure that the new JSON file with the translations is fetched.
High time to test! OK, so we’ve learned how to detect the user’s locale and how to show translated messages. Before moving to the last part, let’s discuss two other important topics.
In English, most words take one of two possible forms: “one apple,” “many apples.” In other languages, things are a lot more complicated. For example, Russian has four different forms. Hopefully, React Intl will help us to handle pluralization accordingly. It also supports templates, so you can provide variables that will be inserted into the template during rendering. Here’s how it works.
Here, we are defining a template with the variable count. We will print either “1 apple” if count is equal to 1, 21, etc. or “2 apples” otherwise. We have to pass all variables within formatMessage‘s values option.
Let’s rebuild our translation file and add the Russian translations to check that we can provide more than two variants for languages other than English.
npm run build:langs
Here is our public/assets/ru.json file:
{ … "app.counting": "Мне нужно купить {count, number} {count, plural, one {яблоко} few {яблока} many {яблок}}" }
All use cases are covered now. Let’s move forward!
3. Serving Locale-Specific Content Such As Dates, Currencies And Numbers Link
Your data will be represented differently depending on the locale. For example, Russian would show 500,00 $ and 10.12.2016, whereas US English would show $500.00 and 12/10/2016.
React Intl provides React components for such kinds of data and also for the relative rendering of time, which will automatically be updated each 10 seconds if you do not override the default value.
On average, two seconds will elapse between when the server provides markup to the client and the client initializes client-side JavaScript. This means that all DateTimes rendered on the page might have different values on the server and client sides, which, by definition, breaks universal rendering. To resolve this, React Intl provides a special attribute, initialNow. This provides a server timestamp that will initially be used by client-side JavaScript as a timestamp; this way, the server and client checksums will be equal. After all components have been mounted, they will use the browser’s current timestamp, and everything will work properly. So, this trick is used only to initialize client-side JavaScript, in order to preserve universal rendering.
Restart nodemon, and the issue will almost be gone! It might persist because we are using Date.now(), instead of some timestamp provided by the database. To make the example more realistic, in app.jsx replace Date.now() with a recent timestamp, like 1480187019228.
(You might face another issue when the server is not able to render the DateTime in the proper format, which will also break universal rendering. This is because version 4 of Node.js is not built with Intl support by default. To resolve this, follow one of the solutions described in the official wiki11.)
It sounds too good to be true so far, doesn’t it? We as front-end developers always have to be very cautious about anything, given the variety of browsers and platforms. React Intl uses the native Intl browser API for handling the DateTime and Number formats. Despite the fact that it was introduced in 2012, it is still not supported by all modern browsers. Even Safari supports it partially only since iOS 10. Here is the whole table from CanIUse for reference.
This means that if you are willing to cover a minority of browsers that don’t support the Intl API natively, then you’ll need a polyfill. Thankfully, there is one, Intl.js14. It might sound like a perfect solution once again, but from my experience, it has its own drawbacks. First of all, you’ll need to add it to the JavaScript bundle, and it is quite heavy. You’ll also want to deliver the polyfill only to browsers that don’t support the Intl API natively, to reduce your bundle size. All of these techniques are well known, and you might find them, along with how to do it with webpack, in Intl.js’ documentation15. However, the biggest issue is that Intl.js is not 100% accurate, which means that the DataTime and Number representations might differ between the server and client, which will break server-side rendering once again. Please refer to the relevant GitHub issue16 for more details.
I’ve come up with another solution, which certainly has its own drawbacks, but it works fine for me. I implemented a very shallow polyfill17, which has only one piece of functionality. While it is certainly unusable for many cases, it adds only 2 KB to the bundle’s size, so there is not even any need to implement dynamic code-loading for outdated browsers, which makes the overall solution simpler. Feel free to fork and extend it if you think this approach would work for you.
Well, now you might feel that things are becoming too complicated, and you might be tempted to implement everything yourself. I did that once; I wouldn’t recommend it. Eventually, you will arrive at the same ideas behind React Intl’s implementation, or, worse, you might think there are not many options to make certain things better or to do things differently. You might think you can solve the Intl API support issue by relying on Moment.js18 instead (I won’t mention other libraries with the same functionality because they are either unsupported or unusable). Fortunately, I tried that, so I can save you a lot of time. I’ve learned that Moment.js is a monolith and very heavy, so while it might work for some folks, I wouldn’t recommend it. Developing your own polyfill doesn’t sound great because you will surely have to fight with bugs and support the solution for quite some time. The bottom line is that there is no perfect solution at the moment, so choose the one that suits you best.
(If you feel lost at some point or something doesn’t work as expected, check the “solution” branch of my repository19.)
Hopefully, this article has given you all of the knowledge needed to build an internationalized React front-end application. You should now know how to detect the user’s locale, save it in the cookie, let the user change their locale, translate the user interface, and render currencies, DateTimes and Numbers in the appropriate formats! You should also now be aware of some traps and issues you might face, so choose the option that fits your requirements, bundle-size budget and number of languages to support.
As the saying goes, “A picture is worth a thousand words.” Human beings are highly visual creatures who are able to process visual information almost instantly; 90 percent1 of all information that we perceive and that gets transmitted to our brains is visual. Images can be a powerful way to capture users’ attention and differentiate your product. A single image can convey more to the observer than an elaborate block of text. Furthermore, images can cross language barriers in a way text simply can’t.
Images are more than just decoration; they have the power to make or break a user’s experience. In this article, we’ll cover a good number of useful principles and best practices that will help you successfully integrate imagery into your designs. If you’d like to bring your app or website to life with little effort, you can download and test Adobe XD2for free.
Every image has a story to tell. Just like it is with writing, it’s better if you know what you want to say before you begin. Compelling images have a unique ability to inspire and engage your audience, but not all images improve the experience. Some of them just take up space or, in the worst case, confuse the user. One of the most dangerous elements in any design is imagery that conveys the wrong message.
Users react to visuals faster than text, so make sure your content matches the supporting visuals. You should select images that have a strong relationship with your product goals and ensure that they are context-relevant.
The principle “more is better” doesn’t apply to images. Don’t put a lot of effort in creating purely decorative images because people usually ignore such images. Instead, choose images that showcase the purpose of your product. Use limited number of striking visuals in your designs — the ones that really capture users’ attention.
Make sure your images are appropriately sized for displays across all platforms. Images shouldn’t appear pixelated, so be sure to test appropriate resolution sizes for specific ratios and devices. Display photos and graphics in their original aspect ratio, and don’t scale them greater than 100%. You don’t want the artwork or graphics in your product to look skewed, too small or too large.
Responsive websites and mobile apps often struggle with selecting image resolutions that best match the various user devices. It’s quite clear that one image for all screen resolutions and different devices is not enough. However, an image per pixel is too much; cropping images one at a time can be overwhelming especially if you have a ton of images.
So, how can someone automatically choose the optimal responsive image sizes? Hopefully, there are online tools that allow you to manage multiple sizes for an entire folder of images. One of them is Cloudinary1412 which enables you to interactively generate responsive image breakpoints. This tool uses advanced algorithms to easily generate best matching breakpoints for each uploaded image; images are analyzed to find the best breakpoints on an image by image basis, rather than creating all possible image resolutions.
Getting people’s attention with aesthetically pleasing images certainly has value, but it comes at the price of making other elements harder to see and use.
Putting too much focus on images in your designs may create a visual overkill that can seriously distract users from meaningful engagement with your content. You can see this effect in SoundCloud’s app in which the image takes all the attention and you barely notice the two buttons.
16 Screen buttons are overshadowed by the image in Soundcloud’17s home view.
Although image-focused design is appropriate in some cases (e.g. Apple’s homepage), the vast majority of apps and sites should follow a balanced approach — images that are used in user interfaces should support the product, but not obscure other important content or overshadow functionality.
Imagery is a visual communication tool that conveys your message. A clear focus communicates the concept at a glance, whereas a lack of focus makes the image meaningless.
When the point of focus is obscured, the iconic quality of the image is lost:
Human images are a very effective way to get your users engaged. When we see faces of other humans, it makes us feel like we are actually connecting with them, and not just using a product. However, many corporate sites are notorious for the overuse of insincere photography which is employed to “build trust.”
30 Don’t. Inauthentic images leaves the user with a sense of shallow, false pretense. (Image credit31)
U32sability tests33 show that purelydecorative photos rarely add value to the design and more often harm than improve the user experience. Users usually overlook such images and might even get frustrated by them.
A very simple rule of thumb is to use high-quality photographs of people who match your app’s or website’s character. Imagery you use should be an authentic representation of your product, company or culture.
Try to avoid crowd shots; use photos that have a single main subject instead.
Strive for images that represent genuine stories. Take photos of your people doing interesting things. If you have a product, consider ways they can interact with that product.
When using images in your design, ask yourself if the images you’re taking will match the aesthetic of your app or website. The homepage for Squarespace37 is a good example of focus on imagery. It’s elegant, clean and uses a huge amount of white space and large, full-screen images to create a bold design that grabs your attention.
38 It’s important to choose pictures that fit the theme of the experiences we create. (Large preview39)
The product image sells the item. Users often rely on the product image to assess product and it’s features. Regardless of your product, whether it be headphones or toys, product photography is the most important element of any e-commerce website. Ultimately, the more attractive your products look to visitors, the more confident they’ll feel about purchasing from you, and the better your conversion rate will be.
Make product images beautiful. A good image does all the hard work for you: It captures users’ attention and differentiates your product. However, good product photography requires work. Consider reading the article “Improve Your E-Commerce Design With Brilliant Product Photos43” on how to take quality photographs of your products.
Let products sell themselves. Consider the Gorilla Pod44 example shown below. The photo demonstrates brilliantly the benefits of the product.
Display the primary image above the fold. Don’t make users scroll in order to see the main image for a product. The main product image should be anchored in a prominent position in order to merchandise your priority offerings.
For the image to be effective it needs to be big — as big as you can make it. Then, when you’ve maxed out the size of your image, you need to integrate the ability to zoom in on specific details of the product. This is especially important for products like apparel where users are more concerned with detail. The zoomed-in images also need to maintain high quality.
47 Don’t. Zoomed-in view forces the user to look at a specific part. (Image credit5048)49 Do. Put users in control by allowing them to zoom in as they prefer (both depth and area of zoom is controlled by the user). (Image credit5048)
Express Personality And Trigger User Emotions Link
Imagery can convey the essence of a product or service, but it can surprise and delight, too. Images have the capacity to entertain as much as to inform. If you already have a satisfying customer experience, adding delight to your product helps create an emotional connection with your users. Emotionally powerful imagery is a factor in ensuring that users continue to delve into your experience.
51 Imagery is able to evoke emotional responses in the viewer. A dash of humor can ease the burden and your users might love it. (Image credit52) (Large preview53)
The emotional brain is affected by photos and illustrations, especially of people, and by stories. Speaking about illustrations, even sites or apps that don’t incorporate the drawn style throughout still can use cartoons for these purposes. For example, illustrations can be used for instructions, tutorials and empty states.
Real-Life Scenario: How To Pick Images For Landing Page That Serves A Purpose Well Link
Landing pages are essentially your shop window and in most cases you have only one chance to impress the user. When it comes to landing pages, you want your visitors to have just one task on your page: to convert. Great landing pages are built around solid user experiences and imagery plays important role in building this experience. When users come to your page, they’ll have some kind of reaction. Whether it’s positive or negative, in large part, is determined by what they see.
Following the advice “show, don’t tell” and:
Choose imagery that fits your message.
It’s important to choose images that can simply explain the concept of the product or service. That doesn’t mean that the image needs to say everything — the image seen alone might not even seem to be clear, but it should logically fit when it’s connected to everything else on the page. It should visually reinforce the message you try to deliver to visitors.
Show images in the right place.
If the image supports a high priority goal, it should have more visual emphasis; conversely, images related to secondary goals should have less emphasis. The most important images should be anchored in a prominent position (i.e. above the fold), and should be a primary point of focus.
Choose striking visuals that capture attention.
Focus on selecting the most compelling images you can find. As Steven Snell mentioned, “A vivid, striking image will last in the minds of visitors. Text may be read and forgotten, but a strong image will be remembered.”
Use emotionally powerful imagery.
Your images should be emotionally persuasive — have an emotional impact and reinforce the feelings you are trying to create. After all, emotion often overrides logic when it comes to decision making.
Below is an example of landing page by Intercom57, a service that allows you to communicate with your customers more efficiently. The landing page takes a reasonably complex idea and makes it easy to understand how the product works, and why it might be beneficial.
58 Intercom uses illustration to compare the the old way of working, versus a simple approach. (Large preview59)
Thinking about images in terms of their usability is important. All visual communication in your design leaves a cumulative impression on the user.
Compelling images have a unique ability to inspire and engage your audience to provide useful information. Take the time to make every image in your app or site reinforce user experience.
This article is part of the UX design series sponsored by Adobe. The newly introduced Experience Design app63 is made for a fast and fluid UX design process, creating interactive navigation prototypes, as well as testing and sharing them — all in one place.
You can check out more inspiring projects created with Adobe XD on Behance64, and also visit the Adobe XD blog to stay updated and informed. Adobe XD is being updated with new features frequently, and since it’s in public Beta, you can download and test it for free65.
Creating that singular piece of graphic design1 that users will first interact with each time they encounter your product can be intimidating. A beautiful, identifiable and memorable app icon can have a huge impact on the popularity and success of the app. But how exactly does one make a “good” app icon? What does that even mean? Fear not, I’ve put together some tips and advice to help answer these questions and to guide you on your way to designing great app icons.
I’ve been designing2, making resources3 and giving talks4 about icon design for the past couple of years. In this article, and in the video at the end, I’ll sum up what I’ve learned about this amazing craft.
The first things you need to understand when setting out to create an icon is what exactly an app icon is and what job it performs. An app icon is a visual anchor for your product. Think of it as a tiny piece of branding that not only needs to look attractive and stand out, but ideally also communicates the essence of your application.
The word “logo” is thrown around carelessly these days. App icons are not logos. While they certainly share branding-like qualities, they’re under a lot of different restrictions. It’s an important distinction for a designer to make: Logos are scalable vector pieces of branding designed for letterheads and billboards. Icons are most often raster-based outputs customized to look good within a square canvas, at specific sizes and in specific contexts. The approach, the tools, the job and, therefore, the criteria for success are different.
From a practical standpoint, when you’re making an app icon, you are creating a set of PNG files in multiple sizes — ranging from small sizes like 29 × 29 pixels all the way up to 1024 × 1024 pixels — that need to be bundled with your app. This set of carefully crafted designs will be used in the many contexts of the operating system where users will encounter your application — including the iOS App Store and Google Play, the settings panel, the search results and the home screen.
App icons can essentially be made in any application capable of producing raster files, but common choices are Photoshop, Illustrator and Sketch. Tools like the ones found on Apply Pixels211210 offer clever PSD templates that can help you get off the ground quickly.
A short video demonstrating how to use one of the templates on Apply Pixels
Now, let’s look at some of the best practices in designing app icons. I’ll discuss each of my five core aspects of app icon design, give tips on how to improve each aspect and show off some examples of how I’ve worked with that quality. A lot of these examples will be based on my own work. That’s not because I feel like it is the best or only way to illustrate these things, but it has the added benefit of my knowing what thoughts went into the process. When going through the aspects, try to imagine icons that you like and how the individual aspects take shape in the icons on your home screen. Let’s get started.
One of the most important aspects of an icon is scalability. Because the icon is going to be shown in several places throughout the platform, and at several sizes, it’s important that your creation maintains its legibility and uniqueness. It needs to look good in the App Store, on “Retina” devices and even in the settings panel.
13 An app icon needs to work at multiple resolutions, retaining the legibility of the concept across the range of sizes.
Overly complicated icons that cram too much into the canvas often fall victim to bad scalability. A very big part of the conceptual stage of app icon design should be dedicated to thinking about whether a given design will scale gracefully.
An app icon is like a little song, and being able to identify it easily amidst the noise of the store and the home screen is a key component in great icon design. Just as the verse of a song needs to resonate with the listener, so do the shapes, colors and ideas of an app icon. The design needs to instill a memory and sense of connection on both a functional and an emotional level.
15 An icon can be detailed or simple; just make sure it’s creative and interesting and accurately conveys your intentions.
Your icon will be vying for attention among thousands of other icons, all of which have the same 1024-pixel canvas to make their impact and secure their connection with the viewer. While scalability is a huge part of recognizability, so is novelty. The search for balance between these qualities is the very crux of the discipline.
Bland, overly complicated icons are the enemy of recognizability. Try removing details from your icon until the concept starts to deteriorate. Does this improve recognizability?
Try out several variations of your design. Line them up on a grid and glance over them, seeing which aspects of the designs catch your eye.
Deconstruct your favourite app icons and figure out why you like them and what methods were used to make them stand out.
There’s something to be said for creating consistency between the experience of interacting with an app icon and interacting with the app it represents. I feel like good icon design is an extension of what the app is all about. Making sure the two support each other will create a more memorable encounter.
16 Consistency between icon and interface is important to strengthening the visual narrative.
Shaping a sleek, unified image of your app in the user’s mind increases product satisfaction, retention and virality. In short, getting your icon to work harmoniously with the essence, functionality and design of your application is a big win.
One way to ensure consistency between app and icon is to align their color palettes and to use a similar and consistent design language — a green interface reinforced by a green app icon, for example.
Although it’s not always possible, one way to tighten the connection between an app and its icon is to tie the symbolism of the icon directly to the functionality of the app.
17 Icons can also be made consistent across a suite of related apps.
This almost goes without saying, but try to make something unique. Mimicking a style or a trend is perfectly fine, but make it your own. Your icon will be constantly competing with other icons for the user’s attention, and standing out can be a perfectly valid argument for a design.
18 The “Productivity” category in the iOS App Store is a great example of how uniqueness hasn’t entered the design process.
Uniqueness is a tricky part of design, because it relies not only on your skill but also on the choices of others who are tackling a similar task.
Consider what everyone else is doing in your space and go in a different direction. Always do your research — the world doesn’t need another checkmark icon.
A single glyph on a one-color background can be a tricky route to go down if you want to be unique. Play around with different colors and compositions, and challenge yourself to find new and clever metaphors.
Color is a great and often overlooked way to reframe a concept.
19 Whatever your design style, uniqueness is often an exercise in finding a novel idea.20 Game icon design can be a great source of inspiration because there’s usually a broader range of ideas on display, free of convention.
This is one of my all-time top pet peeves. Only on the rarest of occasions is it OK to use words in an app icon. If you have to retreat to another tool of abstraction — the written word — then I’d say you’re not using the full force of your pictorial arsenal.
Words and pictures are separate representational tools, and mixing them in what is supposed to be a graphical representation usually leads to an experience that is cluttered, unfocused and harder to decode. Is there really no better way to visualize the application than with dry words? Whenever I see words in an app icon, I feel like the designer missed an opportunity to clearly convey their intention.
What to Think About When You’re Considering Words in Icons Link
There’s no need to include the app’s name in the icon — it will usually accompany the icon in the interface. Instead, spend your time coming up with a cool pictorial concept.
“But Facebook has the ‘f’ in its app icon,” I hear you say. If you’re using a single letter and it’s a good (and unique) fit, then the letter will lose its “wordy” quality and become iconic. However, this is more often the exception than the rule.
Your company logo and name in a square is never a good solution. Do you have a mark or a glyph that works well within the constraints? If not, then you’d probably be best off coming up with something new. Remember that an icon is not the same as a logo and shouldn’t be forced into the same context.
The App Store and Google Play have many examples of bland and unopinionated icon design. Your icon is the strongest connection you’ll have with the user. It is what they’ll see first when they meet you in the App Store. It’s what they’ll interact with every single time they use your app. It is what they’ll think of when they think of the app. Anything short of a well-thought-out, fitting and attractive solution will be a failure of your greatest visual asset. Your app icon should not be an afterthought; it should be a working part of the process.
App icons are tiny little pieces of concentrated design, and the qualities of good iconography are universal: scalability, recognizability, consistency and uniqueness. Mastering these will spill over to other areas of your design. Becoming an iconist will make you a better designer.
Whether they’re detailed or simple, conventional or creative, good icons have one unifying property: They all grab people’s attention in the same limited amount of space, on a completely level playing field. It’s a specific challenge, and the answer is always within that same canvas.
Crowning your application with a singular piece of graphic design is no doubt intimidating, but I hope the tips outlined above will make you more confident in taking on the challenge. Now go forth and make a fantastic app icon!
In this article, I’ve used icon tools available to subscribing members of Apply Pixels211210, but many icon tools are out there, both free and paid. Icon design is one of my great passions, and if you’re hungry for more, I’ve made several videos and given a lot of talks on the subject. Below are two that elaborate on the theories behind this article.
In the video above, in roughly 10 minutes, I go through the five major aspects of app icon design and give real working examples of how I’ve worked on them. It’s packed full of stories, advice and pixels, and I hope there’s something in it for everybody — whether you’re about to make your first app icon or are a seasoned veteran.In this one-hour neon-infused video, I go over some of my work and the concepts outlined in this article, and finally I give a demo on stage on improving an existing app icon.
I’ve been following the idea of algorithm-driven design for several years now and have collected some practical examples. The tools of the approach can help us to construct a UI, prepare assets and content, and personalize the user experience. The information, though, has always been scarce and hasn’t been systematic.
However, in 2016, the technological foundations of these tools became easily accessible, and the design community got interested in algorithms, neural networks and artificial intelligence (AI). Now is the time to rethink the modern role of the designer.
One of the most impressive promises of algorithm-driven design was given by the infamous CMS The Grid3. It chooses templates and content-presentation styles, and it retouches and crops photos — all by itself. Moreover, the system runs A/B tests to choose the most suitable pattern. However, the product is still in private beta, so we can judge it only by its publications and ads.
The Designer News community found real-world examples of websites created with The Grid, and they had a mixed reaction4 — people criticized the design and code quality. Many skeptics opened a champagne bottle on that day.
The idea to fully replace a designer with an algorithm sounds futuristic, but the whole point is wrong. Product designers help to translate a raw product idea into a well-thought-out user interface, with solid interaction principles and a sound information architecture and visual style, while helping a company to achieve its business goals and strengthen its brand.
Designers make a lot of big and small decisions; many of them are hardly described by clear processes. Moreover, incoming requirements are not 100% clear and consistent, so designers help product managers solve these collisions — making for a better product. It’s much more than about choosing a suitable template and filling it with content.
However, if we talk about creative collaboration, when designers work “in pair” with algorithms to solve product tasks, we see a lot of good examples and clear potential. It’s especially interesting how algorithms can improve our day-to-day work on websites and mobile apps.
Designers have learned to juggle many tools and skills to near perfection, and as a result, a new term emerged, “product designer7.” Product designers are proactive members of a product team; they understand how user research works, they can do interaction design and information architecture, they can create a visual style, enliven it with motion design, and make simple changes in the code for it. These people are invaluable to any product team.
However, balancing so many skills is hard — you can’t dedicate enough time to every aspect of product work. Of course, a recent boon of new design tools has shortened the time we need to create deliverables and has expanded our capabilities. However, it’s still not enough. There is still too much routine, and new responsibilities eat up all of the time we’ve saved. We need to automate and simplify our work processes even more. I see three key directions for this:
constructing a UI,
preparing assets and content,
personalizing the UX.
I’ll show you some examples and propose a new approach for this future work process.
Publishing tools such as Medium, Readymag and Squarespace have already simplified the author’s work — countless high-quality templates will give the author a pretty design without having to pay for a designer. There is an opportunity to make these templates smarter, so that the barrier to entry gets even lower.
For example, while The Grid is still in beta, a hugely successful website constructor, Wix, has started including algorithm-driven features. The company announced Advanced Design Intelligence8, which looks similar to The Grid’s semi-automated way of enabling non-professionals to create a website. Wix teaches the algorithm by feeding it many examples of high-quality modern websites. Moreover, it tries to make style suggestions relevant to the client’s industry. It’s not easy for non-professionals to choose a suitable template, and products like Wix and The Grid could serve as a design expert.
Introducing Wix Artificial Design IntelligenceSurely, as in the case of The Grid, rejecting designers from the creative process leads to clichéd and mediocre results (even if it improves overall quality). However, if we consider this process more like “paired design” with a computer, then we can offload many routine tasks; for example, designers could create a moodboard on Dribbble or Pinterest, then an algorithm could quickly apply these styles to mockups and propose a suitable template. Designers would become art directors to their new apprentices, computers.
Of course, we can’t create a revolutionary product in this way, but we could free some time to create one. Moreover, many everyday tasks are utilitarian and don’t require a revolution. If a company is mature enough and has a design system9, then algorithms could make it more powerful.
For example, the designer and developer could define the logic that considers content, context and user data; then, a platform would compile a design using principles and patterns. This would allow us to fine-tune the tiniest details for specific usage scenarios, without drawing and coding dozens of screen states by hand. Florian Schulz shows how you can use the idea of interpolation10 to create many states of components.
My interest in algorithm-driven design sprung up around 2012, when my design team at Mail.Ru Group required an automated magazine layout. Existing content had a poor semantic structure, and updating it by hand was too expensive. How could we get modern designs, especially when the editors weren’t designers?
Well, a special script would parse an article. Then, depending on the article’s content (the number of paragraphs and words in each, the number of photos and their formats, the presence of inserts with quotes and tables, etc.), the script would choose the most suitable pattern to present this part of the article. The script also tried to mix patterns, so that the final design had variety. It would save the editors time in reworking old content, and the designer would just have to add new presentation modules. Flipboard launched a very similar model13 a few years ago.
Vox Media made a home page generator14 using similar ideas. The algorithm finds every possible layout that is valid, combining different examples from a pattern library. Next, each layout is examined and scored based on certain traits. Finally, the generator selects the “best” layout — basically, the one with the highest score. It’s more efficient than picking the best links by hand, as proven by recommendation engines such as Relap.io15.
Creating cookie-cutter graphic assets in many variations is one of the most boring parts of a designer’s work. It takes so much time and is demotivating, when designers could be spending this time on more valuable product work.
Algorithms can create an entire composition. Yandex.Market uses a promotional image generator for e-commerce product lists (in Russian24). A marketer fills a simple form with a title and an image, and then the generator proposes an endless number of variations, all of which conform to design guidelines. Netflix went even further25 — its script crops movie characters for posters, then applies a stylized and localized movie title, then runs automatic experiments on a subset of users. Real magic! Engadget has nurtured a robot apprentice to write simple news articles about new gadgets26. Whew!
Truly dark magic happens in neural networks. A fresh example, the Prisma app29, stylizes photos to look like works of famous artists. Artisto30 can process video in a similar way (even streaming video).
Aristo app: exampleHowever, all of this is still at an early stage. Sure, you could download an app on your phone and get a result in a couple of seconds, rather than struggle with some library on GitHub (as we had to last year); but it’s still impossible to upload your own reference style and get a good result without teaching a neural network. However, when that happens at last, will it make illustrators obsolete? I doubt it will for those artists with a solid and unique style. But it will lower the barrier to entry when you need decent illustrations for an article or website but don’t need a unique approach. No more boring stock photos!
For a really unique style, it might help to have a quick stylized sketch based on a question like, “What if we did an illustration of a building in our unified style?” For example, the Pixar artists of the animated movie Ratatouille tried to apply several different styles to the movie’s scenes and characters; what if a neural network made these sketches? We could also create storyboards and describe scenarios with comics (photos can be easily converted to sketches). The list can get very long.
Finally, there is live identity, too. Animation has become hugely popular in branding recently, but some companies are going even further. For example, Wolff Olins presented a live identity for Brazilian telecom Oi33, which reacts to sound. You just can’t create crazy stuff like this without some creative collaboration with algorithms.
One way to get a clear and well-developed strategy is to personalize a product for a narrow audience segment or even specific users. We see it every day in Facebook newsfeeds, Google search results, Netflix and Spotify recommendations, and many other products. Besides the fact that it relieves the burden of filtering information from users, the users’ connection to the brand becomes more emotional when the product seems to care so much about them.
However, the key question here is about the role of designer in these solutions. We rarely have the skill to create algorithms like these — engineers and big data analysts are the ones to do it. Giles Colborne of CX Partners sees a great example in Spotify’s Discover Weekly feature: The only element of classic UX design here is the track list, whereas the distinctive work is done by a recommendation system that fills this design template with valuable music.
34Spotify’s Discover Weekly feature (a slide from Giles Colborne’s presentation)
Colborne offers advice to designers35 about how to continue being useful in this new era and how to use various data sources to build and teach algorithms. It’s important to learn how to work with big data and to cluster it into actionable insights. For example, Airbnb learned how to answer the question, “What will the booked price of a listing be on any given day in the future?” so that its hosts could set competitive prices36. There are also endless stories about Netflix’s recommendation engine.
“Interaction designers vs. algorithms” by Giles Colborne (Source37)A relatively new term, “anticipatory design38” takes a broader view of UX personalization and anticipation of user wishes. We already have these types of things on our phones: Google Now automatically proposes a way home from work using location history data; Siri proposes similar ideas. However, the key factor here is trust. To execute anticipatory experiences, people have to give large companies permission to gather personal usage data in the background.
I already mentioned some examples of automatic testing of design variations used by Netflix, Vox Media and The Grid. This is one more way to personalize UX that could be put onto the shoulders of algorithms. Liam Spradlin describes the interesting concept of mutative design39; it’s a well-though-out model of adaptive interfaces that considers many variables to fit particular users.
I’ve covered several examples of algorithm-driven design in practice. What tools do modern designers need for this? If we look back to the middle of the last century, computers were envisioned as a way to extend human capabilities. Roelof Pieters and Samim Winiger have analyzed computing history and the idea of augmentation of human ability40 in detail. They see three levels of maturity for design tools:
First-generation systems mimic analogue tools with digital means.
The second generation is assisted creation systems, where humans and machines negotiate the creative process through tight action-feedback loops.
The third generation is assisted creation systems 3.0, which negotiate the creative process in fine-grained conversations, augment creative capabilities and accelerate the acquisition of skills from novice to expert.
Algorithm-driven design should be something like an exoskeleton for product designers — increasing the number and depth of decisions we can get through. How might designers and computers collaborate?
The working process of digital product designers could potentially look like this:
Explore a problem space, and pick the most valuable problem for the business and users to solve (analysis).
Explore a solution space, and pick the best solution to fix the problem (analysis).
Develop, launch and market a product that solves this problem (synthesis).
Evaluate how the product works for real users, and optimize it (analysis and synthesis).
Connect and unify the solution with other products and solutions of the company (synthesis).
These tasks are of two types: the analysis of implicitly expressed information and already working solutions, and the synthesis of requirements and solutions for them. Which tools and working methods do we need for each of them?
Analysis of implicitly expressed information about users that can be studied with qualitative research is hard to automate. However, exploring the usage patterns of users of existing products is a suitable task. We could extract behavioral patterns and audience segments, and then optimize the UX for them. It’s already happening in ad targeting, where algorithms can cluster a user using implicit and explicit behavior patterns (within either a particular product or an ad network).
To train algorithms to optimize interfaces and content for these user clusters, designers should look into machine learning43. Jon Bruner gives44 a good example: A genetic algorithm starts with a fundamental description of the desired outcome — say, an airline’s timetable that is optimized for fuel savings and passenger convenience. It adds in the various constraints: the number of planes the airline owns, the airports it operates in, and the number of seats on each plane. It loads what you might think of as independent variables: details on thousands of flights from an existing timetable, or perhaps randomly generated dummy information. Over thousands, millions or billions of iterations, the timetable gradually improves to become more efficient and more convenient. The algorithm also gains an understanding of how each element of the timetable — the take-off time of Flight 37 from O’Hare, for instance — affects the dependent variables of fuel efficiency and passenger convenience.
In this scenario, humans curate an algorithm and can add or remove limitations and variables. The results can be tested and refined with experiments on real users. With a constant feedback loop, the algorithm improves the UX, too. Although the complexity of this work suggests that analysts will be doing it, designers should be aware of the basic principles of machine learning. O’Reilly published45 a great mini-book on the topic recently.
Two years ago, a tool for industrial designers named Autodesk Dreamcatcher46 made a lot of noise and prompted several publications from UX gurus47. It’s based on the idea of generative design, which has been used in performance, industrial design, fashion and architecture for many years now. Many of you know Zaha Hadid Architects; its office calls this approach “parametric design48.”
Logojoy51 is a product to replace freelancers for a simple logo design. You choose favorite styles, pick a color and voila, Logojoy generates endless ideas. You can refine a particular logo, see an example of a corporate style based on it, and order a branding package with business cards, envelopes, etc. It’s the perfect example of an algorithm-driven design tool in the real world! Dawson Whitfield, the founder, described machine learning principles behind it52.
However, it’s not yet established in digital product design, because it doesn’t help to solve utilitarian tasks. Of course, the work of architects and industrial designers has enough limitations and specificities of its own, but user interfaces aren’t static — their usage patterns, content and features change over time, often many times. However, if we consider the overall generative process — a designer defines rules, which are used by an algorithm to create the final object — there’s a lot of inspiration. The working process of digital product designers could potentially look like this:
An algorithm generates many variations of a design using predefined rules and patterns.
The results are filtered based on design quality and task requirements.
Designers and managers choose the most interesting and adequate variations, polishing them if needed.
A design system runs A/B tests for one or several variations, and then humans choose the most effective of them.
It’s yet unknown how can we filter a huge number of concepts in digital product design, in which usage scenarios are so varied. If algorithms could also help to filter generated objects, our job would be even more productive and creative. However, as product designers, we use generative design every day in brainstorming sessions where we propose dozens of ideas, or when we iterate on screen mockups and prototypes. Why can’t we offload a part of these activities to algorithms?
The experimental tool Rene55 by Jon Gold, who worked at The Grid, is an example of this approach in action. Gold taught a computer to make meaningful typographic decisions56. Gold thinks that it’s not far from how human designers are taught, so he broke this learning process into several steps:
Analyze glyphs to understand similarities in typefaces.
Formulate basic guidelines for combining typefaces.
Identify the best examples of type combinations to understand trends.
Create algorithms to observe how great designers work.
His idea is similar to what Roelof and Samim say: Tools should be creative partners for designers, not just dumb executants.
57Generative design by Jon Gold: Plausible combinations
Gold’s experimental tool Rene is built on these principles58. He also talks about imperative and declarative approaches to programming and says that modern design tools should choose the latter — focusing on what we want to calculate, not how. Jon uses vivid formulas to show how this applies to design and has already made a couple of low-level demos. You can try out the tool59 for yourself. It’s a very early concept but enough to give you the idea.
Rene — A Product Design ToolWhile Jon jokingly calls this approach “brute-force design” and “multiplicative design,” he emphasizes the importance of a professional being in control. Notably, he left The Grid team earlier this year.
Unfortunately, there are no tools for product design for web and mobile that could help with analysis and synthesis on the same level as Autodesk Dreamcatcher does. However, The Grid and Wix could be considered more or less mass-level and straightforward solutions. Adobe is constantly adding features that could be considered intelligent: The latest release of Photoshop has a content-aware feature60 that intelligently fills in the gaps when you use the cropping tool to rotate an image or expand the canvas beyond the image’s original size.
Introducing Content-Aware CropThere is another experiment by Adobe and University of Toronto. DesignScape61 automatically refines a design layout for you. It can also propose an entirely new composition.
DesignScape: Design with Interactive Layout SuggestionsYou should definitely follow Adobe in its developments, because the company announced a smart platform named Sensei62 at the MAX 2016 conference. Sensei uses Adobe’s deep expertise in AI and machine learning, and it will be the foundation for future algorithm-driven design features in Adobe’s consumer and enterprise products. In its announcement63, the company refers to things such as semantic image segmentation (showing each region in an image, labeled by type — for example, building or sky), font recognition (i.e. recognizing a font from a creative asset and recommending similar fonts, even from handwriting), and intelligent audience segmentation.
However, as John McCarthy, the late computer scientist who coined the term “artificial intelligence,” famously said, “As soon as it works, no one calls it AI anymore.” What was once cutting-edge AI is now considered standard behavior for computers. Here are a couple of experimental ideas and tools64 that could become a part of the digital product designer’s day-to-day toolkit:
But these are rare and patchy glimpses of the future. Right now, it’s more about individual companies building custom solutions for their own tasks. One of the best approaches is to integrate these algorithms into a company’s design system. The goals are similar: to automate a significant number of tasks in support of the product line; to achieve and sustain a unified design; to simplify launches; and to support current products more easily.
Modern design systems started as front-end style guidelines, but that’s just a first step (integrating design into code used by developers). The developers are still creating pages by hand. The next step is half-automatic page creation and testing using predefined rules.
If we look in the near term, the value of this approach is more or less clear:
Remove the routine of preparing assets and content, which is more or less mechanical work.
Broaden creative exploration, where a computer makes combinations of variables, while the designer filters results to find the best variations.
Optimize a user interface for narrow audience segments or even specific users.
Quickly adapt a design to various platforms and devices, though in a primitive way.
Experiment with different parts of a user interface or particular patterns — ideally, automatically.
Altogether, this frees the designer from the routines of both development support and the creative process, but core decisions are still made by them. A neat side effect is that we will better understand our work, because we will be analyzing it in an attempt to automate parts of it. It will make us more productive and will enable us to better explain the essence of our work to non-designers. As a result, the overall design culture within a company will grow.
However, all of these benefits are not so easy to implement or have limitations:
We can only talk about a company’s custom solutions in the context of the company’s own tasks. The work requires constant investment into development, support and enhancement.
As The Grid’s CMS shows, a tool alone can’t do miracles. Without a designer at the helm, its results will usually be mediocre. On the other hand, that’s true of most professional tools.
Breaking past existing styles and solutions becomes harder. Algorithm-driven design is based on existing patterns and rules.
Copying another designer’s work becomes easier if a generative design tool can dig through Dribbble.
There are also ethical questions: Is design produced by an algorithm valuable and distinct? Who is the author of the design? Wouldn’t generative results be limited by a local maximum? Oliver Roeder says68 that “computer art” isn’t any more provocative than “paint art” or “piano art.” The algorithmic software is written by humans, after all, using theories thought up by humans, using a computer built by humans, using specifications written by humans, using materials gathered by humans, in a company staffed by humans, using tools built by humans, and so on. Computer art is human art — a subset, rather than a distinction. The revolution is already happening, so why don’t we lead it?
This is a story of a beautiful future, but we should remember the limits of algorithms — they’re built on rules defined by humans, even if the rules are being supercharged now with machine learning. The power of the designer is that they can make and break rules; so, in a year from now, we might define “beautiful” as something totally different. Our industry has both high- and low-skilled designers, and it will be easy for algorithms to replace the latter. However, those who can follow and break rules when necessary will find magical new tools and possibilities.
Moreover, digital products are getting more and more complex: We need to support more platforms, tweak usage scenarios for more user segments, and hypothesize more. As Frog’s Harry West says, human-centered design has expanded from the design of objects (industrial design) to the design of experiences (encompassing interaction design, visual design and the design of spaces). The next step will be the design of system behavior: the design of the algorithms that determine the behavior of automated or intelligent systems. Rather than hire more and more designers, offload routine tasks to a computer. Let it play with the fonts.
Editor’s Note: New year, new challenges! You might have set up your New Year’s resolutions already, but if not, how about designing something… different for a change? Today, we’re happy to introduce Dorota1, an artist who created a fun little project last year that was inspired by Twitter’s new logo based on 13 circles2. Below you’ll find the lessons Dorota has learned along the process, so maybe you’d like to embark on a similar journey as well?
If you can make a bird out of circles, then you can probably make all sorts of animals. I wanted to add something more design-based to my portfolio, so I made that my personal challenge. The idea was to draw animals from exactly 13 circles, and I decided to match that number by making 13 animals. This makes for a nicer title for the project, and it helps to get others to share it around the web, too. Knowing what you want to create early on helps, because then all you have to do is figure out ways to make it happen.
The project mostly consisted of three Adobe applications: Photoshop, Illustrator and After Effects.
I prefer to sketch things on paper first, but you can do so digitally as well. First, I chose some animals that I didn’t think would be extremely difficult to draw. Then, I chose prominent features of those animals to focus on. I also Googled logos, designs and illustrations of the animals to see what features other people emphasize. When limited to 13 circles, you can’t fit everything! For example, with the monkey, all I could fit were the ears, the long tail and the outline around the eyes, leaving me with few circles to play with, but that’s OK.
While sketching, I kept track of the number of circles I was using, counting one for every curve. If I had too many circles, I would examine them to see if two curves could somehow come from one circle. For example, in the part of the giraffe below, the orange circle serves as both the top of the left horn and the bottom of the ear:
After I had a sketch I was happy with, I photographed it or scanned it to my computer.
Before I began, I decided on a size for the project. This is important for consistency and to keep things moving quickly in Photoshop and After Effects. I chose 8 × 10 inches at 300 DPI (or PPI), just in case I decided to print them after, because that’s a common print size. I also felt the ratio would be good to turn them into animated GIFs later.
Here are the first steps to take in Illustrator:
Open your sketch, or drag or paste it into your sized document. Select the sketch, and click Ctrl + 2 to lock it in place.
Draw circles using the Ellipse tool (L); to make perfect circles, hold Shift while dragging. You can find the ellipses by holding or right-clicking the Rectangle tool. Select your circle(s), and set the fill to none, and choose a small stroke to work with. Hide the sketch layer once you’ve finished by clicking the eye.
Select all of your circles by enabling the Selection tool (V) and dragging from one corner over the entire screen. Resize them to the size you want the animal to be in the document. This is important if you want to save time later.
With the circles still selected, we’re going to make a backup by clicking Ctrl + C, then clicking “New Layer,” then clicking Ctrl + F. This pastes in the exact same location. Hide the backup layer.
Click the Shape Builder tool (Shift + M), choose a fill color (removing the stroke), and click in the parts of the circles that you want to fill in.
Once you’re happy with the shape, isolate all the filled shapes from the circles by clicking on one and then going to menu “Select” → “Same” → “Fill Color”. Once they’re selected, you can simply copy them, select & delete everything in the document (we backed up the circles), and press Ctrl + F to bring back just the filled shapes.
Instead of the Shape Builder tool in step 4, you could also use the Live Paint Bucket tool (K), which allows you to move the circles safely while keeping your area filled in, and then you would expand at the very end.
Sometimes the curves I sketched didn’t perfectly form a circle, so I’d have to go back and move a few curves around or change their sizes. If you merely want to suggest some shapes in your animal (rather than being explicit), you may have to add more circles. For example, sometimes I would want an area to be cut out, such as the inside of the fox tail. Other times, I would want an area to be a different color from the rest of the shape, such as the toucan’s beak. There are many ways to create separation.
At this point, I had the animal (still in pieces), a hidden layer with the circles, and a hidden layer with the sketch.
Sometimes, at this point, I would turn the animal into one solid shape. To do this, select the animal, open the Pathfinder panel (in the menu, “Window” → Pathfinder, or Ctrl/Cmd + Shift + F9) and click the “Unite” option. The paths might have small flaws, but you can usually fix those using the Direct Selection tool (A), which allows you to click individual anchors and paths to easily move, modify or delete them.
Often, however, rather than turning an animal into a solid shape, I would add a bit of shading using gradients. I would often add these to one section of the animal, and I would use the same method as above to select a couple of pieces of an animal and merge those pieces into one (often, my animals would be in two or three pieces by the end).
In this example, you can see that I used different shading methods on different parts of the monkey. Above the monkey’s eyes, I used the Mesh tool (U) to get a gradient that follows the curves. A fast way to add a mesh is to click an object and go to “Object” → “Create Gradient Mesh.” I’m not an expert with this tool yet, so my attempt is more of an experiment.
Underneath the monkey’s face, I simply used a regular gradient. A fast way to apply a gradient to an object is to click the object and press the period key (.). Then, in the menu, go to “Window” → “Gradient” to open the Gradient panel and change the settings of that gradient.
Because I knew I would be bringing the animals into Photoshop after, I simply shaded them with shades of gray. This way, if I wanted to use different blending modes with colors and textures, the hues that I chose would be retained.
Create a document in Photoshop of the exact size as your Illustrator document (this is to make things easy and is not a requirement). I also stayed with the RGB color space because my focus is the web, but I can always convert to CMYK later if I want to print. Before bringing in the animals, I would create the background first.
I started with the colors. There are many ways to create gradients. I started with a white background and then simply stacked a few transparent layers of lightly brushed colors. Sometimes I would further tweak the colors using an Adjustment Layer such as “Curves” (experiment to find what works best for you).
Once you’ve got the color gradients down, it’s time to add some texture! I experimented with many different textures that I downloaded online — you can find many by searching for terms like “free paper texture.” There are also some nice textures on Subtle Patterns11, but they’re usually small image tiles meant to be repeated, and I personally don’t like repeating ones.
I often used a subtle paper texture as a base and then used other textures to bring out more light and dark speckles. It’s easy to bring out speckles from a texture using Curves or Levels. All of my textures are overlaid using different blending modes, as well as by experimenting with opacity.
And below are the layers for the background, along with my settings for each Curves layer. The really crazy curves were the ones I used to bring out different parts of the textures, such as the speckles.
As I said, experiment with Photoshop’s functionality until you’re happy. Here are the layers for this background, starting from the bottom:
a blank white background;
lightly painted colors at a small opacity using the brush;
noise (“Filter” → “Noise” → “Add Noise”) at a 41% “Overlay” blending mode, sometimes enlarged or blurred;
a texture layer with “Color Burn”;
a Curves adjustment layer clipped to the texture layer, to create a high contrast for the speckles in the texture;
a texture layer again, rotated to a different position and a “Color Burn” of 40%;
a Curves layer clipped to the texture, this time bringing out the textures in a different way;
a blue layer set to “Divide” at 37%;
an overall Curves layer to brighten the entire image (including the monkey).
Once my background was ready, I brought in the animal as a smart object. Use smart objects18 whenever possible. I simply copied and pasted the animal from Illustrator. Because the documents are the same size, the animal should be pasted into Photoshop at the same size. I didn’t resize the animal in Photoshop, so that I could easily align the circles in a further step.
It’s almost time to animate! I animated in After Effects, although many programs will do it (Photoshop has some basic animation capability, too).
Use “File” → “Place” (Shift + Ctrl + P) to place the Photoshop file in Illustrator as a linked object; this way, if you need to make any changes in the Photoshop file, it will automatically update in Illustrator. Placing the file in the top-left corner anchor works best, from what I’ve seen. Next, bring back your circles by unhiding the backup layer we created. You may have to drag and change the order of the layers to stack the circles on top, and you might have to realign them to your animal if it has moved.
I decided to stoke the circles with a dashed line. I did this by selecting the circles, clicking “Stroke,” checking “Dashed line” and specifying the size of the dash and the size of the gap. I used 5 points for the dash and 3 points for the gap.
In case you need to slightly resize the circles, select them and use the width (“W”) and height (“H”) boxes on top to change the size in small increments. Make sure the chain in the middle is activated, to maintain the proportions.
I had to put each circle on a separate layer so that I could animate them in After Effects. I simply created 13 new layers, then dragged a circle into each one. Your file will look like this:
First, download and install Ease & Wizz25, which will make the movement of our circles a bit more interesting — moving in slow, speeding up quickly, and ending slow again. This is a “name your price” script, so you could technically download it for $0.
Start a new project, go to “Import” → “File” (Ctrl + I), and select your Illustrator file. But make sure where it says “Import as Footage,” you change it to “Composition — Retain layer sizes.”
If the composition doesn’t open up right away, double-click it in the “Project” tab. If you’re planning to resize the composition, make sure to click the little gear icon to the right of it.
It might also be a good idea to choose an animation frame rate before starting (“Composition” → “Composition Settings”). I chose 20 frames per second because I knew my animation would be quite short and would loop. If you’re working with a longer animation, you should lower it, because animated GIFs with a high number of frames can end up being too big in size.
Select all of the layers except for the layer with the background; right-click and choose “Create shapes from vector layer.” These are the shapes we’ll be animating. The original Illustrator layers should still be there, but their visibility should now be off.
Choose a shape layer, and click its contents; to the right of it, where it says “Add,” select “Trim Paths.” First, I set “End” to 0%. Clicking the stopwatch near “Start” or “End” will activate the keyframes for that action and turn blue. A keyframe will be created at that point, depending on where your indicator is placed. It’ll be a small diamond. I set mine to “Start 0%,” which made my circle invisible, and I moved it down the timeline to where I wanted my circles to start animating. Move your indicator down the timeline, and then change “Start” to 100%; you’ll see a new keyframe appear automatically.
Depending on which direction you want the path to disappear (clockwise versus counterclockwise), you might have to start with “Start” or “End.” Below is an example of what I did to make the circle be invisible at first for a moment, appear into the frame, pause, and then disappear in the direction that it appeared. The timing isn’t what I used for my project — it’s just an example.
Then, I added the Ease & Wizz effect. Open the plugin by going to “Window” → “Ease and Wizz” (.jsx). Then, highlight and select all of the keyframes, and click “Apply” (I used the plugin’s default settings). The percentage text should now be in red. You could also drag the plugin window into your toolbar, so that it’s not floating around.
Also, I used the Rotation tool (W) on the circles to rotate them, so that the animation starts at a different point, such as the end of the tail, rather than right in the middle of it.
You can also copy and paste your keyframes into the “Trim Paths” folder of another circle if that animation is going in the same direction that you want this circle to go in. I created a clockwise animation and then a counterclockwise one (renaming the layer folders to not lose my place), and I would copy and paste those keyframes into the rest of the circles according to how I wanted; for example, the monkey’s tail would be counterclockwise, whereas the ears would be clockwise.
Once all of the circles are done, you can go to “File” → “Export” → “Add to Render Queue” (or Ctrl + Shift + /) and render it as an AVI file (or any video format of your choice).
To turn the video into an animated GIF, I opened Photoshop and went to “File” → “Import” → “Video Frames to Layers.” Once it opens up, I went to “Windows” → “Timeline” (or “Animation”) to open the “Animation” tab. In newer versions of Photoshop, you have the option of a video timeline or a frame animation. I chose frame animation.
Because there were pauses in my animation, each pause rendered as its own frame, so I had to delete all of the duplicate frames from each pause in the animation and keep only one frame, but then set the timing of that one frame to a higher duration. You can avoid this by removing all gaps in your After Effects animation and then adding the pauses back in Photoshop; however, not being able to see the entire thing at once might make it a little harder to decide on the duration of the animation. Also, don’t forget to set the looping option to “forever.”
30 Frames 1, 28 and 53 are consolidated in my example (you could further combine 1 and 53). (View large version31)
Once that’s done, go to “File” → “Export” → “Save for Web” and choose “GIF.” Here is where it gets experimental, because I had to play around with the settings to get a good balance of quality and file size. Choosing the best quality will often make the file size way too big (I try never to exceed 1 MB for a GIF).
I also found that when resizing the image to be smaller, the color table would change and would often look much worse (or even vice versa). Here’s a trick: Change the animated GIF to various sizes until the colors look as best as possible, then save that color table, resize it to your desired size, and then load that color table:
When I initially created the animals, I didn’t make sure that all of my document sizes were the same, and so I had to resize and realign all of the circles for each animal! Pay close attention to document size.
I haven’t figured out why an image loads in After Effects at narrower than 600 pixels, even when the original document is much larger! I have a lot to learn about After Effects.
I haven’t yet figured out a way to quickly remove extra frames in a Photoshop animation. Maybe better applications for creating GIFs are out there?
I also gained some knowledge while working on this:
I’ve never really drawn so many animals before. I realized with this project that you’re not really drawing the animal — you’re mainly just drawing its features! That takes a lot of the pressure off.
I also realized that experimenting with textures can be extremely difficult and sometimes hit or miss. Start building your texture collection folder early on! I wish I had started years ago.
I discovered the color table trick only after getting extremely annoyed when some of the GIFs would suddenly look horrible when I’d change their size by a slight amount (for example, 50 pixels in width). Always be open to discovering tricks, even in the applications most familiar to you!
This was probably my third time making something in After Effects, so there was a lot of tedious trial and error here, as well as some help from a friend. It helps having friends who share your passion.
I did many things that could probably have been done more quickly or easily. This was a learning experience. If you have any tips for making these types of animations faster, better or easier, feel free to share in the comments!
New year, new beginnings! To cater for a fresh start into 2017 and all the challenges, endeavors and adventures it might bring along, artists and designers from across the globe put their creative skills to the test and created unique desktop wallpapers for you to indulge in.
This monthly wallpapers mission has been going on for eight years1 now, and we are very thankful to all the creative minds who contribute to it tirelessly each month anew. Today’s wallpapers all come in versions with and without a calendar and can be downloaded for free. Happy New Year!
Please note that:
All images can be clicked on and lead to the preview of the wallpaper,
You can feature your work in our magazine2 by taking part in our Desktop Wallpaper Calendars series. We are regularly looking for creative designers and artists to be featured on Smashing Magazine. Are you one of them?
Looking for more winter-related wallpapers3 dedicated to snow, ice and frost? We’ve got you covered with only the best ones since 2008.
“The new year brings hope, festivity, lots and lots of resolutions, and many more goals that need to be achieved. This wallpaper is based on the idea of ‘A New Start’.” — Designed by Damn Perfect84 from India.
“You wake me up to a beautiful day; lift my spirit when I’m feeling blue. When I’m home you relieve me of the long day’s stress. You help me have a good time with my loved ones; give me company when I’m all alone. You’re none other than my favourite cup of hot tea.” — Designed by Acodez IT Solutions129 from India.
“Following the busy Christmas season, the cold and boring January comes, love is one thing, what can make us warm for sure!” — Designed by Barbara Dörnyei172 from Hungary.
“Summer in Australia is about sun and the beach – which inspired the colours I have used. It is a wonderful celebration of the ending on one year and the beginning of another. I hope my illustration inspires this feeling of the celebration of rebirth and growth.” — Designed by Katherine Appleby216 from Australia.
“2017 is the year of the rooster according to the Chinese horoscope, which begins January 28, 2017. The rooster being the sign of dawn and awakening, triumph and success can only be achieved at the price of hard work and patience in 2017.” — Designed by Lucas Debelder259 from Belgium.
“2016 was an exciting year, many things happened and changed our world. In the coming year of 2017, we wish all to be more successful, to love and be loved, and to look into the future holding hands with your better half. Let every day in January be smashing for you. Happy New Year, everybody!” — Designed by PopArt Studio304 from Serbia.
“For once you have tasted flight you will walk the earth with your eyes turned skywards, for there you have been and there you will long to return. (Leonardo da Vinci)” — Designed by Dipanjan Karmakar421 from India.
“2017 is the year of the rooster, so I made a wallpaper with a rooster on it. I myself have 8 chickens at home but no rooster, so maybe we could buy one this year to celebrate the year of the rooster. Happy New Year to everyone!” — Designed by Melissa Bogemans450 from Belgium.
“I love Winnie the Pooh! January 18th marks A.A. Milne’s 135th birthday, the creator of Winnie the Pooh. I have included one of my favourite quotes to symbolize what an inspiration his stories have been to both kids and adults.” — Designed by Safia Begum491 from United Kingdom.
“Most of us have over-indulged a little over the holiday period – spare a thought for our bathroom scales, who will have much heavier people standing on them for the next few months!” — Designed by James Mitchell559 from United Kingdom.
“Sitting on a chair before my desk playing video games when a friend called me to ask something about the exams. Then I realized that I have one more week to study before the first exam begins. So wake up guys! It is time to study!” — Designed by Robert Vaida580 from Belgium.
“January is a month of cold winter days. Whenever I hear ‘January’, the first thing that comes to my mind are long sleepy winter nights, cause these days are the most comfortable for sleeping. It gives me the feeling of a baby from heaven sleeping comfortably.” — Designed by Swapnil Chavan599 from India.
“I choose a typographic wallpaper for the mont January to clearly emphasize my message to the world. We need to make this upcoming year a better year than 2016 and and we can only achieve that if we stand together and try making the best of it.” — Designed by Thomas Debelder637 from Belgium.
“January represents a new beginning, a new chance to start over. This wallpaper is made to charge everyone with energy and to remember that smiling everyday does make the difference.” — Designed by Rodrigo Flores675 from Costa Rica.
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.
We have all encountered names that are difficult to pronounce. Having a challenging name myself, I get different pronunciations of my first name, Atif, all the time. In order to solve my own naming problem, I built a Javascript plugin called Vocalizer. In this article, I will introduce what Vocalizer is and a few different ways to use it.
Earlier this year, I redesigned my portfolio website. During this process, I decided to add a feature that educated visitors on how to say my name. One day, I opened the “Voice Memos” app on my iPhone, tapped “Record”, and asked my wife to say my first name. Then, I embedded a small button onto the landing page after my first name. Clicking on that button would play the audio file of my name.
1 The audio pronunciation button that I added to my website (Large preview2)
After launching the website, I received a few emails and tweets calling out the audio feature. I even attended a few conferences and meetups where people pronounced my name the right way. A few people expressed interest in implementing the pronunciation feature on their own websites.
Over the next few weeks, I spent time converting my singular implementation into a reusable plugin. Before publicly releasing it, I stumbled upon a company called NameShouts, which is an audio-based pronunciation tool with a repository of over 70,000 name pronunciations. I reached out to them for access to their API, implemented it into my plugin, and open-sourced it.
Vocalizer is a simple, lightweight JavaScript plugin that facilitates the accessibility of difficult to pronounce names. If you’re someone who is unsure of how to say a certain name, Vocalizer shows you how. Or, if you’re someone with an unfamiliar name, Vocalizer shows others how to pronounce it.
3 A close-up view of what an implementation of Vocalizer looks like (Large preview4)
The benefit of using NameShouts’ API is that it makes the implementation as quick as possible. In its simplest usage, there are only two steps required to add it to a website.
First, you must include the Javascript library before the closing </body> tag within the code of your website:
Next, all you have to do is wrap your first name in a <span> tag with the specified attributes:
<span data-source="auto">NAME</span>
Note: The latest version of Vocalizer.js is available on CDNJS5, or you can choose to download6 and serve the files from your own server.
As you might have noticed, the data-source attribute is set to auto in the example above. This attribute determines the source of the audio file.
When data-source is set to auto, the library will use the NameShouts API. This option is completely hands-off. Vocalizer will automatically search NameShouts’ name listing and feed in the audio file from their servers.
The alternative option is to manually record and use your own audio file instead of the API. In this scenario, the data-source attribute should be set to the path to your audio file. For example:
There’s a chance that NameShouts’ library does not have the pronunciation for your name, and in that event, you should use your own audio recording or Vocalizer won’t be doing its job!
The actual source code for Vocalizer.js is about eighty lines of code. Let me explain exactly what’s happening under the hood.
When the user wraps his or her name within the <span> tag with the class vocalizer, a Javascript function stores that name into a string:
var name = document.getElementsByClassName('vocalizer'); var names = []; for (var i = 0; i < name.length; i++) { var data_source = name[i].getAttribute("data-source"); names[i] = name[i].innerHTML.toLowerCase().replace(/W/g,'') var request = buildRequests(names[i]); fetchAudio(data_source, request, i); }
We perform this inside of a loop in case there are multiple usages of Vocalizer on the page.
Next, a conditional checks the data-source attribute to see if you’re opting to use the NameShouts API to source the pronunciation or if you’re using your own audio file:
var data_source = name[i].getAttribute("data-source"); if (data_source == 'auto') { /* code for using NameShouts API */ } else { /* code for using your own audio file */ }
The buildRequest() function that we call inside that loop returns the path for the endpoint based on the user’s name.
function buildRequests(n) { return request = 'https://www.nameshouts.com/api/names/'+n; }
From there, we pass the request to the fetchAudio() function and make our xmlHttpRequest to the NameShouts API.
var xhr = new XMLHttpRequest(); xhr.open('GET', request, true); xhr.onload = function (e) { if (xhr.readyState === 4) { if (xhr.status === 200) { var audioPath = JSON.parse(xhr.responseText).message[names[i]][0]["path"]; var audio = new Audio(BASE_URL+audioPath+'.mp3'); audio.playbackRate = 0.75; name[i].addEventListener('click', function() { audio.play(); }, false); } else { console.error(xhr.statusText); } } } xhr.onerror = function (e) { console.error(xhr.statusText); }; xhr.send(null);
NameShouts’ API returns a JSON object that contains the name of the audio file corresponding to your name. From there, we combine NameShouts’ base URL (where the audio files are stored) and the audio file’s path.
In the event the name you are targeting does not exist within the NameShouts API, the plugin will throw an error.
A solution to this situation would be to record and link your own audio file. Setting the data-source attribute to a file path designates your own audio file. In that case, we just create an Audio element based on the file path from data-source:
var audioPath = sourceType; var btn = document.getElementsByClassName('vocalizer'); var audio = new Audio(audioPath, function() { 'Error!'; });
On the front end, an audio button appears after the targeted name. The cosmetics are added with CSS styles on the pseudo-element :after on the <span> tag.
Finally, we add a click event to the audio button:
Vocalizer’s use case can extend beyond just personal websites. I can see blogs and digital news publications begin to adopt the plugin, as well.
7 An example of how Vocalizer could be used by news publications, such as Vox.com (Image credit8) (Large preview9)
Imagine you are browsing news stories on Vox.com10 and you see the name of a political figure or a region of the world with a name in which you are unfamiliar. In that situation, Vocalizer could educate you on its pronunciation. In theory, this would better equip you to discuss these current events and issues. No one wants to sound uninformed.
In an age when people often connect with each other via social media platforms, such as Facebook, Twitter, or LinkedIn, prior to meeting — a tool like Vocalizer could prove useful.
Unbeknownst to me, Facebook recently rolled out a similar feature that automatically generates audio to enunciate names.
It’s nice to see mainstream platforms focus on these types of accessibility features. Unfortunately, there is no guarantee that autogenerated playback will be correct. Facebook’s pronunciation tool mangles my last name.
With every potential solution, there are problems. Vocalizer faces issues of its own. The main issue is that two people with the same name do not always pronounce their name in the same way.
Often, a person’s origin language dictates the pronunciation of their name. For example, the name José in Spanish is pronounced HOH-SEH. In French, the same name is pronounced JOO-ZE. Vocalizer’s current implementation does not cater to these circumstances unless you opt to use a custom recording.
In the last few years, web evangelists have emphasized the importance of web accessibility. Most accessibility functions cater to people with physical and cognitive disabilities. I believe there is a lack of attention in regards to inclusion and cross-cultural accessibility.
Though unintentional, in a way, Vocalizer seeks to enable cultural accessibility. Technology companies continually strive to diversify their workforces. We’re seeing heightened mobility in our professional lives. As a result, multiculturalism is becoming more and more prevalent.
For what it is — I hope Vocalizer helps familiarize people with names from other cultures or ethnicities.
A 2014 study18 found that people with easier-to-pronounce names are deemed “more trustworthy”. I built Vocalizer to solve a problem that has persisted all my life. Now, I hope this will prove useful to others, helping them solve the same problem.
Thanks so much for reading! Please don’t hesitate to tweet to me19 if you have any questions, comments or feedback.
With a couple of days left until New Year’s Eve, it’s just about time to set aside 60 minutes to clean up, sort out and back up your digital footprint, to ensure a good smooth start to 2017. So many little details tend to get forgotten or overlooked every single time, only to get fixed hastily later — but doesn’t it just feel right when everything is in the right place, neatly organized, even if you aren’t a compulsory cleaner or an obsessed perfectionist?
This is not a generic article about unspectacular things like getting to inbox zero or changing the copyright year in your footer (although that’s a good idea!) — we published a detailed checklist1 of all of those details a couple of years ago. Instead, you’ll find below an overview of all of those obscure little things that I forget about every year; so, I decided to gather them all in one place once and for all.
The list below serves as a personal reminder for yours truly, and I thought that it might be useful for you as well. In fact, I set up a yearly reminder on December 28th just to have a couple of days to free the mind for the more important things in life and to start the next year without second thoughts or unresolved issues. Curious? Well, let’s dive in!
If you think something is missing, do please let us know in the comments so that we can put it all together and benefit from it collectively.
Invoices! Who doesn’t occasionally forget to include a payslip in their invoice, basically throwing money out of the window? Extract all the receipts and payslips that have accumulated over the year. You might already be using a dedicated phone app to scan, keep, organize, submit and track your receipts, but you might still have some neglected receipts in your inbox as well.
Collect train, bus and airplane PDF tickets and receipts. You could organize them by destination and add a date stamp in a separate folder (for example, 2016/Dec-London/Receipts).
Collect Uber, Lyft, Gett and other PDF receipts, and save them in those folders as well (for example, 2016/Dec-London/Receipts/Cabs).
Collect PDF receipts for accommodation business expenses (Airbnb, hotels, takeout food), and save them in those folders (for example, 2016/Dec-London/Receipts/Accommodation).
Collect one-time expenses for printed books and eBooks, including any online purchases (such as from Amazon). Don’t forget those handy utilities (Alfred, TextExpander, etc.), mobile apps, as well as your third-party text editor and calendar applications. Again, save them in those folders (for example, 2016/one-time-expenses).
Collect monthly digital expenses as PDF receipts and save them. Think of mobile phone charges, roaming expenses, Internet and TV, GitHub, CodePen, Typekit, Dropbox, Spotify, Slack, BrowserStack, Amazon S3, Adobe Creative Cloud, email services such as MailChimp, Litmus and Campaign Monitor, Flickr, Vimeo, Dribbble, Netflix, CRM tools, Amazon Prime, external services, hosting services and CDNs, usability testing tools, conference and workshop tickets, learning services such as Treehouse and Skillshare, and other monthly service costs2. Not to mention the antivirus software and firewalls that you’re using (and probably paying for monthly as well). Your monthly digital service costs might be higher than you think.
Once you’ve collected all of the receipts, you could set up a little spreadsheet3 to keep track of your expenses (even using the free Google Spreadsheet template4). Your accountant will appreciate it, and you can set up a budget allowance of how much you’d like to spend next year. Knowing where you stand will help you decide how much money to set aside next year, and how you’d like to approach it strategically.
While you’re at it, double-check that all outstanding invoices have been sent and paid, and set up invoice reminders to be sent out automatically either in late December or in early January — for example, with Boomerang for Gmail97.
8 Boomerang for Gmail97 allows you to send reminders automatically, or send emails later.
Throughout the year, we are bombarded with all kinds of notifications — Twitter mentions, Basecamp messages, Trello cards, GitHub updates. Do you really need them? Quite frankly, more often than not, they clutter search, making it more difficult to find things you’re looking for. Delete all notifications that have come in over the years:
While you’re at it, review your notification settings as well. Do you really need hourly notifications, or would daily notifications do just fine? It’s probably a good idea to reduce the frequency of notifications and then see whether you are missing anything — you can always adjust the frequency later.
Delete any other notifications you probably don’t need just by browsing your incoming messages by sender’s address to identify the usual and not-so-usual suspects. You could set up a separate email address just for notifications (for example, notifications@smashingmagazine.com) to prevent them from flooding your primary inbox, so that you can stay focused on emails from colleagues and coworkers.
Also, double check your privacy settings in the applications you are using the most. Review the ads settings, data collection settings and security settings and activities in Gmail10, Facebook11, Twitter12, LinkedIn13, Pinterest14 and Instagram. Double points if you have installed an ad blocker and Privacy Badger15 that blocks spying ads and invisible trackers.
Triple points if you also review authorized apps in Twitter, Facebook and Gmail. You’ve probably tried quite a few apps over the year once and never used them again; no need to grant them permission to access your accounts. Ah, quadruple your points if you look into the front-end performance checklist 201716 as well at this point!
Everybody loves a good ol’ email newsletter. We here are guilty of this as much as any other (albeit lovely) company, and indeed we send Smashing newsletters every now and again (sorry about that!). It might just be time to revisit all of your subscriptions. If you haven’t opened more than five newsletters from a single source, then you might not need them after all. Be brutal and unsubscribe from as many newsletters17 as you can. Depending on how thorough your cleaning preferences are, you might choose to either archive or delete messages received.
18 Services such as Unroll.Me19, help you clean up your inbox by unsubscribing from newsletters you don’t need with one single click.
Clean up your news alerts and notifications (New York Times, Quartz Daily).
Clean up all out-of-office replies and automatic replies (filter by “out-of-office” and “automatic reply”).
Clean up all event reminders (Meetup.com, Eventbrite, etc.) — just save tickets that you will need for invoicing later, though!
Clean up all form submissions (for example, Wufoo and Typeform). You can track conversations in email or download Excel spreadsheets later if needed.
Clean up all the drafts of messages that you started writing and never finished. If you haven’t sent them out yet, maybe you will never send them at all. Might be a good idea to check the contents of those drafts before deleting them, though — keep the good ideas and delete the unnecessary stuff!
Archive customer support tickets and discussions, as well as emails that are older than a certain threshold. An email that is about three years old might be important enough to look up one day but doesn’t need to be synced across all of your devices.
Clean up all newsletters that you’ve never managed to readand that you won’t be able to read this year. Chances are that if something is important and worth reading, it will bubble up in your conversations with colleagues or on Twitter or Facebook at some point anyway.
Clean up all marketing newsletters from companies you admire and don’t feel like unsubscribing from (MailChimp, Litmus, TED, type foundries, fashion brands etc.).
Delete spam messages and, you know, deleted messages — for good.
Again, just to keep all of these emails away from your primary inbox, it might be a good idea to set up a dedicated account for newsletters and form submissions. Also, set up a filter for all out-of-office replies and automatic replies.
Revisit The Email Signature And Text Shortcuts Link
Double-check that your email signature is up to date, especially your phone number, VAT number and postal address. Is including your mobile phone number in every email absolutely necessary? Maybe your office number would do just fine.
And if you need a bit of inspiration for a tasteful email signature, Kat Neville has got your back with “The Art and Science of the Email Signature20” — an article published seven years ago and still relevant today.
Also, if you’re using shortcuts and text abbreviations, possibly with a tool such as TextExpander, revisit your text snippets and write new ones, to save precious minutes next year.
Unless you’re an extraordinary, super-organized machine, all of your devices have complained to you throughout the year about the lack of space. Well, removing unnecessary email will help, but the main problem usually isn’t just email.
Among all of the apps installed on your phone, tablet, phablet, desktop, laptop, schlaptop, smart TV or anything in between, you are probably not using most of them. If you can’t even remember what an app does, chances are high that you don’t really need it on that device.
You probably have Dropbox21 and Basecamp22 and Trello23 installed on your mobile phone, but how often do you actually access them? Do you need to fully sync your personal folder — usually you’ll have your laptop nearby anyway, right? Delete all the apps you don’t use — maybe you’ve replaced some of the installed ones with the newer, better alternatives, or maybe you tend to use the services on desktop, and the mobile apps aren’t useful anyway?
While finding your way through your apps and looking through the ones you use a lot, revise your privacy and notification settings on mobile — many of them might be slowing you down and draining your battery because they are running in the background. Check what apps are actively updating, refreshing and collecting data about you behind your back in the “Background App Refresh” settings — deactivating them might be a good idea. Also, don’t forget to archive your chat messages and media files sent via WhatsApp and Viber. And — if you’d like to go all the way — delete your accounts on services you don’t use24.
Offload Images And Videos To An External Hard Drive Link
Everybody needs access to a memorable concert video or colorful pictures from a recent trip — I get it. However, when you need space, you need to be reassured that if you delete that great video, you will still be able to find it easily when needed. Having an overloaded phone and running out of space is that one thing that is probably the most annoying (at least to me!) during the year.
Offload all images from your phone and tablet to Dropbox, Google Drive, iCloud, and your laptop or desktop, or just get a dedicated external hard drive and store them there neatly. This goes for movies you haven’t watched yet and TV shows you’re saving for that long-haul intercontinental flight next year.
What happens if your phone drowns or your laptop decides to cease cooperating with you? Be ready in case something happens to your machine and you need it right away. Obviously, you have backed up your phone and your desktop, but what if something fails or you don’t have online access? (Yep, it’s happened to me29 — start watching the first video at 5:55:25).
Prepare a Restore Kit, a folder collecting all your important applications, settings and license codes. Take a close look at all of the applications you use regularly and write them down. You might end up with something like what follows.
Google Maps, WhatsApp, Skype, Foursquare, Instagram, Messenger, Twitter, Facebook, Google Translate, Shopify, Shazam, Spotify, Uber, Lyft, iA Writer, SpeedSmart, Google Authenticator, Opera Mini, Trello, Slack, Airbnb, Adblock, Revolut, banking application
Download the latest versions of these applications, extract the settings or config files from your existing apps, and store them all both locally and on a USB stick. Some services live online, so make sure to reference them (for example, in a plain-text file). Also, don’t forget to extract, encrypt and store the license codes for all of your locally installed applications:
Save encrypted passwords for your Google Chrome and Firefox accounts, so that you don’t need to sync bookmarks, popular search hits, your browsing history or extensions.
Save encrypted credentials to access your primary email account.
Save encrypted PIN and PUK codes for your mobile phone.
Take a screenshot of the arrangement of icons on your desktop, tablet and phone — including the deck and app icons on your phone. They will serve as a point of reference. Sync them via Dropbox — just in case mobile/desktop backup fails at some point in the future (yep, happened to me already as well).
If you put all of these files together in a separate Restore Kit folder, encrypted and stored both locally and on an external USB drive, you’ll be able to set up your working environment and get up and running completely from scratch within half an hour. Bonus points if you use Ninite30 (Windows), Get Mac Apps31, createOSXinstallPkg32 or Homebrew Cask33 (Mac) with a little shell script34 to bundle a handful of installable packages and run them at once one after another automatically. Better to feel safe than sorry!
35 Caskroom36 installs your apps to your /Applications folder in the same way as you would manually, but with just one click.
Just to make sure you don’t leave out something important in your to-do-list or in the “considered-to-be-spam” trench of your inbox, below is a quick checklist of a few things that could be helpful to revisit before diving into the new year:
Install updates you’ve been delaying for weeks.
Check Facebook’s hidden tab, “Message requests,” for people who aren’t your Facebook friends.
Check whether you’re overpaying for mobile, Internet or web services — prices tend to change all the time.
Learn one new keyboard shortcut a week, and define at least one custom text abbreviation a week.
Remove sharing buttons, links and any irrelevant content from the footer.
Review if you need all reserved and parked domains and check when they expire, to set up notifications and extend the license in time.
Write down important phone numbers of relatives, close friends and colleagues — on paper — and store them carefully.
Whenever a loved one mentions something they’d love to have, write it down and order it right away — you’ll find an occasion to give it to them later in the year.
38 A simple shell command39 helps you hide the icons on your desktop.
Clean up your desktop before the new year starts — when in doubt, just quickly hide all of the icons on your desktop.
Of course, in a perfect world, we would properly name all files and keep them in properly grouped and marked folders, and we would keep our inbox lean and clean. But more often than not, our data isn’t as neatly organized as we’d love it to be. Set up a cleaning reminder for late December 2017 (and December 2018), maybe even with a link to this article.
Phew! Here we go. Now, this list is quite comprehensive, and taking on the task of cleaning up your digital footprint might be the most tedious task you accomplish this entire year! So, if you had just one hour to get significant improvements, what would you do? Let’s boil it all down to 7 low-hanging fruits.
Think of and collect the receipts for the highest business expenses to send to your accountant early next year.
Double-check that all outstanding invoices have been sent and paid.
Revisit the frequency of notifications for services you use. Delete email notifications. The usual suspects are email, Twitter, Facebook, Trello and Slack.
Review your privacy settings, ads settings, data collection settings and security settings and review authorized apps in Twitter, Facebook, Gmail and others.
Create separate email accounts (and/or filters) for notifications and receipts.
Delete apps that you don’t need on your phone, tablet and desktop.
Revisit your ultimate restore or reboot kit: List essential apps, and collect and sync config and settings files, encrypted license files and the arrangement of icons on your screens. Whenever a loved one mentions something they’d love to have, write it down and order it right away.
Fantastic — you made it! Reward yourself for the last days of the year: uncork and share a bottle of champagne with your family or your friends who managed to get through the checklist just like you, and have a good clean start to 2017! 😉
Not good enough? Well, let us know what’s missing in the comments below!
When designing a landing page to promote a product or service online, you’re ultimately pointing users toward one goal. That goal most often relates to generating business via sales or leads. You may want users to purchase a product immediately, or you may simply want them to sign up for a mailing list. Whatever the goal, you want to ensure that every piece of the user experience works toward fulfilling that goal.
If you don’t yet have goals in mind, start by defining goals. Are you seeking to generate a 10% increase in qualified leads? Are you looking to build sales by 20%? Establishing clear key performance indicators based on what will benefit your business will ultimately help you understand how to properly approach a landing page.
Every goal should tie to a clear business outcome. For example, let’s say you run a software-as-a-service company and have determined that 100 new customers would provide the income you need to meet your revenue goals for the year. If you’ve established proper analytics and are carefully tracking results from your website, you might know that 10% of people who sign up for your mailing list are likely to become paying customers. So, you establish a goal of getting 1,000 new email registrations, which would likely result in your end goal of 100 new customers.
For more on establishing realistic goals and correlating those to online goals, see Avinash Kaushik’s article “Web Analytics 101: Definitions: Goals, Metrics, KPIs, Dimensions, Targets1.” Start with a foundation of being able to track the right data, and build from there to establish metrics you can seek to improve.
Ultimately, the best way to convert a user on a mobile landing page is to provide a clear description of what you’re offering, along with obvious ways to contact you. Be clear in describing what your product does and how you’re solving your target customer’s problems. For instance, “Best vacuum ever” says less than “Breathe more easily with a vacuum that removes 99% of allergens.” Clear contact options include simple, prominent forms and visible phone numbers, so that visitors don’t have to struggle to find out how to reach you.
Get to the point of what you’re selling and show the user how to buy it or contact you. Lack of any distractions, whether from a content or technical standpoint, will help to ensure the page supports your goal of converting users.
Sadly, too often businesses design landing pages without clearly thinking through every context in which users will be viewing the page, including what devices they’ll be on. Creating landing pages with mobile users in mind will help you to focus on how best to convert people on smartphones.
To create a landing page that follows the guidelines we’ll be talking about, you’ll need to pick the right tools to build and host it. If you have the right coding expertise, of course, you could build a page from scratch. However, a number of platforms exist to streamline the creation of landing pages. While the primary purpose of this article is to help you plan the elements and structure of a landing page, here are some brief suggestions of tools to build one.
First, if you already have a hosting service, then WordPress offers an excellent starting point for building a responsive landing page that easily integrates with plugins for forms and other elements. You will find a number of pre-built templates on websites such as ThemeForest2.
Next, several other tools allow you to create and host pages on their platforms. Unbounce3 and Wishpond4 are two popular platforms that enable you not only to build pages but also to implement A/B testing, which we’ll discuss in the last section. Neil Patel has a detailed overview5 of various platforms for landing pages.
A quick Google search will give you thousands of articles recommending various optimal lengths for landing page content. One source says to include at least 500 words6, while another recommends up to 1,000 words7. In reality, the ideal length will depend on what you’re selling and who your audience is, and you can test to determine the length that converts best. However, once the content has been condensed into a mobile format, you’ll need to especially consider how much your users will be willing to read and how far they’ll scroll before you lose the opportunity for a conversion. You can test pages with more or less content (for instance, testing a 500-word page against a 1,000-word page) with an A/B testing tool (discussed in more detail later), monitoring conversion rates to determine whether users are more likely to contact you with more or fewer words to read through.
To identify what content lengths are ideal for your users, you can test to see how long, on average, they’re scrolling through the content. In addition to scrolling, you should factor in how likely people are to engage with content by watching videos, clicking links or filling out forms. Measuring this activity is possible using a heatmapping tool, which we’ll also talk about more in depth later in this article.
In addition, you may start with some assumptions, such as thinking that most mobile users stop at “the fold” of the bottom of their screen. However, several studies8 show that most website visitors will naturally scroll as long as the page provides a user-friendly interface for doing so. For instance, a Time article9 shares that 66% of activity on a page happens below the fold. With this in mind, still keep important content and elements visible as high as possible, but don’t shy away from providing more detail in the copy.
If you’re looking to generate leads for an air-conditioning repair business, people are more likely to want to get right to the point of calling or filling out a form. If someone’s air-conditioning unit is broken on a 90-degree day, they likely won’t want to read a 2,000-word writeup on the inner workings of an air conditioner. They’ll probably be turned off by having to scroll through lengthy text before reaching a section containing contact information. They’ll want to reach right out to someone who can come to fix their unit, and feel assured that the person they contact can arrive quickly to take care of the problem.
However, if you’re selling luxury gold watches for $5,000 each, you’ll likely be better off including a detailed explanation of what sets your watches apart. In this case, you’re targeting a niche wealthy audience who will want to read and visualize details about your products in order to make a purchasing decision. They’re not so likely to make a purchasing decision on a whim with limited information: They’ll want to see pictures showing all angles of the luxury watch, a video about how each watch is handcrafted from the finest-quality materials, and a writeup about a lifetime guarantee.
Whatever the content’s length, take care that individual paragraphs don’t become excessively long when viewed on a mobile device. While a paragraph may stretch to only four lines of text on a desktop screen, the same paragraph might take up ten lines when compressed to a mobile screen size. More frequent paragraphs break will improve legibility.
Whether promoted via paid search or a social media campaign, a landing page should keep a focus on converting users into sales or leads. In the midst of ensuring brand integrity and writing copy to present a product or service, don’t let this main goal fall by the wayside. Especially in the limited amount of space available on a mobile device, you’ll have a brief window in which to grab the user’s attention and, ultimately, to get them to convert.
For a service-related business looking to generate leads, like the air-conditioning repair example, you should feature a phone number prominently across all devices. When users are looking to fix a problem right away, especially when browsing on a phone, they often prefer to place a call for service. Make sure to include click-to-call functionality10 on the mobile version of the page.
For instance, look at the landing page above used for paid search. In a desktop format, the only conversion option is a quote form. However, once the page shrinks to a mobile size, a phone icon appears in the upper-right corner, giving the option to click to call. This change provides a positive conversion focus for mobile, since users searching for insurance from a smartphone would likely want to speak with an agent.
In addition to a phone number, ensure that a form features prominently on mobile. Some responsive design templates that include a form might shrink to the point where the form no longer shows up at a mobile size. This will more than likely result in fewer leads.
Make sure the form’s fields are large enough to be tapped easily with a finger. While a form might work perfectly at a desktop size, the fields might shrink to the point where they’re difficult to select on a phone. For more on designing landing page forms that will aid the conversion process on mobile and not turn off users, see UserTesting’s article covering form usability resources13.
When creating a mobile landing page, a marketing mindset too often leads to one overlooking the user experience. In the process of introducing every possible piece of content or way of presenting a signup form, you could end up turning off users who might have otherwise taken time to read the page and converted. Before launching any campaign, review your landing page on multiple devices with multiple users to determine possible issues to fix. Below are a few examples of potential barriers.
Interstitial forms are a tempting option to “force” users to convert. However, they tend to create a higher number of annoyed users than converted users, especially on mobile. For instance, a Google study14 reveals that an interstitial ad promoting a Google+ app download resulted in 69% of users immediately leaving the page without engaging.
While an interstitial newsletter signup form might be easy to close on desktop, the same popup on a phone might shrink to the point that the “x” is painful to tap. Be careful especially of such conversion tactics that turn into a frustrating barrier for mobile users. Ironically, people can be turned away by the very elements intended to add an extra chance of conversion. For instance, according to a study cited in VentureBeat15, “viewers were 2X as likely to have a negative emotional response to a full page interstitial ad than to a rewarded, opt-in ad.” Also, note that Google recently began penalizing websites16 for some obtrusive interstitial formats.
In addition, think about how responsive design factors into the mobile experience. In theory, the idea of responsively stacking elements to fit a screen size works well. This setup could, however, result in a user having to scroll excessively to get to a form, if you don’t carefully plan out how elements will stack at a mobile size. A templated website might stack a form at the bottom, but you should readjust the layout to place the form higher on the page or include a clear “Contact” button that scrolls with the user’s activity and leads directly to the form when clicked.
19 In this example, the form jumps to the bottom of the page in the mobile version. (View large version20)
Also, think about how text will look when compressed to a mobile size. Will it be too small? Does the color allow for easy legibility? For instance, the white text for the page below looks fine over a dark background at a large size but blends with the light-blue background at a mobile size. However, on a positive note, see how the form fields go from four to one, making the process of completing the form simpler on mobile.
Additionally, don’t keep the user captive on the landing page. While you do want to focus on conversion and don’t necessarily need your website’s full navigation bar, you also don’t want to frustrate a user who’s looking for more information about your brand. Make your logo clickable back to your primary website, or provide footer links back to it.
To better identify what elements of the website are and aren’t working, test the experience of the website on mobile devices. Enlist people using different phone models across both Android and iOS, either finding people you know or using a website such as UserTesting23.
With the launch of a page, you can A/B test the placement of elements on the website using a tool such as Optimizely24 or Google Analytics’ free Content Experiments25. For instance, in the case of pricier products sold to a niche audience, you might want to test if these people will indeed respond to a form they see immediately or if they will need to read through content and view imagery before deciding to convert. For more ideas and tips, see Shopify’s “Beginner’s Guide to Simple A/B Testing26.”
In addition, install a heatmapping tool such as Crazy Egg27 or Hotjar28 to measure clicking and scrolling activity via a tracking script inserted in your website. This data will allow you to look more closely at how people are scrolling and what elements of the page they’re interacting with. In this way, you can determine how far into the content the average user is likely to read, as well as what buttons and form configurations are likely to produce a response.
Be sure to look at heatmaps specific to mobile. While desktop heatmaps might show no issues, mobile might show a different story. Of course, data will vary from website to website, but you might find that a larger percentage of your desktop users scroll through an entire page than mobile users (or vice versa). Or you might find that desktop users are more inclined to fill out a lengthier form, whereas mobile users fill out the first two fields and then drop out due to faulty functionality on mobile. In the example below, see how users scroll through more of the content on desktop than on mobile. Based on this data, the developer would be wise to take out some of the lengthy content on the mobile version of the page.
In addition, use Google Analytics to review mobile performance on your landing page. Segment by device when looking at the data to identify specific issues with mobile use. For instance, in the example shown below, we’ve selected a specific landing page under the “Behavior” → “Landing Pages” report, and used the “Secondary Dimension” dropdown menu to break out performance by device category. Here, we can see that mobile sessions resulted in a significantly lower conversion rate than desktop (0.65% versus 2.35%), indicating a potential flag of a poor user experience.
While page-loading speed is crucial for any website on any device, you should especially consider how quickly a page appears to load on mobile. One extra second of time spent waiting for an image to load could mean that an impatient mobile user gives up. In order to keep the user’s attention, make sure that resources load as quickly as possible in the user’s eyes.
One useful solution involves preloading resources on a landing page. You can use HTML5 prefetch35 to fetch some assets that will be used on a page that appears when the user clicks a call-to-action button on a landing page. In addition, you could also dynamically inject resource hints that tell the browser to download the required resources ahead of time. For more on this topic, see Denys Mishunov’s series on “Why Performance Matters36” (including part 237 and part 338) and CSS-Tricks’ article on prefetching39.
Here’s a recap of what to keep in mind when designing a landing page:
Define your goals to determine what to say on the page and what action you want users to take.
Describe your product or service as concisely as possible to grab the attention of users.
Break content into brief, readable paragraphs.
Exclude distracting elements, such as large navigation bars and excessive external links.
If appropriate, show imagery and/or video related to what you’re selling.
Place conversion elements such as forms and phone numbers in highly visible sections.
Test landing-page performance via analytics, heatmapping and A/B testing tools to determine changes to content length and page elements to include.
When building a landing page for any online campaign, take special care to consider the mobile experience. Review the presentation of content, as well as the prominence of contact information. Solicit the opinions of multiple users to identify issues, and test with analytics data to determine usability. With a clear plan in place for mobile, you’ll better convert users coming from multiple devices.
Welcome to the last reading list of the year. I’m happy to still have you as a reader and very grateful to all the people who value and support my work. I hope you’ll be on vacation for the upcoming days or can relax a bit from your daily work. Remind to take care of yourself, and see you next year!
Vitaly Friedman put together a great Front-End Performance Checklist 20174 for your next projects, with PDF and Apple Pages files so you can tick it off point by point.
We like to say “2016 was the worst”, and I don’t like this. Angus Hervey shares 99 good news stories that we probably didn’t hear about in 201616. Don’t let you be fooled by the all negative news and instead embrace the good things that happened as well. Despite some bad news, 2016 was quite a good year. Enjoy its last days!
Human interactions are incredibly fascinating if you take a close look at them — the social awkwardness, the communication styles, the way knowledge is transferred, the way stories are told and trust is built.
But what happens when a machine evokes the same response?
Conversational interfaces have become the new hotness in UX design. Google is about to release a new virtual assistant chatbot1; Facebook has already launched the updated Messenger platform with chatbots2; and Microsoft went as far as to claim that the operating system of the future isn’t Windows, but “conversation as a platform.”
What all of the big industry players have already figured out is that advances in artificial intelligence (AI) can solve a very important UX problem: making faceless branded websites and apps feel really personal.
3 Facebook Messenger presentation: booking a hotel room on the go (View large version4)
Chatbots can create a more genuine, custom-tailored experience, one that could be compared to the experience in a store — you get a smile from the salesperson, some chit chat and a friendly wink, which makes the whole buying experience more personal and pleasant. For brands, this represents an opportunity to extend and manage relationships with their customers and to go beyond being “just a product.”
However, building a genuinely helpful and attractive chatbot is still a challenge from a UX standpoint. Though we now have brilliant machine learning, which advances AI and natural-language processing (NLP) technologies, we are still somewhat limited in the type of helper we can create, and we need to force the most out of what we have. Matt Schlicht, founder of the Chatbots Magazine has created a very comprehensive guide5 summarizing the current state of the chatbot ecosystem and opportunities for designers.
Recently, I worked on the chatbot project for Alty6 — a Facebook messenger bot to chit chat with potential customers, introduce them to the company and services offered, and send out email inquiries.
The experience was relatively new and challenging. Unlike the standard graphical user interface (GUI), the app needed to work seamlessly with little user input, provide new value by leveraging stored information, and anticipate users needs. Standard patterns and flows don’t really work in conversational design, or else they need significant readjustment. Check Bot UI Kit9 for Messenger platform, courtesy of Mockuuups and Botframe10 – a simple prototyping tool for emulating conversations developed by Alsadir Monk11 to get a better idea of the common flows on this platform.
As already stated the first challenge you are likely to encounter is that you have little control over the application’s appearance. You don’t need to fuss over typography, layouts or styling too much. If you are building a voice-control chatbot, it won’t even have a visual side! Hence, ditch most of the standard tools and power up your toolkit with new useful ones.
For our project, we opted for the simplest tool — Chatfuel12, a free, intuitive bot builder for Facebook Manager with a drag-and-drop interface and hardly any coding required.
However, if you plan to build a more advanced bot, it’s worth looking into the following tools:
Twine13 This non-linear text editor creates text scripts and message sequences for your dialogs.
Wit14 This indispensable tool will help you convert voice and text commands into actions. Dozens of handy commands have been created by the community, and you can add custom ones.
Botkit15 Howdy’s Botkit offers a handy set of commands and ready-made code for you to build your first Slack chatbot.
Api.ai16 Recently acquired by Google, this robust and comprehensive platform will help you build any type of conversational UX interface.
Botwiki17 This wiki answers all of the common chatbot questions.
Few of the standard controls or styles we use in standard apps apply to conversational design.
Conversational design completely changes the way users interact with an app. Typically, when a user opens a new iOS app, they will see some familiar elements, such as a menu, a panel to log in or create an account, buttons and so on — the elements they already know how to interact with based on common schemas18.
However, the first encounter with a chatbot is less conventional. The user will be staring at a blank screen, lost in assumptions about what to do next or how to interact with the app. They face two simple problems:
“I have no idea what I’m supposed to do.”
“What exactly can this thing do for me?”
Chatbots don’t seem intuitive for most users yet. Hence, your first task is to prompt the user on what’s about to happen next. Start with a quick introduction and a straightforward call to action, something like:
Keep it short and simple. Invite users to experience one quick benefit of your app and to enjoy the result immediately.
In the case of Alty’s bot, we opted to include buttons within the conversation for a few key reasons:
Typing on the go could be cumbersome for some users, and chatbots are not always smart enough to detect typos (although we’ll talk about dealing with that later on).
Buttons can hint to users about what kind of questions the bot can answer and what actions it can perform.
You want your robot to seem like a wizard, rather than an obstacle, right?
One of the most challenging parts about designing a chatbot is to make the conversation flow as naturally and efficiently as possible. However, human interaction is typically messy and non-linear. Here are some tips for optimizing the app’s performance.
Teach Your Bot To Distinguish Between Different Types of Questions Link
Create the initial scope of questions that your bot will be capable of processing and answering efficiently. You can use a great library named qTypes21, which has over 40 sub-classifications for how questions should be answered. qType indicates the type of reply the user expects, and qSubType indicates the question’s format:
CH
With alternative choice question, the bot is asked to pick between two alternatives (for example, “Is this shirt red or green?”).
WH
These are questions starting with who, what, when, where or why.
YN
These are yes or no questions (for example, “Do you have a dog?”).
TG
A tag question is not an actual question, but rather an option to keep the conversation flowing (for example, “This beach is lovely, isn’t it?”).
When your bot receives one of the standard questions, it can produce more accurate replies based on the data from the library:
A standard GUI allows you to refine inputted data easily when processing it. Is this email address valid? Is this username available? Is this phone number valid? You can easily restrict and refine inputted data before processing it.
Yet, in conversational design, things get a bit more complicated. The user is free to say or type whatever they’d like; hence, you need to be smart when constructing your questions and processing the answers.
Offer hints. Avoid open-ended questions whenever possible because they usually result into more confusion. Instead, prompt for the kind of answer you expect. For example:
What kind of case study would you like to see? We have ones for travel, social networking, design and personal finance apps.
Or you could present the information according to the format of the platform you are building on — for example, lists in the case of Facebook Messenger:
Also, confirm. If the answer is valid, repeat it to ensure that everything is correct, and then move on to the next question:
Got it. Travel apps. And what budget do you have in mind?
Or suggest what went wrong. If the inputted data isn’t valid, explain again what kind of answer you need. Ideally, distinguish between answers that you don’t understand and answers that are fine but that you can’t accept:
Don’t forget that users are talking to your app. They may use different words to describe the same thing — for example, “Thu,” “Thursday,” “tomorrow” or a word with a typo. You could either ask them to confirm their entry or focus on creating more advanced message sequences for your chatbot.
You can refine the inputted data by running it through Normalizer27, a library that converts UK and Canadian spelling to US English, explains common abbreviations and fixes over 4,000 misspelled words.
Wait for critical inputs. In some cases, you’ll need the user to input some essential information that you cannot proceed without. In standard GUIs, the problem is usually solved with a popup modal window that blocks access to everything until the user completes the task: “Did you validate your email address?,” with the window prompting “Yes” or “No.”
However, in conversational design, you should tackle this issue in a slightly different manner. This kind of a loop can get rather annoying with a robot, so make sure to explain the exact action you require and why you need it so critically. Prepare a few conversational snippets for this purpose to keep the chatbot from getting repetitive:
In general, think twice about whether certain information is critical in order to proceed. Whenever possible, make an educated guess, or ask for the same information again during a subsequent step.
Another option is to use buttons and pre-suggested texts that users can choose from both when asking questions and providing the replies. Buttons should improve the overall quality of user inputs, however, they may slightly reduce the engagement factor. So it’s best to use them only when you need to receive the essential data for proceeding.
As AI technology advances, it may become easier to train bots to make certain responses and to teach them to second-guess the user’s intention based on previous interactions stored in the database. Yet the majority of chatbots today don’t have fancy AI brains to respond to users; hence, for a better UX, you’ll need to tackle this job yourself.
The designer should think like a copywriter when developing a chatbot. The content and the dialog will define your product’s style. The best apps are usually those that feature a fun conversational manner of speech. Hence, focus on the following:
Follow the same user flow as you would if you were actually speaking to a person.
The bot shouldn’t sound too clever, using complicated grammar or language structures. Keep it simple and be concise.
Don’t use gender-specific pronouns, because you never know who’s on the other side of the conversation.
Prepare a set of slightly different canned replies to make the conversation more human-like.
Add help messages and suggestions for when the user feels lost.
Write witty replies for unsupported topics, so that the bot doesn’t look dumb.
Standard GUIs usually show all of the features available on the screen at once. The user can hover over icons, click buttons and access the menu to see what the app is capable of doing.
Interacting with a chatbot, however, can seem like the user is speaking into the void. Hence, hint at each next step, and gradually highlight unfamiliar features. Let’s explore what this means.
After receiving the initial command from the user, explain what’s about to happen next and what the robot will do to complete the task. Suggest the next possible steps and/or link to the FAQ page or user manual.
Unlock additional features after the first successful interaction. Disable “training mode,” and start suggesting additional features and more advanced tips. Base those features and tips on the user’s history and previously inputted data.
Prompt the user about new things to do. For instance, proactively suggest some other cool features of your robot:
Hey, you have a party coming up! Do you want me to order 5 large pizzas?
Conversational agility is one of the key strengths of Taco bot, for instance. The company used Wit.ai to power different conversation scenarios and even crack some jokes. The platform’s natural language processing technology, which is also now used to power Facebook’s M Virtual Assistant33, allows the bot to render different ordering styles. For instance, “Can I have a burrito?”, “Buritto, please”, and even hilariously respond to “I’m drunk” request, which triggers the “Ok. A cup of water added to your order” reply. Additionally, users can type a one-line comment like “sans cheese” and the bot will understand that the information refers to the previously ordered burrito.
However, if the chatbot initiates the conversation, make sure it gives relevant suggestions because you don’t want to appear like an obnoxious spammer, right?
Speech commands are becoming a thing with Siri and Google Now, yet developing such bots obviously takes human and material resources. Even the most powerful neural networks that are responsible for speech recognition are rather hard to train at the moment. The most common challenge is that, while small errors are simple enough to eliminate, the larger recurring ones can become even larger due to multiplication, as Andrew Gibiansky points out34.
For instance, if a user with an accent pronounces Apple as Eupple, the network might remember the command this way. Homophones are another major challenge for speech recognition; words like “flower” and “flour” sound identical, and understanding the right context might be hard.
Hence, if your aim is to build a simple chatbot, opting for speech commands might not be your best bet at the moment, unless you are ready to invest heavily in the architecture and advanced machine-learning technology stack.
While chatbots can be a great tool for creating more personalized customer experience, conversational design still have certain limitations. As Mariya Yao pointed out, there are clear cases when a conversation can help or hurt the UX35.
Before building a chatbot for your business, you should clearly define its purpose and the exact value it could bring to the user. Teach the bot to do one thing extremely good, such as delivering weather forecasts or introducing the company’s scope of service before experimenting further with more advanced features. That’s the key lesson we learned when developing the April bot based on user feedback.
Are you using progressive booting already? What about tree-shaking and code-splitting in React and Angular? Have you set up Brotli or Zopfli compression, OCSP stapling and HPACK compression? Also, how about resource hints, client hints and CSS containment — not to mention IPv6, HTTP/2 and service workers?
Back in the day, performance was often a mere afterthought. Often deferred till the very end of the project, it would boil down to minification, concatenation, asset optimization and potentially a few fine adjustments on the server’s config file. Looking back now, things seem to have changed quite significantly.
Performance isn’t just a technical concern: It matters, and when baking it into the workflow, design decisions have to be informed by their performance implications. Performance has to be measured, monitored and refined continually, and the growing complexity of the web poses new challenges that make it hard to keep track of metrics, because metrics will vary significantly depending on the device, browser, protocol, network type and latency (CDNs, ISPs, caches, proxies, firewalls, load balancers and servers all play a role in performance).
So, if we created an overview of all the things we have to keep in mind when improving performance — from the very start of the process until the final release of the website — what would that list look like? Below you’ll find a (hopefully unbiased and objective) front-end performance checklist for 2017 — an overview of the issues you might need to consider to ensure that your response times are fast and your website smooth.
Micro-optimizations are great for keeping a performance on track, but it’s critical to have clearly defined targets in mind — measurable goals that would influence any decisions made throughout the process. There are a couple of different models, and the ones discussed below are quite opinionated — just make sure to set your own priorities early on.
According to psychological research3, if you want users to feel that your website is faster than any other website, you need to be at least 20% faster. Full-page loading time isn’t as relevant as metrics such as start rendering time, the first meaningful paint4 (i.e. the time required for a page to display its primary content) and the time to interactive5 (the time at which a page — and primarily a single-page application — appears to be ready enough that a user can interact with it).
Measure start rendering (with WebPagetest1686) and first meaningful paint times (with Lighthouse1727) on a Moto G, a mid-range Samsung device and a good middle-of-the-road device like a Nexus 4, preferably in an open device lab8 — on regular 3G, 4G and Wi-Fi connections.
9 Lighthouse, a new performance auditing tool by Google.
Look at your analytics to see what your users are on. You can then mimic the 90th percentile’s experience for testing. Collect data, set up a spreadsheet10, shave off 20%, and set up your goals (i.e. performance budgets11) this way. Now you have something measurable to test against. If you’re keeping the budget in mind and trying to ship down just the minimal script to get a quick time-to-interactive value, then you’re on a reasonable path.
Share the checklist with your colleagues. Make sure that the checklist is familiar to every member of your team to avoid misunderstandings down the line. Every decision has performance implications, and the project would hugely benefit from front-end developers being actively involved when the concept, UX and visual design are decided on. Map design decisions against performance budget and the priorities defined in the checklist.
100-millisecond response time, 60 frames per second.
The RAIL performance model14 gives you healthy targets: Do your best to provide feedback in less than 100 milliseconds after initial input. To allow for <100 milliseconds response, the page must yield control back to main thread at latest after every <50 milliseconds. For high pressure points like animation, it’s best to do nothing else where you can and the absolute minimum where you can’t.
Also, each frame of animation should be completed in less than 16 milliseconds, thereby achieving 60 frames per second (1 second ÷ 60 = 16.6 milliseconds) — preferably under 10 milliseconds. Because the browser needs time to paint the new frame to the screen your code should finish executing before hitting the 16.6 milliseconds mark. Be optimistic15 and use the idle time wisely. Obviously, these targets apply to runtime performance, rather than loading performance.
First meaningful paint under 1.25 seconds, SpeedIndex under 1000.
Although it might be very difficult to achieve, your ultimate goal should be a start rendering time under 1 second and a SpeedIndex16 value under 1000 (on a fast connection). For the first meaningful paint, count on 1250 milliseconds at most. For mobile, a start rendering time under 3 seconds for 3G on a mobile device is acceptable17. Being slightly above that is fine, but push to get these values as low as possible.
Don’t pay much attention to what’s supposedly cool these days. Stick to your environment for building, be it Grunt, Gulp, Webpack, PostCSS or a combination of tools. As long as you are getting results fast and you have no issues maintaining your build process, you’re doing just fine.
Progressive enhancement.
Keeping progressive enhancement18 as the guiding principle of your front-end architecture and deployment is a safe bet. Design and build the core experience first, and then enhance the experience with advanced features for capable browsers, creating resilient19 experiences. If your website runs fast on a slow machine with a poor screen in a poor browser on a suboptimal network, then it will only run faster on a fast machine with a good browser on a decent network.
Angular, React, Ember and co.
Favor a framework that enables server-side rendering. Be sure to measure boot times in server- and client-rendered modes on mobile devices before settling on a framework (because changing that afterwards, due to performance issues, can be extremely hard). If you do use a JavaScript framework, make sure your choice is informed20 and well considered21. Different frameworks will have different effects on performance and will require different strategies of optimization, so you have to clearly understand all of the nuts and bolts of the framework you’ll be relying on. When building a web app, look into the PRPL pattern22 and application shell architecture23.
24 PRPL stands for Pushing critical resource, Rendering initial route, Pre-caching remaining routes and Lazy-loading remaining routes on demand.25 An application shell26 is the minimal HTML, CSS, and JavaScript powering a user interface.
AMP or Instant Articles?
Depending on the priorities and strategy of your organization, you might want to consider using Google’s AMP27 or Facebook’s Instant Articles28. You can achieve good performance without them, but AMP does provide a solid performance framework with a free content delivery network (CDN), while Instant Articles will boost your performance on Facebook. You could build progressive web AMPs29, too.
Choose your CDN wisely.
Depending on how much dynamic data you have, you might be able to “outsource” some part of the content to a static site generator30, pushing it to a CDN and serving a static version from it, thus avoiding database requests. You could even choose a static-hosting platform31 based on a CDN, enriching your pages with interactive components as enhancements (JAMStack32).
Notice that CDNs can serve (and offload) dynamic content as well? So, restricting your CDN to static assets is not necessary. Double-check whether your CDN performs content compression and conversion, smart HTTP/2 delivery, edge-side includes, which assemble static and dynamic parts of pages at the CDN’s edge (i.e. the server closest to the user), and other tasks.
It’s a good idea to know what you are dealing with first. Run an inventory of all of your assets (JavaScript, images, fonts, third-party scripts and “expensive” modules on the page, such as carousels, complex infographics and multimedia content), and break them down in groups.
Set up a spreadsheet. Define the basic core experience for legacy browsers (i.e. fully accessible core content), the enhanced experience for capable browsers (i.e. the enriched, full experience) and the extras (assets that aren’t absolutely required and can be lazy-loaded, such as web fonts, unnecessary styles, carousel scripts, video players, social media buttons, large images). We published an article on “Improving Smashing Magazine’s Performance33,” which describes this approach in detail.
Use the “cutting-the-mustard” technique.
Use the cutting-the-mustard technique34 to send the core experience to legacy browsers and an enhanced experience to modern browsers. Be strict in loading your assets: Load the core experience immediately, the enhancements on DomContentLoaded and the extras on the load event.
Note that the technique deduces device capability from browser version, which is no longer something we can do these days. For example, cheap Android phones in developing countries mostly run Chrome and will cut the mustard despite their limited memory and CPU capabilities. Beware that, while we don’t really have an alternative, use of the technique has become more limited recently.
Consider micro-optimization and progressive booting.
In some apps, you might need some time to initialize the app before you can render the page. Display skeleton screens35 instead of loading indicators. Look for modules and techniques to speed up the initial rendering time (for example, tree-shaking36 and code-splitting37), because most performance issues come from the initial parsing time to bootstrap the app. Also, use an ahead-of-time compiler38 to offload some of the client-side rendering39 to the server40 and, hence, output usable results quickly. Finally, consider using Optimize.js41 for faster initial loading by wrapping eagerly invoked functions (it might not be necessary42 any longer, though).
43 Progressive booting44 means using server-side rendering to get a quick first meaningful paint, but also include some minimal JavaScript to keep the time-to-interactive close to the first meaningful paint.
Client-side rendering or server-side rendering? In both scenarios, our goal should be to set up progressive booting45: Use server-side rendering to get a quick first meaningful paint, but also include some minimal JavaScript to keep the time-to-interactive close to the first meaningful paint. We can then, either on demand or as time allows, boot non-essential parts of the app. Unfortunately, as Paul Lewis noticed46, frameworks typically have no concept of priority that can be surfaced to developers, and hence progressive booting is difficult to implement with most libraries and frameworks. If you have the time and resources, use this strategy to ultimately boost performance.
Are HTTP cache headers set properly?
Double-check that expires, cache-control, max-age and other HTTP cache headers have been set properly. In general, resources should be cacheable either for a very short time (if they are likely to change) or indefinitely (if they are static) — you can just change their version in the URL when needed.
Limit third-party libraries, and load JavaScript asynchronously.
When the user requests a page, the browser fetches the HTML and constructs the DOM, then fetches the CSS and constructs the CSSOM, and then generates a rendering tree by matching the DOM and CSSOM. If any JavaScript needs to be resolved, the browser won’t start rendering the page until it’s resolved, thus delaying rendering. As developers, we have to explicitly tell the browser not to wait and to start rendering the page. The way to do this for scripts is with the defer and async attributes in HTML.
You can also use client hints63, which are now gaining browser support64. Not enough resources to bake in sophisticated markup for responsive images? Use the Responsive Image Breakpoints Generator6562 or a service such as Cloudinary66 to automate image optimization. Also, in many cases, using srcset and sizes alone will reap significant benefits. On Smashing Magazine, we use the postfix -opt for image names — for example, brotli-compression-opt.png; whenever an image contains that postfix, everybody on the team knows that it’s been optimized.
Take image optimization to the next level.
When you’re working on a landing page on which it’s critical that a particular image loads blazingly fast, make sure that JPEGs are progressive and compressed with mozJPEG67 (which improves the start rendering time by manipulating scan levels), Pingo68 for PNG, Lossy GIF69 for GIF and SVGOMG70 for SVG. Blur out unnecessary parts of the image (by applying a Gaussian blur filter to them) to reduce the file size, and eventually you might even start to remove colors or make a picture black and white to reduce the size further. For background images, exporting photos from Photoshop with 0 to 10% quality can be absolutely acceptable as well.
Chances are high that the web fonts you are serving include glyphs and extra features that aren’t being used. You can ask your type foundry to subset web fonts or subset them yourself75 if you are using open-source fonts (for example, by including only Latin with some special accent glyphs) to minimize their file sizes. WOFF2 support76 is great, and you can use WOFF and OTF as fallbacks for browsers that don’t support it. Also, choose one of the strategies from Zach Leatherman’s “Comprehensive Guide to Font-Loading Strategies8077,” and use a service worker cache to cache fonts persistently. Need a quick win? Pixel Ambacht has a quick tutorial and case study78 to get your fonts in order.
79 Zach Leatherman’s Comprehensive Guide to Font-Loading Strategies8077 provides a dozen of options for bettern web font delivery.
To ensure that browsers start rendering your page as quickly as possible, it’s become a common practice85 to collect all of the CSS required to start rendering the first visible portion of the page (known as “critical CSS” or “above-the-fold CSS”) and add it inline in the <head> of the page, thus reducing roundtrips. Due to the limited size of packages exchanged during the slow start phase, your budget for critical CSS is around 14 KB. If you go beyond that, the browser will need addition roundtrips to fetch more styles. CriticalCSS86 and Critical87 enable you to do just that. You might need to do it for every template you’re using. If possible, consider using the conditional inlining approach88 used by the Filament Group.
With HTTP/2, critical CSS could be stored in a separate CSS file and delivered via a server push without bloating the HTML. The catch is that server pushing isn’t supported consistently and has some caching issues (see slide 114 onwards of Hooman Beheshti’s presentation89). The effect could, in fact, be negative90 and bloat the network buffers, preventing genuine frames in the document from being delivered. Server pushing is much more effective on warm connections91 due to the TCP slow start. So, you might need to create a cache-aware HTTP/2 server push mechanism92. Keep in mind, though, that the new cache-digest specification93 will negate the need to manually build these “cache-aware” servers.
Use tree-shaking and code-splitting to reduce payloads.
Code-splitting100 is another Webpack feature that splits your code base into “chunks” that are loaded on demand. Once you define split points in your code, Webpack takes care of the dependencies and outputted files. It basically enables you to keep the initial download small and to request code on demand, when requested by the application.
Note that Rollup101 shows significantly better results than Browserify exports. While we’re at it, you might want to check out Rollupify102, which converts ECMAScript 2015 modules into one big CommonJS module — because small modules can have a surprisingly high performance cost103 depending on your choice of bundler and module system.
Improve rendering performance.
Isolate expensive components with CSS containment104 — for example, to limit the scope of the browser’s styles, of layout and paint work for off-canvas navigation, or of third-party widgets. Make sure that there is no lag when scrolling the page or when an element is animated, and that you’re consistently hitting 60 frames per second. If that’s not possible, then at least making the frames per second consistent is preferable to a mixed range of 60 to 15. Use CSS’ will-change105 to inform the browser of which elements and properties will change.
Use skeleton screens, and lazy-load all expensive components, such as fonts, JavaScript, carousels, videos and iframes. Use resource hints110 to save time on dns-prefetch111 (which performs a DNS lookup in the background), preconnect112 (which asks the browser to start the connection handshake (DNS, TCP, TLS) in the background), prefetch113 (which asks the browser to request a resource), prerender114 (which asks the browser to render the specified page in the background) and preload115 (which prefetches resources without executing them, among other things). Note that in practice, depending on browser support, you’ll prefer preconnect to dns-prefetch, and you’ll be cautious with using prefetch and prerender — the latter should only be used if you are very confident about where the user will go next (for example, in a purchasing funnel).
With Google moving towards a more secure web116 and eventual treatment of all HTTP pages in Chrome as being “not secure,” you’ll need to decide on whether to keep betting on HTTP/1.1 or set up an HTTP/2 environment117. HTTP/2 is supported very well118; it isn’t going anywhere; and, in most cases, you’re better off with it. The investment will be quite significant, but you’ll need to move to HTTP/2 sooner or later. On top of that, you can get a major performance boost119 with service workers and server push (at least long term).
120 Eventually, Google plans to label all HTTP pages as non-secure, and change the HTTP security indicator to the red triangle that Chrome uses for broken HTTPS. (Image source121)
The downsides are that you’ll have to migrate to HTTPS, and depending on how large your HTTP/1.1 user base is (that is, users on legacy operating systems or with legacy browsers), you’ll have to send different builds, which would require you to adapt a different build process122. Beware: Setting up both migration and a new build process might be tricky and time-consuming. For the rest of this article, I’ll assume that you’re either switching to or have already switched to HTTP/2.
Properly deploy HTTP/2.
Again, serving assets over HTTP/2123 requires a major overhaul of how you’ve been serving assets so far. You’ll need to find a fine balance between packaging modules and loading many small modules in parallel.
On the one hand, you might want to avoid concatenating assets altogether, instead breaking down your entire interface into many small modules, compressing them as a part of the build process, referencing them via the “scout” approach124 and loading them in parallel. A change in one file won’t require the entire style sheet or JavaScript to be redownloaded.
On the other hand, packaging still matters125 because there are issues with sending many small JavaScript files to the browser. First, compression will suffer. The compression of a large package will benefit from dictionary reuse, whereas small separate packages will not. There’s standard work to address that, but it’s far out for now. Secondly, browsers have not yet been optimized for such workflows. For example, Chrome will trigger inter-process communications126 (IPCs) linear to the number of resources, so including hundreds of resources will have browser runtime costs.
Still, you can try to load CSS progressively129128. Obviously, by doing so, you are actively penalizing HTTP/1.1 users, so you might need to generate and serve different builds to different browsers as part of your deployment process, which is where things get slightly more complicated. You could get away with HTTP/2 connection coalescing130, which allows you to use domain sharding while benefiting from HTTP/2, but achieving this in practice is difficult.
What to do? If you’re running over HTTP/2, sending around 10 packages seems like a decent compromise (and isn’t too bad for legacy browsers). Experiment and measure to find the right balance for your website.
Make sure the security on your server is bulletproof.
Different servers and CDNs are probably going to support HTTP/2 differently. Use Is TLS Fast Yet?139137 to check your options, or quickly look up how your servers are performing and which features you can expect to be supported.
138 Is TLS Fast Yet?139137 allows you to check your options for servers and CDNs when switching to HTTP/2.
Is Brotli or Zopfli compression in use?
Last year, Google introduced140Brotli141, a new open-source lossless data format, which is now widely supported142 in Chrome, Firefox and Opera. In practice, Brotli appears to be more effective143 than Gzip and Deflate. It might be slow to compress, depending on the settings, and slower compression will ultimately lead to higher compression rates. Still, it decompresses fast. Because the algorithm comes from Google, it’s not surprising that browsers will accept it only if the user is visiting a website over HTTPS — and yes, there are technical reasons for that as well. The catch is that Brotli doesn’t come preinstalled on most servers today, and it’s not easy to set up without self-compiling NGINX or Ubuntu. However, you can enable Brotli even on CDNs that don’t support it144 yet (with a service worker).
Alternatively, you could look into using Zopfli’s compression algorithm145, which encodes data to Deflate, Gzip and Zlib formats. Any regular Gzip-compressed resource would benefit from Zopfli’s improved Deflate encoding, because the files will be 3 to 8% smaller than Zlib’s maximum compression. The catch is that files will take around 80 times longer to compress. That’s why it’s a good idea to use Zopfli on resources that don’t change much, files that are designed to be compressed once and downloaded many times.
Is OCSP stapling enabled?
By enabling OCSP stapling on your server146, you can speed up your TLS handshakes. The Online Certificate Status Protocol (OCSP) was created as an alternative to the Certificate Revocation List (CRL) protocol. Both protocols are used to check whether an SSL certificate has been revoked. However, the OCSP protocol does not require the browser to spend time downloading and then searching a list for certificate information, hence reducing the time required for a handshake.
Have you adopted IPv6 yet?
Because we’re running out of space with IPv4147 and major mobile networks are adopting IPv6 rapidly (the US has reached148 a 50% IPv6 adoption threshold), it’s a good idea to update your DNS to IPv6149 to stay bulletproof for the future. Just make sure that dual-stack support is provided across the network — it allows IPv6 and IPv4 to run simultaneously alongside each other. After all, IPv6 is not backwards-compatible. Also, studies show150 that IPv6 made those websites 10 to 15% faster due to neighbor discovery (NDP) and route optimization.
Is HPACK compression in use?
If you’re using HTTP/2, double-check that your servers implement HPACK compression151 for HTTP response headers to reduce unnecessary overhead. Because HTTP/2 servers are relatively new, they may not fully support the specification, with HPACK being an example. H2spec152 is a great (if very technically detailed) tool to check that. HPACK works153.
Are service workers used for caching and network fallbacks?
No performance optimization over a network can be faster than a locally stored cache on user’s machine. If your website is running over HTTPS, use the “Pragmatist’s Guide to Service Workers157” to cache static assets in a service worker cache and store offline fallbacks (or even offline pages) and retrieve them from the user’s machine, rather than going to the network. Also, check Jake’s Offline Cookbook158 and the free Udacity course “Offline Web Applications159.” Browser support? It’s getting there160, and the fallback is the network anyway.
If you’ve recently migrated from HTTP to HTTPS, make sure to monitor both active and passive mixed-content warnings, with a tool such as Report-URI.io161. You can also use Mixed Content Scan162 to scan your HTTPS-enabled website for mixed content.
Is your development workflow in DevTools optimized?
Pick a debugging tool and click on every single button. Make sure you understand how to analyze rendering performance and console output, and how to debug JavaScript and edit CSS styles. Umar Hansa recently prepared a (huge) slidedeck163 and talk164 covering dozens of obscure tips and techniques to be aware of when debugging and testing in DevTools.
Have you tested in proxy browsers and legacy browsers? Testing in Chrome and Firefox is not enough. Look into how your website works in proxy browsers and legacy browsers. UC Browser and Opera Mini, for instance, have a significant market share in Asia165 (up to 35% in Asia). Measure average Internet speed166 in your countries of interest to avoid big surprises down the road. Test with network throttling, and emulate a high-DPI device. BrowserStack167 is fantastic, but test on real devices as well.
Is continuous monitoring set up?
Having a private instance of WebPagetest1686 is always beneficial for quick and unlimited tests. Set up continuous monitoring of performance budgets with automatic alerts. Set your own user-timing marks to measure and monitor business-specific metrics. Look into using SpeedCurve169 to monitor changes in performance over time, and/or New Relic170 to get insights that WebPagetest cannot provide. Also, look into SpeedTracker171, Lighthouse1727 and Calibre173.
This list is quite comprehensive, and completing all of the optimizations might take quite a while. So, if you had just 1 hour to get significant improvements, what would you do? Let’s boil it all down to 10 low-hanging fruits. Obviously, before you start and once you finish, measure results, including start rendering time and SpeedIndex on a 3G and cable connection.
Your goal is a start rendering time under 1 second on cable and under 3 seconds on 3G, and a SpeedIndex value under 1000. Optimize for start rendering time and time-to-interactive.
Prepare critical CSS for your main templates, and include it in the <head> of the page. (Your budget is 14 KB).
Defer and lazy-load as many scripts as possible, both your own and third-party scripts — especially social media buttons, video players and expensive JavaScript.
Add resource hints to speed up delivery with faster dns-lookup, preconnect, prefetch, preload and prerender.
Subset web fonts and load them asynchronously (or just switch to system fonts instead).
Optimize images, and consider using WebP for critical pages (such as landing pages).
Check that HTTP cache headers and security headers are set properly.
Enable Brotli or Zopfli compression on the server. (If that’s not possible, don’t forget to enable Gzip compression.)
If HTTP/2 is available, enable HPACK compression and start monitoring mixed-content warnings. If you’re running over LTS, also enable OCSP stapling.
If possible, cache assets such as fonts, styles, JavaScript and images — actually, as much as possible! — in a service worker cache.
With this checklist in mind, you should be prepared for any kind of front-end performance project. Feel free to download the print-ready PDF of the checklist as well as an editable Apple Pages document to customize the checklist for your needs:
Some of the optimizations might be beyond the scope of your work or budget or might just be overkill given the legacy code you have to deal with. That’s fine! Use this checklist as a general (and hopefully comprehensive) guide, and create your own list of issues that apply to your context. But most importantly, test and measure your own projects to identify issues before optimizing. Happy performance results in 2017, everyone!
Huge thanks to Anselm Hannemann, Patrick Hamann, Addy Osmani, Andy Davies, Tim Kadlec, Yoav Weiss, Rey Bango, Matthias Ott, Mariana Peralta, Jacob Groß, Tim Swalling, Bob Visser, Kev Adamson and Rodney Rehm for reviewing this article, as well as our fantastic community, which has shared techniques and lessons learned from its work in performance optimization for everybody to use. You are truly smashing! (al)