Conversion Rate vs. Click-Through Rate: What’s The Difference?

Note: This is a guest article written by Malaika Nicholas, the content marketing strategist at Ladder. Any and all opinions expressed in the post are Malaika’s.

What Is Click-Through Rate?

Click-through rate (CTR) is a metric, shown as a percentage, that measures how many people clicked your ad to visit a website or landing page.

Why Are Click-Through Rates Important?

For paid ads on Facebook, Google AdWords, and other advertising platforms, the click-through rate directly influences an ad’s Quality Score or Relevance Score.

difference between conversion rate and click through rate

Photo Credit: WordStream

However, note that high click-through rates aren’t always a positive sign. If your ad isn’t targeting the right keywords, or your ad copy, landing page, or offering isn’t helpful or relevant to a visitor, you may end up spending a lot of money on ads that don’t impact your bottom line. Therefore, spend time conducting keyword research to make sure every paid ad is relevant to your ideal customer or target audience.

How Do You Calculate Click-Through Rates?

To calculate the click-through rate on a paid ad, divide the total number of clicks on the ad by the total number of impressions (i.e. the total number of people who saw the ad).

Pro Tip: Don’t forget to multiply your result by 100 to save some extra time calculating the percentage.

Although a lot of marketers may talk about click-through rates in paid advertising, there are several ways to measure click-through rates on other channels.

Say, I want to know how many people visit my website after reading one of my blog posts. In this case, I’ll look at the click-through rate, which will tell me how many people clicked the link to my website from my blog post, out of the total number of visitors to the blog post.

People Who Click Website from Blog Post/Total Number of Blog Post Visitors x 100 = Conversion Rate

What Is Conversion Rate?

Conversion rate is a metric, shown as a percentage, that displays how many website or app visitors complete an action out of the total number of visitors.

Why Are Conversion Rates Important?

For many marketers and entrepreneurs, conversion rates are the most important metric to monitor frequently, because it directly impacts their business’ overall sales and revenue.

Chris Keller from Bizible reinforces this idea and goes so far as to outline 3 reasons why website conversions are more important than web traffic. For one, Keller argues that more traffic doesn’t necessarily mean you’ll see a spike in sales. This can be the result of several issues: attracting the wrong kind of traffic by targeting wrong keywords, your website content isn’t related to the product or service you’re selling, or your lead capture forms are broken, just to name a few.

Secondly, Keller argues that it is significantly easier and takes less time to increase web conversions than it is to increase web traffic.

Finally, Keller’s last point is that prioritizing optimizing your conversion rate, and then optimizing web traffic—instead of the other way around—would have a greater impact on your business’ ROI and profitability.

difference between conversion rate and click through rate

Photo Credit: Bizible

How Do You Calculate Conversion Rates?

To calculate the Conversion Rate, you’ll divide the total number of visitors to your website or landing page by the number of completed goals.

Pro Tip: You can multiply this result by 100 to save some extra time calculating the percentage.  

It is important to note, however, that this formula will change slightly depending on the type of conversions you’re measuring.

For example, if you’re measuring the Conversion Rate of people visiting your website who turn into leads, the formula will be:

  • Total Number of Leads Collected/Total Traffic to Site x 100 = Conversion Rate

Similarly, if I want to calculate how many website visitors convert into paying customers, the conversion rate formula will look like this:

  • Number of Sales / Total Traffic to Site  x 100 = Conversion Rate

Finally, if I want to measure how many people subscribed to my newsletter after clicking my ad, the conversion rate formula will change to this:

Number of People Who Subscribe To My Newsletter/Total Number of People Who Clicked My Ad x 100 = Conversion Rate

Analytics Tools for Tracking Conversion Rates and Click-Through Rates

While there are several analytics tracking tools that can provide data about Conversion Rates and Click-Through Rates, there’s one tool that reigns supreme: Google Analytics.

Google Analytics is an incredibly versatile tool that allows you to understand who your audiences are, how they behave on your website, where they find out about your business (that is, traffic sources), and how they interact with your website content.

More specifically, Google Analytics allows you to set up Goals, which gives you the ability to track whenever a defined action is taken on your website (that is, the conversion rate), like submit a contact form or make a purchase.

Look at this short video from Google on how to use Goals within Google Analytics to track your conversion rates.

Link to video []

You can also use Google Analytics to track impressions and your ad Click-Through Rate from your Google AdWords campaigns. Here’s a short video that explains how it works.

Link to video []

In addition to Google Analytics, you can use any of the following to track Conversion Rates and/or Click-Through Rates.

Conversion Rate vs. Click-Through Rate: Which One Should You Measure?

Digital marketers use both the conversion rate and the click-through rate to measure the success of their marketing efforts. However, as Andrew Chu from MGX Copy notes, click-through rates and conversion rate affect two different stages of the marketing/sales funnel.

At the top of the sales funnel, the click-through rate measures how many people perform an action (such as click your ad) before they get to your website.

At the middle and bottom of the sales funnel, conversion rates measure actions that people take when they’re already on your website, like submit a form, sign up for a newsletter, download an infographic, make a purchase, and others.

As an example, let’s say I want to know how many people visited my website after seeing my Facebook ad. In this case, I would want to determine the click-through rate.

If my Facebook ad earned 100,000 impressions, and 3,500 of those people clicked my ad to visit my website, that makes my click-through rate 3.5%.

Not too bad!

Now, say I want to know that how many people became email newsletter subscribers from the ones who clicked my Facebook ad. In this case, I want to measure the conversion rate.

In this case, of the 3,500 people who clicked my Facebook ad and visited my website, 40 people subscribed to my email newsletter, making the conversion rate about 1.14%.

difference between conversion rate and click through rate

Photo Credit:

So, which metric are you supposed to measure—conversion rate or click-through rate?

The answer depends on which stage in the marketing/sales funnel you want to optimize.

If you want to improve your website rankings or increase traffic to the blog, then you’ll probably want to focus on measuring and optimizing your click-through rate.

If you want to focus on growing your email newsletter subscription list, increasing the number of people who sign up for a free trial, or increasing the number of products you sell online, then focus on measuring and optimizing your website conversion rates.

Actionable Growth Tactics for Improving Click-Through Rates

Here are a few quick tips that can help you improve your click-through rates:

  • First and foremost, conduct some consumer research on your target audience. This will give you a better understanding of what type of messaging your target audience is more likely to respond to.
  • Use Google Keyword Planner or another keyword research tool to find specific keywords your target audience is searching for. Include negative keywords and branded keywords as well in your research.
  • Write ad copy that is enticing and helps your brand stand out. Use power words that convey urgency, authority, performance, advanced technology, scarcity, or social proof.
  • Use high-quality, eye-catching photos in your ads; but make sure your images do not contain more than 20% of overlay text.
  • Make sure the copy, content, and design of your landing pages are aligned with your paid ads.
  • Have a clear and concise call-to-action that makes it clear to the viewer what they can expect after clicking your ad.

For more in-depth information about these tips, look at these helpful resources:

41 Ad Copy Approaches to Increase Ad Click Rates

Google AdWords Tips to Create Highly Converting Search Ads

Actionable Growth Tactics for Improving Conversion Rates

Conversion rate optimization is all about identifying, analyzing, testing, and improving various touchpoints at the middle and bottom levels of the marketing/sales funnel. Here are a few quick tips on how to optimize your conversion rates.

  • Personalize your messaging and user experiences, based on visitor behavior, preferences, or interests.
  • Don’t give up on website visitors who don’t convert right away. Keep them engaged with retargeting ads, where you can display services, products, or offers based on they’ve shown some interest in.
  • Offer customer support throughout the buying cycle. You can offer real-time chat with a customer support representative, provide Help Center informational tutorials and troubleshooting information, or answer questions visitors may have on a dedicated FAQ page.
  • Convert website visitors into potential leads by offering free materials in exchange for their contact information. For example, you can offer a technical white paper, an instructional e-Book, data-rich infographics, or exclusive video content.
  • Give website visitors several opportunities to convert. There’s a slim chance someone will visit your website for the first time and immediately decide to make a purchase. Instead, give hesitant visitors additional opportunities to convert (also known as “micro-conversions”), like giving them a chance to sign up for your email list through a smart bar, display a limited-time offer in an exit-intent pop-up, or allowing them to subscribe to a web browser and mobile push notifications for the latest updates.
  • A/B test various elements of your landing pages, including hero images, call-to-actions, taglines, descriptions, button positioning, the format of contact forms, and others.
  • Add social proof on popular landing pages. Experiment adding customer testimonials, recognizable brands you’ve worked with, or mobile app store reviews and ratings to your website and landing pages.

Also, make sure to bookmark these materials to help bolster your conversion rate optimization strategy:

How To Convert Your Website Visitors Into High-Quality Leads

10 Ways to Build an Actionable Content Marketing Strategy to Boost Conversion Rates

The post Conversion Rate vs. Click-Through Rate: What’s The Difference? appeared first on Blog.


Conversion Rate vs. Click-Through Rate: What’s The Difference?

Prototyping An App’s Design From Photoshop To Adobe XD

(This is a sponsored article.) Designing mobile apps means going through different stages: pre-planning, visual concepts, designing, prototyping, development. After defining your project, you need to test how it will work before you begin to develop it.

This stage is captured by prototyping. Prototyping allows designers to get a feel for the functionality and flow of an app, and to preview screens and interactions. Testing with prototypes provides valuable insights into user behavior and can be used to validate the interaction model. It is possible to represent the interactivity of an app before its development, and this gives developers a global vision of an app’s functioning, user behavior and steps to afford.

Prototyping is the simulation of the final result of an app’s development. Through this step, it’s possible to show a workflow of an app and consider problems and solutions. The two fundamental roles who will work in this phase are the user interface (UI) designer, who creates the look and feel, and the user experience (UX) designer, who creates the interaction structure between elements.

There are many ways to design and create an app’s look. As a loving user of Adobe products, I work most of the time in Illustrator and Photoshop. Illustrator helps me when I create and draw UI elements, which I can simply save and use later with Adobe XD. The process is the same as I’ve done for icons and that I showed you in my previous article “Designing for User Interfaces: Icons as Visual Elements for Screen Design.”

Photoshop comes in handy when I have to work with images in UI. But that’s not all: With the latest Adobe XD release, we can bring Photoshop design files into XD very quickly, and continue prototyping our app.

Today, I’ll offer a tutorial in which we discover how to transfer our app’s design from Photoshop to XD, continuing to work on it and having fun while prototyping. Please note that I’ve used images from in order to provide examples for this article.

We will cover the following steps:

  1. Simple hand sketch,
  2. Designing In Photoshop,
  3. Importing PSD files to XD,
  4. Developing a prototype,
  5. Tips.

For Adobe tools, I will use Photoshop CC, Illustrator CC and XD CC — all in the 2018 versions.

Let’s get started!

1. Simple Hand Sketch

Before we start designing our app, we need a plan for how to go about it. There are some questions we have to answer:

  • What is the app for?
  • What problem does it solve?
  • How easy is it to use?

Let’s assume we want to create an app for recipes. We want something simple: a space for pictures with ingredients and recipes.

I sketched by hand what I have in mind :

Then, I grabbed Photoshop and created my layouts.

2. Designing In Photoshop

Before we create layouts for our app, we can take advantage of a very useful resource by Adobe: free UI design resources. Because we will be designing an iOS app, I downloaded the iOS interface for Photoshop.

Feel free to experiment with the layouts you’ve downloaded.

In Photoshop, I created a new blank document from a preset for the iPhone 6 Plus:

Below is our layout, as I designed it in Photoshop. I tried to reproduce what I drew by hand earlier.

The PSD file contains four artboards. Each has its own layers.

Note: The images used in this prototype are from

Let’s see how to import this PSD file into Adobe XD.

3. Importing PSD Files To Adobe XD

Let’s run Adobe XD and click on “Open.” Select our PSD file, and click “Open.”

Ta-dah! In a few seconds, you’ll see all of your PSD elements open in XD.

More importantly, all of the elements you just imported will be organized exactly as they were in Photoshop. You can see your artboards on the left:

When you select an artboard, you will see its layers on the left — exactly the way it was in Photoshop before exporting.

Let’s do something in XD to improve our layout.

Go to Artboard 3. In this artboard, I want to add some more images. I just created three spaces in Photoshop to get an idea of what I want. Now, I can add more with some very simple steps.

First, delete the second and third image. From the first rectangle, delete the image, too, by double-clicking on it. You’ll have just one rectangle.

With this rectangle selected, go to “Repeat Grid” on the right and click it. Then, grab the handle and pull it downward. The grid will replicate your rectangle, inserting as many as you want. Create six rectangles, and adjust your artboard’s height by double-clicking on it and pulling its handle downwards.

Now, select all of the images you want to put in rectangles, and drag them all together onto the grid you just created:

Et voilà! All of your pictures are in place.

Now that all of the layouts are ready, let’s play with prototyping!

4. Developing A Prototype

Let’s begin the fun part!

We have to create interactions between our artboards and elements. Click on “Prototype” in the top left, as shown in the image below.

Click on the “Start here” button. When the little blue arrow appears, click and drag it to the second artboard. We are connecting these two artboards and creating interaction by clicking the intro button. Then, you can decide which kind of interaction to use (slide, fading, time, etc.).

See how I’ve set it in the image below:

Scrolling tip: Before viewing our prototype preview, we need to do another important thing. We have to make our artboards scrollable, giving them the same effect as when pushing a screen up and down with a finger on the phone.

Let’s go back a step and click on “Design” in the top left. Check which artboards are higher — in this case, the third and fourth. Select the third artboard from the left, and you’ll see the section “Scrolling” on the right. Set it to “Vertical.”

Then, you’ll see that your “Viewport Height” is set to a number, higher than the original artboard’s size. That’s normal, because we made it higher by adding some elements. But to make our artboard scrollable, we need to set that value to the original artboard’s size — in this case, 2208 pixels, the height of the iPhone 6 Plus, which we set in Photoshop and then imported to XD.

After setting that, you’ll see a dotted line where your artboard ends. That means it is now scrollable.

To see our first interactions in action, click on “Prototype” in the top left, and then click the little arrow in the top right. See them in action below:

Let’s finish up by connecting all of our artboards, as we’ve seen before, and check our final prototype. Don’t forget to connect them “back” to the previous artboard when clicking on the little arrow to go back:

And here is the final demo:

In this tutorial, you have learned:

  • that you can design your app in Photoshop,
  • how you can bring it into Adobe XD,
  • how to create a simple prototype.


  • Decide on one primary action per screen, and highlight its containing element through visual design (e.g. a big CTA).
  • White space is very important on small screens. It prevents confusion and gives the user more clickable space. And here comes that rule again: One primary action works well with more white space.
  • If you are not on a desktop, avoid all unnecessary elements.
  • Always test your prototypes with regular users. They will help you to understand whether the flow is easy to follow.

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

Smashing Editorial
(ra, al, il)

Source article:

Prototyping An App’s Design From Photoshop To Adobe XD

Lazy Loading JavaScript Modules With ConditionerJS

Linking JavaScript functionality to the DOM can be a repetitive and tedious task. You add a class to an element, find all the elements on the page, and attach the matching JavaScript functionality to the element. Conditioner is here to not only take this work of your hands but supercharge it as well!

In this article, we’ll look at the JavaScript initialization logic that is often used to link UI components to a webpage. Step-by-step we’ll improve this logic, and finally, we’ll make a 1 Kilobyte jump to replacing it with Conditioner. Then we’ll explore some practical examples and code snippets and see how Conditioner can help make our websites more flexible and user-oriented.

Conditioner And Progressive Enhancement Sitting In A Tree

Before we proceed, I need to get one thing across:

Conditioner is not a framework for building web apps.

Instead, it’s aimed at websites. The distinction between websites and web apps is useful for the continuation of this story. Let me explain how I view the overall difference between the two.

Websites are mostly created from a content viewpoint; they are there to present content to the user. The HTML is written to semantically describe the content. CSS is added to nicely present the content across multiple viewports. The last and third act is to carefully layer JavaScript on top to add that extra zing to the user experience. Think of a date picker, navigation, scroll animations, or carousels (pardon my French).

Examples of content-oriented websites are for instance: Wikipedia, Smashing Magazine, your local municipality website, newspapers, and webshops. Web apps are often found in the utility area, think of web-based email clients and online maps. While also presenting content, the focus of web apps is often more on interacting with content than presenting content. There’s a huge grey area between the two, but this contrast will help us decide when Conditioner might be effective and when we should steer clear.

As stated earlier, Conditioner is all about websites, and it’s specifically built to deal with that third act:

Enhancing the presentation layer with JavaScript functionality to offer an improved user experience.

The Troublesome Third Act

The third act is about enhancing the user experience with that zingy JavaScript layer.

Judging from experience and what I’ve seen online, JavaScript functionality is often added to websites like this:

  1. A class is added to an HTML element.
  2. The querySelectorAll method is used to get all elements assigned the class.
  3. A for-loop traverses the NodeList returned in step 2.
  4. A JavaScript function is called for each item in the list.

Let’s quickly put this workflow in code by adding autocomplete functionality to an input field. We’ll create a file called autocomplete.js and add it to the page using a <script> tag.

function createAutocomplete(element) 
  // our autocomplete logic
  // ...
<input type="text" class="autocomplete"/>

<script src="autocomplete.js"></script>

var inputs = document.querySelectorAll('.autocomplete');

for (var i = 0; i < inputs.length; i++) 


Go to demo →

That’s our starting point.

Suppose we’re now told to add another functionality to the page, say a date picker, it’s initialization will most likely follow the same pattern. Now we’ve got two for-loops. Add another functionality, and you’ve got three, and so on and so on. Not the best.

While this works and keeps you off the street, it creates a host of problems. We’ll have to add a loop to our initialization script for each functionality we add. For each loop we add, the initialization script gets linked ever tighter to the document structure of our website. Often the initialization script will be loaded on each page. Meaning all the querySelectorAll calls for all the different functionalities will be run on each and every page whether functionality is defined on the page or not.

For me, this setup never felt quite right. It always started out “okay,” but then it would slowly grow to a long list of repetitive for-loops. Depending on the project it might contain some conditional logic here and there to determine if something loads on a certain viewport or not.

if (window.innerWidth <= 480) 
  // small viewport for-loops here

Eventually, my initialization script would always grow out of control and turn into a giant pile of spaghetti code that I would not wish on anyone.

Something needed to be done.

Soul Searching

I am a huge proponent of carefully separating the three web dev layers HTML, CSS, and JavaScript. HTML shouldn’t have a rigid relationship with JavaScript, so no use of inline onclick attributes. The same goes for CSS, so no inline style attributes. Adding classes to HTML elements and then later searching for them in my beloved for-loops followed that philosophy nicely.

That stack of spaghetti loops though, I wanted to get rid them so badly.

I remember stumbling upon an article about using data attributes instead of classes, and how those could be used to link up JavaScript functionality (I’m not sure it was this article, but it seems to be from right timeframe). I didn’t like it, misunderstood it, and my initial thought was that this was just covering up for onclick, this mixed HTML and JavaScript, no way I was going to be lured to the dark side, I don’t want anything to do with it. Close tab.

Some weeks later I would return to this and found that linking JavaScript functionality using data attributes was still in line with having separate layers for HTML and JavaScript. As it turned out, the author of the article handed me a solution to my ever-growing initialization problem.

We’ll quickly update our script to use data attributes instead of classes.

<input type="text" data-module="autocomplete">

<script src="autocomplete.js"></script>

var inputs = document.querySelectorAll('[data-module=autocomplete]');

for (var i = 0; i < inputs.length; i++) 


Go to demo →


But hang on, this is nearly the same setup; we’ve only replaced .autocomplete with [data-module=autocomplete]. How’s that any better? It’s not, you’re right. If we add an additional functionality to the page, we still have to duplicate our for-loop — blast! Don’t be sad though as this is the stepping stone to our killer for-loop.

Watch what happens when we make a couple of adjustments.

<input type="text" data-module="createAutocomplete">

<script src="autocomplete.js"></script>

var elements = document.querySelectorAll('[data-module]');

for (var i = 0; i < elements.length; i++) 
    var name = elements[i].getAttribute('data-module');
    var factory = window[name];


Go to demo →

Now we can load any functionality with a single for-loop.

  1. Find all elements on the page with a data-module attribute;
  2. Loop over the node list;
  3. Get the name of the module from the data-module attribute;
  4. Store a reference to the JavaScript function in factory;
  5. Call the factory JavaScript function and pass the element.

Since we’ve now made the name of the module dynamic, we no longer have to add any additional initialization loops to our script. This is all we need to link any JavaScript functionality to an HTML element.

This basic setup has some other advantages as well:

  • The init script no longer needs to know what it loads; it just needs to be very good at this one little trick.
  • There’s now a convention for linking functionality to the DOM; this makes it very easy to tell which parts of the HTML will be enhanced with JavaScript.
  • The init script does not search for modules that are not there, i.e. no wasted DOM searches.
  • The init script is done. No more adjustments are needed. When we add functionality to the page, it will automatically be found and will simply work.


So What About This Thing Called Conditioner?

We finally have our single loop, our one loop to rule all other loops, our king of loops, our hyper-loop. Ehm. Okay. We’ll just have to conclude that our is a loop of high quality and is so flexible that it can be re-used in each project (there’s not really anything project specific about it). That does not immediately make it library-worthy, it’s still quite a basic loop. However, we’ll find that our loop will require some additional trickery to really cover all our use-cases.

Let’s explore.

With the one loop, we are now loading our functionality automatically.

  1. We assign a data-module attribute to an element.
  2. We add a <script> tag to the page referencing our functionality.
  3. The loop matches the right functionality to each element.
  4. Boom!

Let’s take a look at what we need to add to our loop to make it a bit more flexible and re-usable. Because as it is now, while amazing, we’re going to run into trouble.

  • It would be handy if we moved the global functions to isolated modules. This prevents pollution of the global scope. Makes our modules more portable to other projects. And we’ll no longer have to add our <script> tags manually. Fewer things to add to the page, fewer things to maintain.
  • When using our portable modules across multiple projects (and/or pages) we’ll probably encounter a situation where we need to pass configuration options to a module. Think API keys, labels, animation speeds. That’s a bit difficult at the moment as we can’t access the for-loop.
  • With the ever-growing diversity of devices out there we will eventually encounter a situation where we only want to load a module in a certain context. For instance, a menu that needs to be collapsed on small viewports. We don’t want to add if-statements to our loop. It’s beautiful as it is, we will not add if statements to our for-loop. Never.

That’s where Conditioner can help out. It encompasses all above functionality. On top of that, it exposes a plugin API so we can configure and expand Conditioner to exactly fit our project setup.

Let’s make that 1 Kilobyte jump and replace our initialization loop with Conditioner.

Switching To Conditioner

We can get the Conditioner library from the GitHub repository, npm or from unpkg. For the rest of the article, we’ll assume the Conditioner script file has been added to the page.

The fastest way is to add the unpkg version.

<script src=""></script>

With Conditioner added to the page lets take a moment of silence and say farewell to our killer for-loop.

Conditioners default behavior is exactly the same as our now departed for-loop. It’ll search for elements with the data-module attribute and link them to globally scoped JavaScript functions.

We can start this process by calling the conditioner hydrate method.

<input type="text" data-module="createAutocomplete"/>

<script src="autocomplete.js"></script>


Go to demo →

Note that we pass the documentElement to the hydrate method. This tells Conditioner to search the subtree of the <html> element for elements with the data-module attribute.

It basically does this:


Okay, great! We’re set to take it to the next level. Let’s try to replace our globally scoped JavaScript functions with modules. Modules are reusable pieces of JavaScript that expose certain functionality for use in your scripts.

Moving From Global Functions To Modules

In this article, our modules will follow the new ES Module standard, but the examples will also work with modules based on the Universal Module Definition or UMD.

Step one is turning the createAutocomplete function into a module. Let’s create a file called autocomplete.js. We’ll add a single function to this file and make it the default export.

export default function(element) 
  // autocomplete logic
  // ...

It’s the same as our original function, only prepended with export default.

For the other code snippets, we’ll switch from our classic function to arrow functions.

export default element => 
  // autocomplete logic
  // ...

We can now import our autocomplete.js module and use the exported function like this:

import('./autocomplete.js').then(module => 
  // the autocomplete function is located in module.default

Note that this only works in browsers that support Dynamic import(). At the time of this writing that would be Chrome 63 and Safari 11.

Okay, so we now know how to create and import modules, our next step is to tell Conditioner to do the same.

We update the data-module attribute to ./autocomplete.js so it matches our module file name and relative path.

Remember: The import() method requires a path relative to the current module. If we don’t prepend the autocomplete.js filename with ./ the browser won’t be able to find the module.

Conditioner is still busy searching for functions on the global scope. Let’s tell it to dynamically load ES Modules instead. We can do this by overriding the moduleImport action.

We also need to tell it where to find the constructor function (module.default) on the imported module. We can point Conditioner in the right direction by overriding the moduleGetConstructor action.

<input type="text" data-module="./autocomplete.js"/>

  // fetch module with dynamic import
  moduleImport: (name) => import(name),
  // get the module constructor
  moduleGetConstructor: (module) => module.default


Go to demo →


Conditioner will now automatically lazy load ./autocomplete.js, and once received, it will call the module.default function and pass the element as a parameter.

Defining our autocomplete as ./autocomplete.js is very verbose. It’s difficult to read, and when adding multiple modules on the page, it quickly becomes tedious to write and error prone.

This can be remedied by overriding the moduleSetName action. Conditioner views the data-module value as an alias and will only use the value returned by moduleSetName as the actual module name. Let’s automatically add the js extension and relative path prefix to make our lives a bit easier.

<input type="text" data-module="autocomplete"/>
  // converts module aliases to paths
  moduleSetName: (name) => `./$ name .js`

Go to demo →

Now we can set data-module to autocomplete instead of ./autocomplete.js, much better.

That’s it! We’re done! We’ve setup Conditioner to load ES Modules. Adding modules to a page is now as easy as creating a module file and adding a data-module attribute.

The plugin architecture makes Conditioner super flexible. Because of this flexibility, it can be modified for use with a wide range of module loaders and bundlers. There’s bootstrap projects available for Webpack, Browserify and RequireJS.

Please note that Conditioner does not handle module bundling. You’ll have to configure your bundler to find the right balance between serving a bundled file containing all modules or a separate file for each module. I usually cherry pick tiny modules and core UI modules (like navigation) and serve them in a bundled file while conditionally loading all scripts further down the page.

Alright, module loading — check! It’s now time to figure out how to pass configuration options to our modules. We can’t access our loop; also we don’t really want to, so we need to figure out how to pass parameters to the constructor functions of our modules.

Passing Configuration Options To Our Modules

I might have bent the truth a little bit. Conditioner has no out-of-the-box solution for passing options to modules. There I said it. To keep Conditioner as tiny as possible I decided to strip it and make it available through the plugin API. We’ll explore some other options of passing variables to modules and then use the plugin API to set up an automatic solution.

The easiest and at the same time most banal way to create options that our modules can access is to define options on the global window scope.

window.autocompleteSource = './api/query';
export default (element) => 
  // will log './api/query'
  // autocomplete logic
  // ...

Don’t do this.

It’s better to simply add additional data attributes.

<input type="text" 

These attributes can then be accessed inside our module by accessing the element dataset which returns a DOMStringMap of all data attributes.

export default (element) => 
  // will log './api/query'
  // autocomplete logic
  // ...

This could result in a bit of repetition as we’ll be accessing element.dataset in each module. If repetition is not your thing, read on, we’ll fix it right away.

We can automate this by extracting the dataset and injecting it as an options parameter when mounting the module. Let’s override the moduleSetConstructorArguments action.


  // the name of the module and the element it's being mounted to
  moduleSetConstructorArguments: (name, element) => ([

The moduleSetConstructorArguments action returns an array of parameters which will automatically be passed to the module constructor.

export default (element, options) => 
  // will log './api/query'
  // autocomplete logic
  // ...

We’ve only eliminated the dataset call, i.e. seven characters. Not the biggest improvement, but we’ve opened the door to take this a bit further.

Suppose we have multiple autocomplete modules on the page, and each and every single one of them requires the same API key. It would be handy if that API key was supplied automagically instead of having to add it as a data attribute on each element.

We can improve our developer lives by adding a page level configuration object.

const pageOptions = 
  // the module alias
    key: 'abc123' // api key


  // the name of the module and the element it's being mounted to
  moduleSetConstructorArguments: (name, element) => ([
    // merge the default page options with the options set on the element it self

Go to demo →

As our pageOptions variable has been defined with const it’ll be block-scoped, which means it won’t pollute the global scope. Nice.

Using Object.assign we merge an empty object with both the pageOptions for this module and the dataset DOMStringMap found on the element. This will result in an options object containing both the source property and the key property. Should one of the autocomplete elements on the page have a data-key attribute, it will override the pageOptions default key for that element.

const ourOptions = Object.assign(
   key: 'abc123' , 
   source: './api/query' 

// output:   key: 'abc123', source: './api/query' 

That’s some top-notch developer convenience right there.

By having added this tiny plugin, we can automatically pass options to our modules. This makes our modules more flexible and therefore re-usable over multiple projects. We can still choose to opt-out and use dataset or globally scope our configuration variables (no, don’t), whatever fits best.

Our next challenge is the conditional loading of modules. It’s actually the reason why Conditioner is named Conditioner. Welcome to the inner circle!

Conditionally Loading Modules Based On User Context

Back in 2005, desktop computers were all the rage, everyone had one, and everyone browsed the web with it. Screen resolutions ranged from big to bigger. And while users could scale down their browser windows, we looked the other way and basked in the glory of our beautiful fixed-width sites.

I’ve rendered an artist impression of the 2005 viewport:

A rectangular area illustrating a single viewport size of 1024 pixels by 768 pixels

The 2005 viewport in its full glory, 1024 pixels wide, and 768 pixels high. Wonderful.

Today, a little over ten years later, there’s more people browsing the web on mobile than on desktop, resulting in lots of different viewports.

I’ve applied this knowledge to our artist impression below.

Multiple overlapping rectangles illustrating a high amount of different viewport sizes

More viewports than you can shake a stick at.

Holy smokes! That’s a lot of viewports.

Today, someone might visit your site on a small mobile device connected to a crazy fast WiFi hotspot, while another user might access your site using a desktop computer on a slow tethered connection. Yes, I switched up the connection speeds — reality is unpredictable.

And to think we were worried about users resizing their browser window. Hah!

Note that those million viewports are not set in stone. A user might load a website in portrait orientation and then rotate the device, (or, resize the browser window), all without reloading the page. Our websites should be able to handle this and load or unload functionality accordingly.

Someone on a tiny device should not receive the same JavaScript package as someone on a desktop device. That seems hardly fair; it’ll most likely result in a sub-optimal user experience on both the tiny mobile device and the good ol’ desktop device.

With Conditioner in place, let’s configure it as a gatekeeper and have it load modules based on the current user context. The user context contains information about the environment in which the user is interacting with your functionality. Some examples of environment variables influencing context are viewport size, time of day, location, and battery level. The user can also supply you with context hints, for instance, a preference for reduced motion. How a user behaves on your platform will also tell you something about the context she might be in, is this a recurring visit, how long is the current user session?

The better we’re able to measure these environment variables the better we can enhance our interface to be appropriate for the context the user is in.

We’ll need an attribute to describe our modules context requirements so Conditioner can determine the right moment for the module to load and to unload. We’ll call this attribute data-context. It’s pretty straightforward.

Let’s leave our lovely autocomplete module behind and shift focus to a new module. Our new section-toggle module will be used to hide the main navigation behind a toggle button on small viewports.

Since it should be possible for our section-toggle to be unloaded, the default function returns another function. Conditioner will call this function when it unloads the module.

export default (element) => 
  // sectionToggle logic
  // ...

  return () => 
    // sectionToggle unload logic
    // ...

We don’t need the toggle behavior on big viewports as those have plenty of space for our menu (it’s a tiny menu). We only want to collapse our menu on viewports more narrow than 30em (this translates to 480px).

Let’s setup the HTML.

  <h1 data-module="sectionToggle" 
      data-context="@media (max-width:30em)">
    <li><a href="/home">home</a></li>
    <li><a href="/about">about</a></li>
    <li><a href="/contact">contact</a></li>

Go to demo →

The data-context attribute will trigger Conditioner to automatically load a context monitor observing the media query (max-width:30em). When the user context matches this media query, it will load the module; when it does not, or no longer does, it will unload the module.

Monitoring happens based on events. This means that after the page has loaded, should the user resize the viewport or rotate the device, the user context is re-evaluated and the module is loaded or unloaded based on the new observations.

You can view monitoring as feature detection. Where feature detection is about an on/off situation, the browser either supports WebGL, or it doesn’t. Context monitoring is a continuous process, the initial state is observed at page load, but monitoring continues after. While the user is navigating the page, the context is monitored, and observations can influence page state in real-time.

This nonstop monitoring is important as it allows us to adapt to context changes immediately (without page reload) and optimizes our JavaScript layer to fit each new user context like a glove.

The media query monitor is the only monitor that is available by default. Adding your own custom monitors is possible using the plugin API. Let’s add a visible monitor which we’ll use to determine if an element is visible to the user (scrolled into view). To do this, we’ll use the brand new IntersectionObserver API.

  // the monitor hook expects a configuration object
    // the name of our monitor with the '@'
    name: 'visible',

    // the create method will return our monitor API
    create: (context, element) => (

      // current match state
      matches: false,

      // called by conditioner to start listening for changes
      addListener (change) 

        new IntersectionObserver(entries => 

          // update the matches state
          this.matches = entries.pop().isIntersecting == context;

          // inform Conditioner of the state change



We now have a visible monitor at our disposal.

Let’s use this monitor to only load images when they are scrolled in to view.

Our base image HTML will be a link to the image. When JavaScript fails to load the links will still work, and the contents of the link will describe the image. This is progressive enhancement at work.

<a href="cat-nom.jpg" 
   A red cat eating a yellow bird

Go to demo →

The lazyImage module will extract the link text, create an image element, and set the link text to the alt text of the image.

export default (element) => 

  // store original link text
  const text = element.textContent;

  // replace element text with image
  const image = new Image();
  image.src = element.href;
  image.setAttribute('alt', text);
  element.replaceChild(image, element.firstChild);
  return () => 
    // restore original element state
    element.innerHTML = text

When the anchor is scrolled into view, the link text is replaced with an img tag.

Because we’ve returned an unload function the image will be removed when the element scrolls out of view. This is most likely not what we desire.

We can remedy this behavior by adding the was operator. It will tell Conditioner to retain the first matched state.

<a href="cat-nom.jpg" 
   data-context="was @visible">
   A red cat eating a yellow bird

There are three other operators at our disposal.

The not operator lets us invert a monitor result. Instead of writing @visible false we can write not @visible which makes for a more natural and relaxed reading experience.

Last but not least, we can use the or and and operators to string monitors together and form complex context requirements. Using and combined with or we can do lazy image loading on small viewports and load all images at once on big viewports.

<a href="cat-nom.jpg" 
   data-context="was @visible and @media (max-width:30em) or @media (min-width:30em)">
   A red cat eating a yellow bird

We’ve looked at the @media monitor and have added our custom @visible monitor. There are lots of other contexts to measure and custom monitors to build:

  • Tap into the Geolocation API and monitor the location of the user @location (near: 51.4, 5.4) to maybe load different scripts when a user is near a certain location.
  • Imagine a @time monitor, which would make it possible to enhance a page dynamically based on the time of day @time (after 20:00).
  • Use the Device Light API to determine the light level @lightlevel (max-lumen: 50) at the location of the user. Which, combined with the time, could be used to perfectly tune page colors.

By moving context monitoring outside of our modules, our modules have become even more portable. If we need to add collapsible sections to one of our pages, it’s now easy to re-use our section toggle module, because it’s not aware of the context in which it’s used. It just wants to be in charge of toggling something.

And this is what Conditioner makes possible, it extracts all distractions from the module and allows you to write a module focused on a single task.

Using Conditioner In JavaScript

Conditioner exposes a total of three methods. We’ve already encountered the hydrate and addPlugin methods. Let’s now have a look at the monitor method.

The monitor method lets us manually monitor a context and receive context updates.

const monitor = conditioner.monitor('@media (min-width:30em)');
monitor.onchange = (matches) => 
  // called when a change to the context was observed

This method makes it possible to do context monitoring from JavaScript without requiring the DOM starting point. This makes it easier to combine Conditioner with frameworks like React, Angular or Vue to help with context monitoring.

As a quick example, I’ve built a React <ContextRouter> component that uses Conditioner to monitor user context queries and switch between views. It’s heavily inspired by React Router so might look familiar.

    <Context query="@media (min-width:30em)" 
             component= FancyInfoGraphic />
        // fallback to use on smaller viewports

I hope someone out there is itching to convert this to Angular. As a cat and React person I just can’t get myself to do it.


Replacing our initialization script with the killer for loop created a single entity in charge of loading modules. From that change, automatically followed a set of requirements. We used Conditioner to fulfill these requirements and then wrote custom plugins to extend Conditioner where it didn’t fit our needs.

Not having access to our single for loop, steered us towards writing more re-usable and flexible modules. By switching to dynamic imports we could then lazy load these modules, and later load them conditionally by combining the lazy loading with context monitoring.

With conditional loading, we can quickly determine when to send which module over the connection, and by building advanced context monitors and queries, we can target more specific contexts for enhancement.

By combining all these tiny changes, we can speed up page load time and more closely match our functionality to each different context. This will result in improved user experience and as a bonus improve our developer experience as well.

Smashing Editorial
(rb, ra, hj, il)

Continue reading: 

Lazy Loading JavaScript Modules With ConditionerJS

Copyright Law Basics For UK Software Developers

Software developers all over the world can benefit from an increased understanding of intellectual property (IP) laws and how those laws may affect their work. Software programs are often complex works that include both functional and artistic elements and may be covered by a variety of different types of IP laws. This can be very confusing for those who haven’t been taught about IP and can cause them to miss out on opportunities to protect their own work or to accidentally infringe on the work of another.

The purpose of this article is to provide information about one type of IP law, copyright law, for software developers who live or work in the United Kingdom. Below we will discuss the definition of copyright law, the source of UK copyright law, and how it applies to technological works. I’ll also elaborate on what is not covered by copyright law, as well as the UK concepts of fair dealing and moral rights as they are related to copyright law.

Copyright Law Essentials

You can learn more about copyright law in general and about how it applies to software in my previous article. Go to article →

What Is Copyright Law?

Copyright law is a type of intellectual property law that protects creative works, which can include things like plays, movies, drawings, songs, and many other things. Around the world, copyright laws give the authors or creators of literary, dramatic, musical, or artistic works the right to control the ways in which their material may be used. With regard to software, copyright law generally covers the artistic elements of a software program as opposed to the functional elements.

What Is The Source Of Copyright Law In The UK?

Copyright law originated in the United Kingdom from a concept of common law; the Statute of Anne 1709. It became statutory with the passing of the Copyright Act 1911. The current act is the Copyright, Designs and Patents Act of 1988. Those interested can read the full text here.

The relevant government office for copyright inquiries is the UK Intellectual Property Office. The UK is also a signatory to the Berne Convention, an international agreement concerning copyright law that has been adopted by 172 countries worldwide.

How Does UK Copyright Law Apply Specifically To Technological Works?

Copyright law can apply to all kinds of technological works that are used with computers, tablets, smartphones, or video game systems. This includes apps, computer programs, databases, spreadsheets, screen displays, and even virtual reality environments. Copyright also applies to works that are used or distributed on the internet like websites, blogs, and other online content. In the UK, computer programs are specifically protected as literary works.

Throughout the European Union, the Computer Programs Directive provides guidance regarding the legal protection of computer programs. The Copyright (Computer Programs) Regulations of 1992 extended the rules covering literary works to include computer programs in other European countries as well.

What Is Not Covered By UK Copyright Law?

Copyright law in the UK, as elsewhere, does not protect ideas, procedures, methods of operations, or mathematical concepts (though other types of IP may protect them under certain circumstances). In other words, copyright law is about protecting a particular expression of an idea, not the idea itself, and not functional elements of a work. Additionally, names, titles, short phrases, and colors are not generally considered unique or substantial enough to be covered by copyright law. However, a work that combines some of the elements, such as a logo or design, could possibly be eligible for copyright (and perhaps trademark) protection.

How Long Does Copyright Protection In The UK Last?

Because the UK is a signatory to the Berne Convention which covered this issue, a copyright in the UK will typically be protected for either the life of the author plus 70 years from the death of the author or, for published works, for 70 years from the date of first publication. However, there are many exceptions to this rule, and each work should be treated on a case-by-case basis if there are any doubts.

One notable UK-specific exception has to do with the boy who never grew up, Peter Pan. Author J.M. Barrie gifted all of the rights to his creation to a children’s hospital in London. When the original copyright expired in 1987, an extension was added to the Copyright, Designs and Patents Act of 1988 mentioned above so that the hospital could continue to collect royalties based on uses of the work (though the hospital has no creative control over how the work is used). Ultimately, this is only an unusual — and perhaps endearingly British — exception to the normal copyright term.

Photo by Christian Battaglia on Unsplash. (Large preview)

What Is Fair Dealing?

The copyright laws of almost all countries allow exceptions for certain permitted uses of copyrighted works such as news reporting, educational uses, or where the use of the work is de minimus. In the United States, one can assert a “fair use” defense if accused of infringing a copyright if the use was due to one of these permitted activities. In the UK, these permitted activities fall under the legal concept known as “fair dealing.” According to the University of Nottingham, eligible activities which can be conducted without infringing a copyrighted work include:

  • Private and research study purposes;
  • Performance, copies or lending for educational purposes;
  • Criticism and news reporting;
  • Incidental inclusion;
  • Copies and lending by librarians;
  • Format shifting or back up of a work you own for personal use;
  • Caricature, parody or pastiche;
  • Acts for the purposes of royal commissions, statutory enquiries, judicial proceedings and parliamentary purposes;
  • Recording of broadcasts for the purposes of listening to or viewing at a more convenient time;
  • Producing a back-up copy for personal use of a computer program.

How Does “Fair Dealing” Affect Technology Copyrights In The UK?

The “fair dealing” exceptions mentioned above may specifically impact copyrights for technology-related works such as software programs or databases. For example, producing a backup copy of a software program for personal use only would not be considered copyright infringement under a fair dealing exception. Though fair dealing explicitly excludes decompilation or copying a software program during decompilation, the European Software Directive allows software licensees to use their copy of the software “to observe study or test the functioning of the program” in order to “determine the ideas and principles which underlie any element of the program.”

Therefore, users may freely observe a program as it operates to determine their functions and its underlying ideas, even if the goal is to create a competing program (see the UK case SAS Institute v. World Programming for more information on this concept). However, actual copying, for example in the case of source code copying, is not tolerated since this is explicitly protected by copyright.

For practical reasons, database copyrights would not be infringed if a person with the legal right to use part or all of a database performs steps necessary to use or access the contents of the database. Also, accessing a database for the purposes of private study or non-commercial research does not infringe copyright in a database.

Photo by on Unsplash. (Large preview)

Moral Rights In The UK

Another difference between the UK and other parts of the world with regard to copyright law is the UK’s emphasis on the importance of moral rights. Though this issue may not often arise in technology-related copyright disputes, moral rights are additional rights over and above the economic rights typically protected by copyright law.

In the UK, moral rights are: the right to attribution, or the right to be known or recognized as the author of a work; the right to object to derogatory treatment of a work, which includes any addition, deletion, or adaptation of a work that would distort or “mutilate” the work or injure the honor or reputation of the author; the right to object to false attribution, which basically means that you would not be named as the author of something you didn’t create; and the right to privacy of certain photographs and recordings, such as those commissioned for a private occasion.

One reason moral rights might be important for developers is that the moral right to attribution gives the developer the right to be named as the author of the software program, even though it is not common industry practice to do so. By the same token, if a developer doesn’t get their name associated with projects they didn’t work on, the right to object to false attribution protects them also. Find more information about moral rights here.

It is our hope that this information has been helpful for UK software designers and developers. Though this is only introductory information, and should not be substituted for legal counsel in the event of specific questions or disputes, education about copyright law issues and other IP issues helps to empower software designers and developers to make sure their works are fully protected.

Smashing Editorial
(da, ra, yk, il)

Read article here – 

Copyright Law Basics For UK Software Developers

How to blast through silo mentality to create a culture of experimentation

Creating and maintaining a culture of experimentation doesn’t happen in a straightforward, sequential manner. It’s an iterative process. For example,…Read blog postabout:How to blast through silo mentality to create a culture of experimentation

The post How to blast through silo mentality to create a culture of experimentation appeared first on WiderFunnel Conversion Optimization.

More here:

How to blast through silo mentality to create a culture of experimentation

Getting Started With The Web MIDI API

As the web continues to evolve and new browser technologies continue to emerge, the line between native and web development becomes more and more blurred. New APIs are unlocking the ability to code entirely new categories of software in the browser.

Until recently, the ability to interact with digital musical instruments has been limited to native, desktop applications. The Web MIDI API is here to change that.

In this article, we’ll cover the basics of MIDI and the Web MIDI API to see how simple it can be to create a web app that responds to musical input using JavaScript.

What Is MIDI?

MIDI has been around for a long time but has only recently made its debut in the browser. MIDI (Musical Instrument Digital Interface) is a technical standard that was first published in 1983 and created the means for digital instruments, synthesizers, computers, and various audio devices to communicate with each other. MIDI messages relay musical and time-based information back and forth between devices.

A typical MIDI setup might consist of a digital piano keyboard which can send messages relaying information such as pitch, velocity (how loudly or softly a note is played), vibrato, volume, panning, modulation, and more to a sound synthesizer which converts that into audible sound. The keyboard could also send its signals to desktop music scoring software or a digital audio workstation (DAW) which could then convert the signals into written notation, save them as a sound file, and more.

MIDI is a fairly versatile protocol, too. In addition to playing and recording music, it has become a standard protocol in stage and theater applications, as well, where it is often used to relay cue information or control lighting equipment.

A performer plays a digital piano onstage

MIDI lets digital instruments, synthesizers, and software talk to each other and is frequently used in live shows and theatrical productions. Photo by Puk Khantho on Unsplash.

MIDI In The Browser

The WebMIDI API brings all the utility of MIDI to the browser with some pretty simple JavaScript. We only need to learn about a few new methods and objects.


First, there’s the navigator.requestMIDIAccess() method. It does exactly what it sounds like—it will request access to any MIDI devices (inputs or outputs) connected to your computer. You can confirm the browser supports the API by checking for the existence of this method.

if (navigator.requestMIDIAccess) 
    console.log('This browser supports WebMIDI!');
    console.log('WebMIDI is not supported in this browser.');

Second, there’s the MIDIAccess object which contains references to all available inputs (such as piano keyboards) and outputs (such as synthesizers). The requestMIDIAccess() method returns a promise, so we need to establish success and failure callbacks. And if the browser is successful in connecting to your MIDI devices, it will return a MIDIAccess object as an argument to the success callback.

    .then(onMIDISuccess, onMIDIFailure);

function onMIDISuccess(midiAccess) 

    var inputs = midi.inputs;
    var outputs = midi.outputs;

function onMIDIFailure() 
    console.log('Could not access your MIDI devices.');

Third, MIDI messages are conveyed back and forth between inputs and outputs with a MIDIMessageEvent object. These messages contain information about the MIDI event such as pitch, velocity (how softly or loudly a note is played), timing, and more. We can start collecting these messages by adding simple callback functions (listeners) to our inputs and outputs.

Going Deeper

Let’s dig in. To send MIDI messages from our MIDI devices to the browser, we’ll start by adding an onmidimessage listener to each input. This callback will be triggered whenever a message is sent by the input device, such as the press of a key on the piano.

We can loop through our inputs and assign the listener like this:

function onMIDISuccess(midiAccess) 
    for (var input of midiAccess.inputs.values())
        input.onmidimessage = getMIDIMessage;

function getMIDIMessage(midiMessage) 

The MIDIMessageEvent object we get back contains a lot of information, but what we’re most interested in is the data array. This array typically contains three values (e.g. [144, 72, 64]). The first value tells us what type of command was sent, the second is the note value, and the third is velocity. The command type could be either “note on,” “note off,” controller (such as pitch bend or piano pedal), or some other kind of system exclusive (“sysex”) event unique to that device/manufacturer.

For the purposes of this article, we’ll just focus on properly identifying “note on” and “note off” messages. Here are the basics:

  • A command value of 144 signifies a “note on” event, and 128 typically signifies a “note off” event.
  • Note values are on a range from 0–127, lowest to highest. For example, the lowest note on an 88-key piano has a value of 21, and the highest note is 108. A “middle C” is 60.
  • Velocity values are also given on a range from 0–127 (softest to loudest). The softest possible “note on” velocity is 1.
  • A velocity of 0 is sometimes used in conjunction with a command value of 144 (which typically represents “note on”) to indicate a “note off” message, so it’s helpful to check if the given velocity is 0 as an alternate way of interpreting a “note off” message.

Given this knowledge, we can expand our getMIDIMessage handler example above by intelligently parsing our MIDI messages coming from our inputs and passing them along to additional handler functions.

function getMIDIMessage(message) 
    var command =[0];
    var note =[1];
    var velocity = ( > 2) ?[2] : 0; // a velocity value might not be included with a noteOff command

    switch (command) 
        case 144: // noteOn
            if (velocity > 0) 
                noteOn(note, velocity);
        case 128: // noteOff
        // we could easily expand this switch statement to cover other types of commands such as controllers or sysex

Browser Compatibility And Polyfill

As of the writing of this article, the Web MIDI API is only available natively in Chrome, Opera, and Android WebView.

Browser support for Web MIDI API from

The Web MIDI API is only available natively in Chrome, Opera, and Android WebView.

For all other browsers that don’t support it natively, Chris Wilson’s WebMIDIAPIShim library is a polyfill for the Web MIDI API, of which Chris is a co-author. Simply including the shim script on your page will enable everything we’ve covered so far.

<script src="WebMIDIAPI.min.js"></script>    
if (navigator.requestMIDIAccess)  //... returns true

This shim also requires’s Jazz-Plugin to work, unfortunately, which means it’s an OK option for developers who want the flexibility to work in multiple browsers, but an extra barrier to mainstream adoption. Hopefully, within time, other browsers will adopt the Web MIDI API natively.

Making Our Job Easier With WebMIDI.js

We’ve only really scratched the surface of what’s possible with the WebMIDI API. Adding support for additional functionality besides basic “note on” and “note off” messages starts to get much more complex.

If you’re looking for a great JavaScript library to radically simplify your code, check out WebMidi.js by Jean-Philippe Côté on Github. This library does a great job of abstracting all the parsing of MIDIAccess and MIDIMessageEvent objects and lets you listen for specific events and add or remove listeners in a much simpler way.

WebMidi.enable(function () 

    // Viewing available inputs and outputs

    // Retrieve an input by name, id or index
    var input = WebMidi.getInputByName("My Awesome Keyboard");
    // OR...
    // input = WebMidi.getInputById("1809568182");
    // input = WebMidi.inputs[0];

    // Listen for a 'note on' message on all channels
    input.addListener('noteon', 'all',
        function (e) 
            console.log("Received 'noteon' message (" + + e.note.octave + ").");

    // Listen to pitch bend message on channel 3
    input.addListener('pitchbend', 3,
        function (e) 
            console.log("Received 'pitchbend' message.", e);

    // Listen to control change message on all channels
    input.addListener('controlchange', "all",
        function (e) 
            console.log("Received 'controlchange' message.", e);

    // Remove all listeners for 'noteoff' on all channels

    // Remove all listeners on the input


Real-World Scenario: Building A Breakout Room Controlled By A Piano Keyboard

A few months ago, my wife and I decided to build a “breakout room” experience in our house to entertain our friends and family. We wanted the game to include some kind of special effect to help elevate the experience. Unfortunately, neither of us have mad engineering skills, so building complex locks or special effects with magnets, lasers, or electrical wiring was outside the realm of our expertise. I do, however, know my way around the browser pretty well. And we have a digital piano.

Thus, an idea was born. We decided that the centerpiece of the game would be a series of passcode locks on a computer that players would have to “unlock” by playing certain note sequences on our piano, a la Willy Wonka.

This is a musical lock
This is a musical lock

Sound cool? Here’s how I did it.


We’ll begin by requesting WebMIDI access, identifying our keyboard, attaching the appropriate event listeners, and creating a few variables and functions to help us step through the various stages of the game.

// Variable which tell us what step of the game we're on. 
// We'll use this later when we parse noteOn/Off messages
var currentStep = 0;

// Request MIDI access
if (navigator.requestMIDIAccess) 
    console.log('This browser supports WebMIDI!');

    navigator.requestMIDIAccess().then(onMIDISuccess, onMIDIFailure);

    console.log('WebMIDI is not supported in this browser.');

// Function to run when requestMIDIAccess is successful
function onMIDISuccess(midiAccess) 
    var inputs = midiAccess.inputs;
    var outputs = midiAccess.outputs;

    // Attach MIDI event "listeners" to each input
    for (var input of midiAccess.inputs.values()) 
        input.onmidimessage = getMIDIMessage;

// Function to run when requestMIDIAccess fails
function onMIDIFailure() 
    console.log('Error: Could not access MIDI devices.');

// Function to parse the MIDI messages we receive
// For this app, we're only concerned with the actual note value,
// but we can parse for other information, as well
function getMIDIMessage(message) 
    var command =[0];
    var note =[1];
    var velocity = ( > 2) ?[2] : 0; // a velocity value might not be included with a noteOff command

    switch (command) 
        case 144: // note on
            if (velocity > 0) 
        case 128: // note off
        // we could easily expand this switch statement to cover other types of commands such as controllers or sysex

// Function to handle noteOn messages (ie. key is pressed)
// Think of this like an 'onkeydown' event
function noteOn(note) 

// Function to handle noteOff messages (ie. key is released)
// Think of this like an 'onkeyup' event
function noteOff(note) 

// This function will trigger certain animations and advance gameplay 
// when certain criterion are identified by the noteOn/noteOff listeners
// For instance, a lock is unlocked, the timer expires, etc.
function runSequence(sequence) 

Step 1: Press Any Key To Begin

To kick off the game, let’s have the players press any key to begin. This is an easy first step which will clue them into how the game works and also start a countdown timer.

function noteOn(note) 
        // If the game hasn't started yet.
        // The first noteOn message we get will run the first sequence
        case 0: 
            // Run our start up sequence

            // Increment the currentStep so this is only triggered once

function runSequence(sequence) 
        case 'gamestart':            
            // Now we'll start a countdown timer...
            // code to trigger animations, give a clue for the first lock

Step 2: Play The Correct Note Sequence

For the first lock, the players must play a particular sequence of notes in the right order. I’ve actually seen this done in a real breakout room, only it was with an acoustic upright piano rigged to a lock box. Let’s re-create the effect with MIDI.

For every “note on” message received, we’ll append the numeric note value to an array and then check to see if that array matches a predefined array of note values.

We’ll assume some clues in the breakout room have told the players which notes to play. For this example, it will be the beginning of the tune to “Amazing Grace” in the key of F major. That note sequence would look like this.

A visual representation of the first nine notes of “Amazing Grace” on a piano

This is the correct sequence of notes that we’ll be listening for as the solution to the first lock.

The MIDI note values in array form would be: [60, 65, 69, 65, 69, 67, 65, 62, 60].

var correctNoteSequence = [60, 65, 69, 65, 69, 67, 65, 62, 60]; // Amazing Grace in F
var activeNoteSequence = [];

function noteOn(note) 
        // ... (case 0)

        // The first lock - playing a correct sequence
        case 1:

            // when the array is the same length as the correct sequence, compare the two
            if (activeNoteSequence.length == correctNoteSequence.length) 
                var match = true;
                for (var index = 0; index < activeNoteSequence.length; index++) 
                    if (activeNoteSequence[index] != correctNoteSequence[index]) 
                        match = false;

                if (match) 
                    // Run the next sequence and increment the current step
                    // Clear the array and start over
                    activeNoteSequence = [];

function runSequence(sequence) 
        // ...

        case 'lock1':
            // code to trigger animations and give clue for the next lock

Step 3: Play The Correct Chord

The next lock requires the players to play a combination of notes at the same time. This is where our “note off” listener comes in. For every “note on” message received, we’ll add that note value to an array; for every “note off” message received, we’ll remove that note value from the array. Therefore, this array will reflect which notes are currently being pressed at any time. Then, it’s a matter of checking that array every time a note value is added to see if it matches a master array with the correct values.

For this clue, we’ll make the correct answer a C7 chord in root position starting on middle C. That looks like this.

A visual representation of a C7 chord on a piano

These are the four notes that we’ll be listening for as the solution to the second lock.

The correct MIDI note values for this chord are: [60, 64, 67, 70].

var correctChord = [60, 64, 67, 70]; // C7 chord starting on middle C
var activeChord = [];

function noteOn(note) 
        // ... (case 0, 1)

        case 2:
            // add the note to the active chord array

            // If the array is the same length as the correct chord, compare
            if (activeChord.length == correctChord.length) 
                var match = true;
                for (var index = 0; index < activeChord.length; index++) 
                    if (correctChord.indexOf(activeChord[index]) < 0) 
                        match = false;

                if (match) 

function noteOff(note) 
        case 2:
            // Remove the note value from the active chord array
            activeChord.splice(activeChord.indexOf(note), 1);

function runSequence(sequence) 
        // ...

        case 'lock2':
            // code to trigger animations, stop clock, end game


Now all that’s left to do is to add some additional UI elements and animations and we have ourselves a working game!

Here’s a video of the entire gameplay sequence from start to finish. This is running in Google Chrome. Also shown is a virtual MIDI keyboard to help visualize which notes are currently being played. For a normal breakout room scenario, this can run in full-screen mode and with no other inputs in the room (such as a mouse or computer keyboard) to prevent users from closing the window.

WebMIDI Breakout Game Demo (watch in Youtube)

If you don’t have a physical MIDI device laying around and you still want to try it out, there are a number of virtual MIDI keyboard apps out there that will let you use your computer keyboard as a musical input, such as VMPK. Also, if you’d like to further dissect everything that’s going on here, check out the complete prototype on CodePen.

See the Pen WebMIDI Breakout Room Demo by Peter Anglea (@peteranglea) on CodePen.

Conclusion says that “Web MIDI has the potential to be one of the most disruptive music [technologies] in a long time, maybe as disruptive as MIDI was originally back in 1983.” That’s a tall order and some seriously high praise.

I hope this article and sample app has gotten you excited about the potential that this API has to spur the development of new and exciting kinds of browser-based music applications. In the coming years, hopefully, we’ll start to see more online music notation software, digital audio workstations, audio visualizers, instrument tutorials, and more.

If you want to read more about Web MIDI and its capabilities, I recommend the following:

And for further inspiration, here are some other examples of the Web MIDI API in action:

Smashing Editorial
(rb, ra, hj, il)

Read More:

Getting Started With The Web MIDI API

How to double your website conversion rate

Take a moment and think about a first meeting with a prospective customer. A good salesman will not try to sell right away. Instead, he will start by asking specific questions and subsequently use the answers provided to give valuable advice. Why does this work? Because in this way, trust is developed between both parties. This trust forms the necessary foundation for a sales transaction to take place further down the road. If a prospect visits your website, you’ll want to apply this principle of building trust in an online environment. Therefore, you typically provide useful content on your site such as articles, white…

The post How to double your website conversion rate appeared first on The Daily Egg.

See the original article here: 

How to double your website conversion rate

Monthly Web Development Update 3/2018: Service Workers, Building A CDN, And Cheating At Design

Service Worker is probably one of the most misrepresented technologies we currently have. When I hear people talking about it, the topic almost always revolves around serving an app when a user is offline. However, Service Worker can do so much more than that, and every week I come across new articles that show how powerful the technology really is.

This month, for example, we can learn how to use Service Worker for cross-tab messaging and to load off requests into the background with the Background Sync API. I think the toolset we now have in our browsers already allows us to build great experiences regardless of the network state. Now it’s up to us to make the experiences so great that users truly love them. And that’s probably the hardest part.


Sketch 49
Sketch 49 has arrived, and with it comes the new Prototyping in Sketch feature which lets you see the entire flow in action. (Image credit)


  • Ed Ellson examined Chrome’s Background Sync API and the retry strategy it uses to perform a request. By allowing synchronization in the background after a first attempt has failed, the API helps us improve the browsing experience for users who go offline or are on unstable connections.


Cheating At Design
Use color and weight to create visual hierarchy instead of size is only one of the seven practical tips for cheating at design that Adam Wathan and Steve Schoger share. (Image credit)


  • With GraphQL you can query exactly what you want whenever you want. This is amazing for working with an API but also has complex security implications. Instead of asking for legitimate, useful data, a malicious actor could submit an expensive, nested query to overload your server, database, network, or all of these. To prevent this from happening, Max Stoiber shows us how we can secure the GraphQL API in our projects.


  • WebKit is introducing the Storage Access API. The new API targets one of the major issues with Safari’s Intelligent Tracking Protection (ITP): Identifying users who are logged in to a first-party service but view content of it embedded on a third party (YouTube videos on a blog, for example). The Storage Access API allows third-party embeds to request access to their first-party cookies when the user interacts with them. A good solution to protect user privacy by default and allow exceptions on request.

Web Performance

  • Janos Pasztor built his own Content Delivery Network because he thinks it can be a better solution than using existing third parties. The code for the CDN of his personal website is now available on Github. A nice web performance article that looks at common solutions from a different angle.
  • A year after Facebook’s announcement to broadly use Cache-Control: Immutable, Paul Calvano examined how widespread its usage is on the web — apart from the few big players. Interesting research and it’s still sad to see that this useful performance tool is used so little. At Colloq, we use it quite a lot, which saves us a lot of traffic and load on our servers and enables us to serve a lot of pages nearly instantly to recurring users.
Global stats of a self-built CDN
Global stats for the custom CDN that Janos Pasztor built. (Image credit)





Accessibility Checklist
The Accessibility Checklist helps build accessibility into your process no matter your role or stage in a project. (Image credit)

Work & Life

  • This week I read an article by Alex Duloz, and his words still stick with me: “When we develop a new application, when we post content on the Internet, whatever we do that people will have access to, we should consider just for a minute if our contribution adds up to the level of dumbness kids/teenagers are exposed to. If it does, we should refrain from going live.” The truth is, most of us, including me, don’t consider this before posting on the Internet. We create funny things, share funny pictures and try to get fame with silly posts. But in reality, we shape society with this. Let’s try to provide more useful resources and make the consumption of this more enjoyable so young people can profit from our knowledge and not only view things we think are funny. “We should always consider how teenagers will use what we release.”
  • The MIT OpenCourseWare released a lot of free audio and video lectures. This is amazing news and makes great content available to broader masses.
  • Jake Knapp says great work requires idealism and cynicism and has strong arguments to back up this theory. An article worth reading.
  • There’s an important article on how unhappiness has grown in America’s population since around the year 2000. It reveals that while income inequality might play a role, the more important aspect is that young people who use a lot of digital media are unhappier than those who use it only up to an hour a day. Interestingly, people who don’t use digital media at all, are unhappy, too, so the outcome of this could be that we should try to use digital media only moderately — at least in our private lives. I bet it’ll make a big difference.
  • Following the theory of Michael Bradley, projects don’t necessarily need a roadmap for success. Instead, he suggests to create a moral compass that points out why the project exists and what its purpose is.

Going Beyond…

We hope you enjoyed this Web Development Update. The next one is scheduled for April 13th. Stay tuned.

Excerpt from – 

Monthly Web Development Update 3/2018: Service Workers, Building A CDN, And Cheating At Design

How to Improve Your Content Marketing Using Digital Analytics

How do you know your content marketing is effective? It’s not a rhetorical question, though it may seem like it. While it’s difficult to measure the success and return on investment of content purely quantitatively, you can absolutely use digital analytics to get some directional insights as well as insights that help you improve your approach. The good thing: there are no shortage of tools and guides to help you do that nowadays. The bad thing: it can be a bit overwhelming when you think about how to get started with digital analytics, especially if you’ve got a content calendar…

The post How to Improve Your Content Marketing Using Digital Analytics appeared first on The Daily Egg.

Original article: 

How to Improve Your Content Marketing Using Digital Analytics

How BBC Interactive Content Works Across AMP, Apps, And The Web

In the Visual Journalism team at the BBC, we produce exciting visual, engaging and interactive content, ranging from calculators to visualizations new storytelling formats.

Each application is a unique challenge to produce in its own right, but even more so when you consider that we have to deploy most projects in many different languages. Our content has to work not only on the BBC News and Sports websites but on their equivalent apps on iOS and Android, as well as on third-party sites which consume BBC content.

Now consider that there is an increasing array of new platforms such as AMP, Facebook Instant Articles, and Apple News. Each platform has its own limitations and proprietary publishing mechanism. Creating interactive content that works across all of these environments is a real challenge. I’m going to describe how we’ve approached the problem at the BBC.

Example: Canonical vs. AMP

This is all a bit theoretical until you see it in action, so let’s delve straight into an example.

Here is a BBC article containing Visual Journalism content:

Screenshot of BBC News page containing Visual Journalism content

Our Visual Journalism content begins with the Donald Trump illustration, and is inside an iframe

This is the canonical version of the article, i.e., the default version, which you’ll get if you navigate to the article from the homepage.

Now let’s look at the AMP version of the article:

Screenshot of BBC News AMP page containing same content as before, but content is clipped and has a Show More button

This looks like the same content as the normal article, but is pulling in a different iframe designed specifically for AMP

While the canonical and AMP versions look the same, they are actually two different endpoints with different behavior:

  • The canonical version scrolls you to your chosen country when you submit the form.
  • The AMP version doesn’t scroll you, as you cannot scroll the parent page from within an AMP iframe.
  • The AMP version shows a cropped iframe with a ‘Show More’ button, depending on viewport size and scroll position. This is a feature of AMP.

As well as the canonical and AMP versions of this article, this project was also shipped to the News App, which is yet another platform with its own intricacies and limitations. So how do we do support all of these platforms?

Tooling Is Key

We don’t build our content from scratch. We have a Yeoman-based scaffold which uses Node to generate a boilerplate project with a single command.

New projects come with Webpack, SASS, deployment and a componentization structure out of the box. Internationalization is also baked into our projects, using a Handlebars templating system. Tom Maslen writes about this in detail in his post, 13 tips for making responsive web design multi-lingual.

Out of the box, this works pretty well for compiling for one platform but we need to support multiple platforms. Let’s delve into some code.

Embed vs. Standalone

In Visual Journalism, we sometimes output our content inside an iframe so that it can be a self-contained “embed” in an article, unaffected by the global scripting and styling. An example of this is the Donald Trump interactive embedded in the canonical example earlier in this article.

On the other hand, sometimes we output our content as raw HTML. We only do this when we have control over the whole page or if we require really responsive scroll interaction. Let’s call these our “embed” and “standalone” outputs respectively.

Let’s imagine how we might build the “Will a robot take your job?” interactive in both the “embed” and “standalone” formats.

Two screenshots side by side. One shows content embedded in a page; the other shows the same content as a page in its own right.

Contrived example showing an ‘embed’ on the left, versus the content as a ‘standalone’ page on the right

Both versions of the content would share the vast majority of their code, but there would be some crucial differences in the implementation of the JavaScript between the two versions.

For example, look at the ‘Find out my automation risk’ button. When the user hits the submit button, they should be automatically scrolled to their results.

The “standalone” version of the code might look like this:

button.on('click', (e) => 
    window.scrollTo(0, resultsContainer.offsetTop);

But if you were building this as “embed” output, you know that your content is inside an iframe, so would need to code it differently:

// inside the iframe
button.on('click', () => 
    window.parent.postMessage( name: 'scroll', offset: resultsContainer.offsetTop , '*');

// inside the host page
window.addEventListener('message', (event) => 
    if ( === 'scroll') 
        window.scrollTo(0, iframe.offsetTop +;

Also, what if our application needs to go full screen? This is easy enough if you’re in a “standalone” page:

document.body.className += ' fullscreen';
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;

Screenshot of map embed with 'Tap to Interact' overlay, followed by a screenshot of the map in full screen mode after it has been tapped.

We successfully use full-screen functionality to make the most of our map module on mobile

If we tried to do this from inside an “embed,” this same code would have the content scaling to the width and height of the iframe, rather than the viewport:

Screenshot of map example as before, but full screen mode is buggy. Text from the surrounding article is visible where it shouldn't be.

It can be difficult going full screen from within an iframe

…so in addition to applying the full-screen styling inside the iframe, we have to send a message to the host page to apply styling to the iframe itself:

// iframe
window.parent.postMessage( name: 'window:toggleFullScreen' , '*');

// host page
window.addEventListener('message', function () 
    if ( === 'window:toggleFullScreen') 
       document.getElementById(iframeUid).className += ' fullscreen';

This can translate into a lot of spaghetti code when you start supporting multiple platforms:

button.on('click', (e) => 
    if (inStandalonePage()) 
        window.scrollTo(0, resultsContainer.offsetTop);
        window.parent.postMessage( name: 'scroll', offset: resultsContainer.offsetTop , '*');

Imagine doing an equivalent of this for every meaningful DOM interaction in your project. Once you’ve finished shuddering, make yourself a relaxing cup of tea, and read on.

Abstraction Is Key

Rather than forcing our developers to handle these conditionals inside their code, we built an abstraction layer between their content and the environment. We call this layer the ‘wrapper.’

Instead of querying the DOM or native browser events directly, we can now proxy our request through the wrapper module.

import wrapper from 'wrapper';
button.on('click', () => 

Each platform has its own wrapper implementation conforming to a common interface of wrapper methods. The wrapper wraps itself around our content and handles the complexity for us.

UML diagram showing that when our application calls the standalone wrapper scroll method, the wrapper calls the native scroll method in the host page.

Simple ‘scrollTo’ implementation by the standalone wrapper

The standalone wrapper’s implementation of the scrollTo function is very simple, passing our argument directly to window.scrollTo under the hood.

Now let’s look at a separate wrapper implementing the same functionality for the iframe:

UML diagram showing that when our application calls the embed wrapper scroll method, the embed wrapper combines the requested scroll position with the offset of the iframe before triggering the native scroll method in the host page.

Advanced ‘scrollTo’ implementation by the embed wrapper

The “embed” wrapper takes the same argument as in the “standalone” example but manipulates the value so that the iframe offset is taken into account. Without this addition, we would have scrolled our user somewhere completely unintended.

The Wrapper Pattern

Using wrappers results in code that is cleaner, more readable and consistent between projects. It also allows for micro-optimisations over time, as we make incremental improvements to the wrappers to make their methods more performant and accessible. Your project can, therefore, benefit from the experience of many developers.

So, what does a wrapper look like?

Wrapper Structure

Each wrapper essentially comprises three things: a Handlebars template, wrapper JS file, and a SASS file denoting wrapper-specific styling. Additionally, there are build tasks which hook into events exposed by the underlying scaffolding so that each wrapper is responsible for its own pre-compilation and cleanup.

This is a simplified view of the embed wrapper:


Our underlying scaffolding exposes your main project template as a Handlebars partial, which is consumed by the wrapper. For example, templates/wrapper.hbs might contain:

<div class="bbc-news-vj-wrapper--embed">

scss/wrapper.scss contains wrapper-specific styling that your application code shouldn’t need to define itself. The embed wrapper, for example, replicates a lot of BBC News styling inside the iframe.

Finally, js/wrapper.js contains the iframed implementation of the wrapper API, detailed below. It is shipped separately to the project, rather than compiled in with the application code — we flag wrapper as a global in our Webpack build process. This means that though we deliver our application to multiple platforms, we only compile the code once.

Wrapper API

The wrapper API abstracts a number of key browser interactions. Here are the most important ones:


Scrolls to the given position in the active window. The wrapper will normalise the provided integer before triggering the scroll so that the host page is scrolled to the correct position.

getScrollPosition: int

Returns the user’s current (normalized) scroll position. In the case of the iframe, this means that the scroll position passed to your application is actually negative until the iframe is at the top of the viewport. This is super useful and lets us do things such as animate a component only when it comes into view.


Provides a hook into the scroll event. In the standalone wrapper, this is essentially hooking into the native scroll event. In the embed wrapper, there will be a slight delay in receiving the scroll event since it is passed via postMessage.

viewport: height: int, width: int

A method to retrieve the viewport height and width (since this is implemented very differently when queried from within an iframe).


In standalone mode, we hide the BBC menu and footer from view and set a position: fixed on our content. In the News App, we do nothing at all — the content is already full screen. The complicated one is the iframe, which relies on applying styles both inside and outside the iframe, coordinated via postMessage.


Tell the wrapper your content has loaded. This is crucial for our content to work in the News App, which will not attempt to display our content to the user until we explicitly tell the app our content is ready. It also removes the loading spinner on the web versions of our content.

List Of Wrappers

In the future, we envisage creating additional wrappers for large platforms such as Facebook Instant Articles and Apple News. We have created six wrappers to date:

Standalone Wrapper

The version of our content that should go in standalone pages. Comes bundled with BBC branding.

Embed Wrapper

The iframed version of our content, which is safe to sit inside articles or to syndicate to non-BBC sites, since we retain control over the content.

AMP Wrapper

This is the endpoint which is pulled in as an amp-iframe into AMP pages.

News App Wrapper

Our content must make calls to a proprietary bbcvisualjournalism:// protocol.

Core Wrapper

Contains only the HTML — none of our project’s CSS or JavaScript.

JSON Wrapper

A JSON representation of our content, for sharing across BBC products.

Wiring Wrappers Up To The Platforms

For our content to appear on the BBC site, we provide journalists with a namespaced path:

/include/[department]/[unique ID], e.g. /include/visual-journalism/123-quiz

The journalist puts this “include path” into the CMS, which saves the article structure into the database. All products and services sit downstream of this publishing mechanism. Each platform is responsible for choosing the flavor of content it wants and requesting that content from a proxy server.

Let’s take that Donald Trump interactive from earlier. Here, the include path in the CMS is:


The canonical article page knows it wants the “embed” version of the content, so it appends /embed to the include path:


…before requesting it from the proxy server:

The AMP page, on the other hand, sees the include path and appends /amp:


The AMP renderer does a little magic to render some AMP HTML which references our content, pulling in the /amp version as an iframe:

<amp-iframe src="" width="640" height="360">
    <!-- some other AMP elements here -->

Every supported platform has its own version of the content:




...and so on

This solution can scale to incorporate more platform types as they arise.

Abstraction Is Hard

Building a “write once, deploy anywhere” architecture sounds quite idealistic, and it is. For the wrapper architecture to work, we have to be very strict on working within the abstraction. This means we have to fight the temptation to “do this hacky thing to make it work in [insert platform name here].” We want our content to be completely unaware of the environment it is shipped in — but this is easier said than done.

Features Of The Platform Are Hard To Configure Abstractly

Before our abstraction approach, we had complete control over every aspect of our output, including, for example, the markup of our iframe. If we needed to tweak anything on a per-project basis, such as add a title attribute to the iframe for accessibility reasons, we could just edit the markup.

Now that the wrapper markup exists in isolation from the project, the only way of configuring it would be to expose a hook in the scaffold itself. We can do this relatively easily for cross-platform features, but exposing hooks for specific platforms breaks the abstraction. We don’t really want to expose an ‘iframe title’ configuration option that’s only used by the one wrapper.

We could name the property more generically, e.g. title, and then use this value as the iframe title attribute. However, it starts to become difficult to keep track of what is used where, and we risk abstracting our configuration to the point of no longer understanding it. By and large, we try to keep our config as lean as possible, only setting properties that have global use.

Component Behaviour Can Be Complex

On the web, our sharetools module spits out social network share buttons that are individually clickable and open a pre-populated share message in a new window.

Screenshot of BBC sharetools section containg Twitter and Facebook social media icons.

BBC Visual Journalism sharetools present a list of social share options

In the News App, we don’t want to share through the mobile web. If the user has the relevant application installed (e.g. Twitter), we want to share in the app itself. Ideally, we want to present the user with the native iOS/Android share menu, then let them choose their share option before we open the app for them with a pre-populated share message. We can trigger the native share menu from the app by making a call to the proprietary bbcvisualjournalism:// protocol.

Screenshot of the share menu on Android with options for sharing via Messaging, Bluetooth, Copy to clipboard, and so on.

Native share menu on Android

However, this screen will be triggered whether you tap ‘Twitter’ or ‘Facebook’ in the ‘Share your results’ section, so the user ends up having to make their choice twice; the first time inside our content, and a second time on the native popup.

This is a strange user journey, so we want to remove the individual share icons from the News app and show a generic share button instead. We are able to do this by explicitly checking which wrapper is in use before we render the component.

Screenshot of the news app share button. This is a single button with the following text: 'Share how you did'.

Generic share button used in the News App

Building the wrapper abstraction layer works well for projects as a whole, but when your choice of wrapper affects changes at the component level, it’s very difficult to retain a clean abstraction. In this case, we’ve lost a little abstraction, and we have some messy forking logic in our code. Thankfully, these cases are few and far between.

How Do We Handle Missing Features?

Keeping abstraction is all well and good. Our code tells the wrapper what it wants the platform to do, e.g. “go full screen.” But what if the platform we’re shipping to can’t actually go full-screen?

The wrapper will try its best not to break altogether, but ultimately you need a design which gracefully falls back to a working solution whether or not the method succeeds. We have to design defensively.

Let’s say we have a results section containing some bar charts. We often like to keep the bar chart values at zero until the charts are scrolled into view, at which point we trigger the bars animating to their correct width.

Screenshot of a collection of bar charts comparing the user's area with the national averages. Each bar has its value displayed as text to the right of the bar.

Bar chart showing values relevant to my area

But if we have no mechanism to hook into the scroll position — as is the case in our AMP wrapper — then the bars would forever remain at zero, which is a thoroughly misleading experience.

Same screenshot of bar charts as before, but bars have 0&#37; width and the values of each bar are fixed at 0&#37;. This is incorrect.

How the bar chart could look if scrolling events aren’t forwarded

We are increasingly trying to adopt more of a progressive enhancement approach in our designs. For example, we could provide a button which will be visible for all platforms by default, but which gets hidden if the wrapper supports scrolling. That way, if the scroll fails to trigger the animation, the user can still trigger the animation manually.

Same screenshot of bar charts as the incorrect 0&#37; bar charts, but this time with a subtle grey overlay and a centered button inviting the user to 'View results'.

We could display a fallback button instead, which triggers the animation on click.

Plans For The Future

We hope to develop new wrappers for platforms such as Apple News and Facebook Instant Articles, as well as to offer all new platforms a ‘core’ version of our content out of the box.

We also hope to get better at progressive enhancement; succeeding in this field means developing defensively. You can never assume all platforms now and in the future will support a given interaction, but a well-designed project should be able to get its core message across without falling at the first technical hurdle.

Working within the confines of the wrapper is a bit of a paradigm shift, and feels like a bit of a halfway house in terms of the long-term solution. But until the industry matures onto a cross-platform standard, publishers will be forced to roll out their own solutions, or use tooling such as Distro for platform-to-platform conversion, or else ignore entire sections of their audience altogether.

It’s early days for us, but so far we’ve had great success in using the wrapper pattern to build our content once and deliver it to the myriad of platforms our audiences are now using.

Smashing Editorial
(rb, ra, il)

See the original post:  

How BBC Interactive Content Works Across AMP, Apps, And The Web

Just another WordPress site