Performance in the Digital Sense

Ethan Gould
ASICS Digital
Published in
9 min readJan 30, 2020

ASICS is a performance athletics brand focused on getting the world moving. We take pride in the research, technology, and quality of materials that go into each product, resulting in some of the best shoes, apparel and accessories on the market. But what about performance in the digital sense? How can we ensure that we are offering the same level of commitment and satisfaction to our users on the web as we do with our physical products?

Coming off of a successful roll out of the ASICS North America site, our third major site on SalesForce and second rollout in 2019 alone, we took a moment to look back at our site infrastructure. Using Google Lighthouse reports, we reviewed relevant site performance data and were happy to see better performance after re-platforming, but we were not yet outperforming our competitors. At this point our competitive nature kicked in and we began a site performance initiative to discover ways to offer a faster, more enjoyable experience to our online e-commerce customers.

As mentioned before, we had been running Lighthouse reports periodically to gather performance reports of our competitors’ sites. The focus of these site speed reports was each competitor’s Homepage, Product List Page (PLP) and Product Display Page (PDP) and gathered numbers on the following metrics:

Time to First Byte (TTFB) — The time it takes for the server to send back a response to the browser.

Time to First Meaningful Paint (TTFMP) — The time it takes for the browser to parse critical page resources such as HTML, CSS and JS. This is about the time the user feels that the page is loading or loaded.

Time to Interactive (TTI) — The time it takes for the page to become interactive after content is displayed. Event handlers are attached to the Document Object Model (DOM) and the site responds to user interactions.

In order to get realistic numbers, we’ve configured the Lighthouse reports to run on a fast 3G network and test against an average mobile device. While it is totally possible that your users are using the latest devices on a strong wifi connection, often it is not the case and your site needs to perform under degraded conditions. It is also important to not rely too heavily on browser cache for your site’s assets. Not everyone is a repeat visitor who has your site’s resources conveniently stored in their browser cache from prior visits. First time visitors will feel the hit of loading all your site assets, and we all know how important first impressions are. Whether it’s a below-average device choking down your site’s JavaScript by the kilobyte or a poor connection resulting in network latency in the requests, optimizations can be made on multiple levels to speed up the loading experience. In this article we will share some of the issues we’ve identified and how we are tackling them here at ASICS.

Issues we’re addressing

1. Bloated stylesheets

  • Overly specific and nested selectors
  • Duplicative code…not #DRY
  • Unused code from old features, unsupported locales

2. Unused libraries

  • Out of the box jQuery UI plugins and effects

3. Unoptimized Critical Rendering Path (CRP)

  • Over 850kb of blocking CSS
  • Over 800kb of in-house JavaScript

4. Lazy loading images

  • Implement lazy loading on Homepage, PLP, and PDP images

Bloated stylesheets

There are a lot of tools out there that aim to help you scan your site to identify unused CSS. Tools like the Chrome Dev Tools “coverage” tab offer a good starting point and expose some initial leads. The problem is that there isn’t an easy copy and paste way to translate/transcode those finding back into a codebase. This is because oftentimes the file that is shipped to the browser doesn’t exist in the same way as it does in the source code in the codebase. For example, the site’s CSS in a codebase might actually be written in Sass to leverage handy tools like variables and mixins for better code reuse and theming. Another limitation with these tools is that they cannot easily and accurately offer reports against all states of all pages. Additionally, they don’t provide a good solution for reporting against dynamically generated classes that were created from a string combined with a variable.

Eventually I opted for a manual audit of the production stylesheet we ship to users, which for now is a large monolithic file of all styling across the site.I would uncover problematic code by finding selectors that had high occurrences in the stylesheet, because this is an indication of potentially duplicative or overly specific code that can be made more DRY. This would typically result in an audit of a component’s template and Sass files for small opportunities for refactors that would cut down on the overall amount of code. Tweaks might include generalizing class names across components that share styles. We had styling for spacing, breadcrumb, and headings for 3 different search page states: product search results, content search result, and no results found. These page elements all look the same regardless of their contexts described in the stylesheet and can therefore share a common set of style rules rather than three identical but independently defined. Tweaks were made.

Our button styling is another area that was quietly producing problematic code. We have around six different button types for a variety of calls to action (CTAs) and each button type has styles for each state such as hover, active, and disabled, as well as various elements and icons that can appear within the button. These button styles are conveniently wrapped in a Sass mixin so new features that require buttons can be styled consistently with a one-liner @include button(“primary”).

Boom! Button styles handled, all consistent and branded. Quick and easy, right? Not quite. In this case we should not let clean looking Sass blind us from the CSS that is behind the mixin. The extensive button styles mentioned previously are already associated with existing general “.button” or “.button-secondary” class etc and the template should leverage those existing classes rather than reassociate the button styles to each context that needs a button. It became clear that, given the amount the code that gets outputted, using this mixin was actually an anti-pattern disguised as a “one-liner”.

Unused libraries

The ASICS site uses jQuery for easy DOM manipulation but also leverages the jQuery UI library for elements like popup modals and tooltips. By default, an instance of the jQuery UI library will include a bunch of handy UI interactions and sweet visual effects you can use in your project. I mean, who wouldn’t want a shaking, pulsating “add to cart” button that explodes when you click it! In all seriousness, there was a lot being required that we were not actually using on our site. Luckily, jQuery offers you the ability to have a custom build of the library so you can ship only the essentials. After confirming a list of features we rely on jQuery UI for, I was able to export a more tailored version of the library for a savings of over 100kb. I should mention that the custom builder page was pretty consistently giving me a 502 response error when trying to export the custom build but with a little perseverance I was able to get through.

Unoptimized Critical Rendering Path (CRP)

The critical rendering path is the series of events occurring between the point at which a user requests your site and the point at which content is displayed in the user’s browser. The CRP ties in closely with the metrics mentioned at the beginning of the article, each metric occurring at some point along the path. The goal, of course, is to make that whole rendering process happen as fast as possible by delivering the critical resources to the user as early as possible. Without any optimizations, a site’s CSS and JavaScript, discovered while the HTML was being parsed by the browser, are considered critical resources and nothing will be displayed to the user until they are downloaded and applied to the document. That is not ideal, especially as a site grows and the amount of styling and JavaScript required increases.

Having brand consistency in-store and online is an important aspect of a cohesive, on-brand experience. On the web, having a custom font on your site is a great way to stand out and achieve that cohesion and brand familiarity. Previously, our monolithic stylesheet contained not only layout and theme styles, but also brand fonts. Fonts can be quite large and can contain multiple font-weights as well as a large amount of glyphs to support multiple languages. Trimming a font down to just the glyphs or languages your site needs can be a great optimization but is not an option for ASICS, given that we support many locales across our eCommerce sites. What we were able to improve on with our fonts was pulling them out of the monolithic stylesheet to allow them to be requested separately but downloaded in parallel with the main stylesheet. Leveraging a trick described here on the media attribute of a link tag, we can further optimize the loading of our non-critical font. This implementation causes a flash of unstyled text (FOUT) but allows for a faster perceived load time because the text content on the page is displayed immediately without waiting for the font to downloaded.

When it comes to optimizing scripts, an old trick to “soften the blow” of render-blocking scripts was to put them towards the bottom of the document, just before the closing </body> tag. This is done to allow the majority of the document to be parsed and displayed to the user without waiting for the subsequent JavaScript. This approach certainly has its benefits compared to putting the scripts in the header, such as displaying initial “above the fold” content without any delay caused by JavaScript that was encountered early in the document. However, the DOM content will not be fully loaded until the markup, stylesheet, and scripts have loaded which means that anything waiting on the “DOMContentLoad” event, such as event handlers and other UI initializations, will have to wait.

To fully optimize scripts and load them in a non-blocking way, we can leverage the “defer” attribute on our external scripts. We can also leverage the “async” attribute, which will download the scripts asynchronously from the DOM parsing, but it will block rendering while the script executes. The big takeaway is to avoid inline JavaScript logic and defer as many scripts as possible. The result is a faster perceived load time, because the site will no longer wait for all the critical JavaScript to be downloaded and executed before showing something to the user. Below is a diagram of the differences between “async” and “defer”, and there are plenty of resources out there detailing them further as well.

Credit: Growing with the Web

Lazy Loading images

Lazy loading images is one of the more impactful improvements we can make to save not only on browser bandwidth but also save on cost for our users. For the longest time we went without lazy loading at ASICS, forcing users into downloading product imagery and promotional images that were halfway down the page and not visible or applicable to them. With lazy loading in place, users are only waiting and using precious bandwidth for image content that is pertinent to their journey or visit.

This technique is especially helpful for users visiting the homepage and search result pages. An ecommerce homepage typically has a lot of high quality marketing imagery detailing the latest products and promotions. A search result page can also contain a lot of image content, especially when offering users the ability to increase the amount of search results per page by an order of magnitude. In either case, lazy loading allows us to save bandwidth, keeping the browser and user happy.

Something to consider with lazy loading content is setting up a system for placeholder or “skeleton” content to avoid janky shifts in layout as the real content loads. Some techniques I will briefly mention are “low quality image placeholders” (LQIP) which are a lighter weight, blurry version of the final image, or a super tiny SVG (1px by 1px). Here at ASICS we inline the super tiny SVG combined with initial min-height settings in CSS to avoid page jank. This placeholder technique paired with a library called bLazy (1.4kb, and works with <img> and <picture> elements, as well as srcset) has allowed us to save hundreds of kilobytes of page weight on initial load while maintaining a smooth browsing experience.

The long game

Improving site performance is not just a task on a road map; it is an ongoing endeavor and requires effort from multiple teams. From marketing and optimized imagery to developers and thoughtful code reviews, it all rolls up to the final presentation to the user, and having a good process for each step helps create a top notch digital experience. By taking a critical look at our site infrastructure and identifying opportunities for improvement, we at ASICS are pushing ourselves forward in the long game of sustainable performance, starting with this first set of optimizations.

ASICS Digital is a Boston-based company responsible for the continued development of ASICS’s mobile-fitness solutions such as ASICS Runkeeper and ASICS Studio, global e-commerce platforms, and other digital services. Come learn more about ASICS Digital here.

--

--