Feb 18 2016
Flickering Content

12 Techniques to Mitigate Content Flashing During A/B Testing

If you’re experiencing flickering or flashing of unstyled content (FOUC) while conducting A/B testing on a website within a platform, read on. Users can be exposed to “flickers” of the original content before a test’s code executes changes, which could negatively impact your user experience or revenue goals.

The code you write for any test lives within a single JavaScript file or “snippet” and is included on every page tests are running on. As the page loads, the browser begins executing the code in the snippet. Factors such as how and where to include the snippet directly impact page performance and the possibility of FOUC, so careful consideration needs to be taken when implementing the snippet.

Variance in testing scenarios and platforms means there’s no all-in-one solution to FOUC. However, we’ve compiled a list of 12 techniques you can use to help mitigate the problem. These techniques are divided into 3 sections: basic preventative measures during setup, best coding practices within the platform tool, and onsite codebase changes.

During Setup

1. Snippet placement

Best practices recommend placing the snippet as high up on the page as possible, allowing the browser to evaluate the snippet’s code before loading other components of the page. Moving the snippet higher up on the page, preferably as close to the opening < head > tag as possible, can help reduce FOUC. Keep in mind, however, that any metadata or dependencies still need to be placed above the snippet if the snippet will use this information for tests. This could include analytics data, JavaScript libraries and page metadata.

Bottom line: if you’re experiencing FOUC issues across many tests, try moving the snippet higher up in the page’s code, as close to the top as possible.

2. Asynchronous vs. synchronous snippet

The snippet injected onto the page can usually be loaded synchronously or asynchronously. An asynchronous script loads alongside other scripts/elements. While this can improve page load speed performance, it can cause the original content to flicker (FOUC). A synchronous script loads in the order it exists relative to other elements on the page, and therefore scripts after it must wait for it to load first. This can negatively impact page load speed, but it will help to mitigate FOUC issues. Generally, the synchronous option is recommended, but you’ll need to determine if page load speed or issues with FOUC is more important.

Bottom line: if FOUC is an issue, try using the synchronous version of the snippet; if page load speed is an issue, try using the asynchronous version.

3. Use libraries already on the site rather than including them via the platform

If your site uses jQuery, which it likely does, then opt for the version loaded on your site over one that may be included within the platform’s snippet. Keep in mind that doing this will make your site’s library a dependency, so it will need to be loaded before the platform’s snippet. For example, Optimizely allows you to include the full jQuery library, a trimmed version, or no version at all. In this case, opt to use the site’s library, not the snippet’s, and you’ll reduce the size of the snippet while increasing page load speed performance–both factors that will help to mitigate FOUC.

Bottom line: leverage existing libraries/code loaded on the site and avoid loading similar versions through the platform.

4. Utilize “Project” JavaScript/settings if possible

Some platforms offer the ability to run global JavaScript for every experiment before the code in any given experiment is executed. Optimizely offers this capability, and it is called “Project JavaScript.” If there is JavaScript that will need to be executed across many/all of your experiments, consider adding the code here to avoid loading this code repeatedly across multiple experiments, which would increase the snippet size and could lead to FOUC.

Bottom line: take advantage of global code shared across experiments if you have the option; this minimizes code you need to write and reduces the snippet size.

5. Ensure inactive/deleted experiments are not included in the snippet

Some platforms will load the code for any and all experiments in the snippet, including experiments that are inactive in some way (paused, for example) and possibly even deleted/archived. Make sure you disable this if your platform offers this option.

Bottom line: ensure code from inactive/deleted experiments is not loaded in the snippet.

Platform Coding Techniques & Best Practices

6. Use CSS over JavaScript when applicable

CSS is faster than JavaScript, and it will apply to all applicable elements, including those that have not rendered on the page at the time the snippet is evaluated. If you find yourself making stylistic changes using JavaScript, consider using CSS instead. Most platforms allow you to write CSS for a test. Some allow you to write CSS for entire experiments as well as the variations within an experiment. If you are unable to write variation-specific CSS, consider adding unique classes to the < body > with variation-specific JavaScript and targeting these classes with the experiment-level CSS. Also, consider prepending stylesheets to the < head > of the document using JavaScript.

Bottom line: use CSS over JavaScript when possible since it is faster and applies to current and future elements. Also consider prepending stylesheets to the page with JavaScript.

7. Add a CSS “mask” over the page and remove it when the changes have been made

Another approach to mitigating FOUC is to “mask” the contents of the page by essentially rendering them invisible, and then removing this mask after the changes have been made. An easy way to do this is to add a stylesheet rendering the invisible at the start of your variation-specific JavaScript, and after the rest of the changes have been made, remove this stylesheet and render the contents visible again. It is advisable to use the visibility:hidden style here over display:none as the latter removes elements from the flow of the page which could have catastrophic effects on layout / other scripts on the site. Monetate offers the ability to add masks throughout their tool’s interface, often with adjustable parameters.

Bottom line: try hiding the elements of the page while the snippet code makes its changes and then reveal the elements after the changes have been made.

8. Poll for elements with JavaScript to make changes as soon as the elements load

Use JavaScript to poll the page for elements as the page loads in order to: (1) speed up the execution of the snippet code, and (2) ensure the code applies to elements that don’t exist on the page right away, including elements that are AJAX’ed in later. Qubit offers built-in polling modules/options. You can write your own polling functions as well. (You can check out the code I’ve written from this Github Gist.) Use a shorter polling time for faster execution, but remember the impact rapid polling has on page performance. Also make sure that your polling function doesn’t run forever. The Gist above times out after 10 seconds of polling if the element(s) is/are not found.

Bottom line: poll for elements that may take a while to load or will be pulled in later, and make your changes accordingly; make sure you do not create endless polling functions if the elements never load.

9. Make use of coding design patterns to avoid repeating similar code across variations with slight changes (advanced topic)

If your platform offers the ability to write experiment-level JavaScript, consider leveraging this capability to prevent rewriting duplicate/similar code across the different variations in an experiment. You could write the bulk of the code logic in the experiment-level JS and import only the functionality you need in the variation-specific JS. Certain design patterns, like the Revealing Module Pattern for example, will lend themselves to this based on a given scenario. Even if your platform doesn’t offer this capability, still consider using efficient modular coding designs to reduce the amount of similar code you need to write, which would increase snippet size and consequently increase chances of FOUC.

Bottom line: use efficient coding patterns/designs to reduce the amount of code you need to write for subtle changes shared across variations/experiments.

10. Last resort: minify production code

A final option to consider if FOUC is still a prevalent issue after exploring the methods above is to minify the code you add to the platform’s snippet. This will reduce the size of your experiments’ code and thus the size of the snippet, reducing chance of FOUC. However, this has a number of negative consequences: (1) minified code is not human readable and thus not easily maintainable by your team or other developers, (2) you run the risk of introducing other errors that would only occur during the minification process, and (3) debugging will be very difficult. If you choose to minify the code for your experiments, consider having a duplicate experiment for each experiment with unminified code for development purposes. This entails maintaining two experiments for every test. If your platform offers the ability to minify code at the snippet level, consider using it.

Bottom line: if the platform allows you to minify code at the snippet-level via a global setting, use it; otherwise, consider minifying the code for each experiment, but keep in mind the potential consequences like readability, maintainability, debugging, and minification errors.

Onsite Codebase Solutions & Best Practices

11. Reduce the size of your assets

Images are a common FOUC influencer, especially if the page contains many high-resolution images. In this case, consider these approaches:

  • Compress your images. There are many free online tools that can compress large images while preserving web-standard quality. Professional software is also capable of this. Optimize your images for the web.
  • Reduce the amount of images loaded on any given page. Perhaps the homepage does not need a 9-slide carousel, a recommended products carousel, a featured products carousel, and all the other graphics/bling.
  • Implement “lazy loading” of your images. This means only images onscreen are actually loaded. Images offscreen load as you scroll to them. Consider this for carousels and exceptionally long pages. There are plugins/tools to help accomplish this.

Note: you can apply these techniques to the images you upload to the platform, as well.

The sheer amount of JavaScript libraries loaded on a site can negatively impact page-load speed and increase chances of FOUC. In that case, consider these options:

  • Minify JavaScript libraries/dependencies as well large CSS files.
  • Ensure that scripts that the snippet/experiments do not depend on are loaded after the snippet.
  • Remove scripts that are no longer relevant to the site. In other words, reduce JavaScript bloat where possible.
  • Minimize the amount of inline JavaScript throughout the site (JavaScript mixed in with the markup).

12. Use a tool to gain insight about your site’s performance

There are numerous tools that can help illustrate components that are negatively affecting your site. A tool like GTMetrix provides scores for various aspects of your site, like image compression, image dimensions/resolution, minified code/libraries, and bad coding practices. Pay attention to your scores and check pages throughout your site’s funnel to determine areas for improvement.

Sean Emmel

Sean Emmel joined Blue Acorn in 2014 and has been conducting a plethora of tests (A/B, multipage, redirect and multivariate, among others) for our optimization and retainer clients. Sean’s background in e-commerce has helped him develop a strong sense of what types of UI/UX enhancements effectively benefit online retailers. That, coupled with a passion for JavaScript, lead him to his role as a front end developer II on Blue Acorn’s optimization team.

One Comment

Social Ninja
Feb 22 2016

I would never imagine there are so many! Thanks for sharing


Leave a Reply

Your email address will not be published. Required fields are marked *