I’ve been working for my client HSE24 for quite some time now on optimizing their website’s load performance with their team. In this article I’d like to share how and what we optimized to become the 2nd fastest retail online shop in Germany according to Dynatrace Performance Benchmark.
Actions to improve website performance
Disclaimer: This isn’t a comprehensive list. It’s just what I could remember we’ve been working on for the past 2,5 years.
Remove unnecessary event listeners
We removed all bindings to the document for scroll
, touchmove
, touchstart
, touchend
and tap
as these are fired constantly while using the site.
Remove unused and unnecessary JavaScript libraries
Since Webkit supports fast clicks on mobile now, we were able to remove libs like Fastclick.js. Also, browsers nowadays have support for many advanced features like e.g. sticky positioning which makes libs like Sticky.js redundant.
Use lazy loading
We use lazyloadxt.js to load images only when they become visible to the viewport.
Hardware-accelerate animations via GPU
jQuery’s $.animate()
method is convenient but very slow. We replaced as many animations with CSS3 translate3D(x,y,z)
as possible. This will force the device to render via GPU and will thus be much smoother than with software rendering.
Reduce CSS effects like gradients and transparency
Both have a huge impact on performance. Use with care and remove as much as possible. Talk to your designer. Explain this in a friendly way and he or she will understand.
Reduce the amount of HTTP requests
Nowadays, bandwidth on mobile devices is no problem due to HSDPA+ and LTE. The bottleneck is latency on mobile networks. Thus, you have to reduce the number of HTTP requests to a minimum. Put all your JS code into one file, same for CSS (unless you’re on HTTP/2).
Reduce the amount of setInterval()
and setTimeout()
Just don’t use these at all if possible.
Init carousels on demand
We have a lot of carousels to show our products. Some are hidden behind tab components and are thus not visible unless you click on one of them. Hence, we only initialize those which can be seen in the first place. When the user clicks a tab, we init carousels on demand.
Use frameworks/libs which care about performance
We replaced OwlCarousel with Swiper.js. What a huge difference!
Drop support for legacy browsers
Optimizing for older browsers has a huge impact on the possibilities to improve performance. Thus, we dropped support for Internet Explorer versions older than 11. Also, on mobile we only support Chrome and Safari. Buggy browsers like Android Stock Browser or Samsung’s built-in desaster is not supported.
Reduce the amount of reflows
It’s a little old but the legendary Paul Irish did a great video about reflows. Drop everything you’re doing and watch it NOW!
Load as few external scripts as possible
Scripts from external sources are a nightmare. They cause additional DNS resolution calls and you make your site dependent to external servers which can lead to slowdown and sometimes even malfunction. Thus, we try to host as much on our own as possible. We do not use CDN’s even if they have some advantages but we like to keep our destiny in our own hands.
Reference Scripts at the end of the document
Never reference your scripts in the head section of your html document. Put them at the end of <body>
if possible. Also, try to use defer or async. Use with caution though!
Remove dead JavaScript code
JavaScript is a nightmare to maintain. You never know which functions are still called and which are not. Thus, we created a logger which writes all function calls during runtime to a database via Kibana. With this list we’re able to determine if a function is still called or not and remove it.
Develop for the weakest devices
Go to eBay and buy an iPhone5 as well as a Samsung Galaxy S5 (or S4 if you wanna go hardcore). When you’re done developing a feature, test it with these two devices. If everything runs smoothly, you’re good because faster devices will run it at least as good as your minimum testing devices.
Reduce images size
Our CMS is able to scale down uploaded images. So we defined templates for screen sizes of width 320px, 480px, 768px, 1024px, 1280px and 1920px. Anything beyond this will be scaled down. Also, JPEG should be compressed with setting “85” (equals 15% compression) which is a good trade-off between image size and quality.
Switch from Apache to NGINX
NGINX is great at delivering many small static files in a short period of time. You should use it, if you can.
Use a static subdomain
We deliver all our static media (scripts, stylesheets, fonts, images…) via an own subdomain static.hse24-dach.net because we do not set any cookies for it (static media does not require cookie information at all). Hence, the cookie overhead for each request should be 0.
Improve cache configuration
We set max-age to 30 days in the HTTP headers for all static media to optimize browser caching. When a file changes, we also change the reference URL to notify the browser that it should get a fresh copy of the ressource. For example, if foo.jpg has changed, we automatically also increment our cid parameter: <img src="foo.jpg?cid=2">
Pre-generate images
We used to have a web application which generates scaled variants of images on demand. This is to slow because the application has to be called for every request and server caching is quite tricky in this case. Thus, we pre-generate all scaled versions of the images we have and deploy them statically on our NGINX servers which is blazing fast. This requires multiple terabytes of data but remember that storage these days is cheap compared to CPU power.
Improve the build process
We cleaned up our Grunt build file and optimized it to get the fastest performance possible. Also, we replaced our SASS compiler which was based on Ruby with a much faster C++ version. This doesn’t have direct impact on website load performance, but the faster devs can work, the faster and better you get the job done. Also, it’s more fun :-)
Use server side includes for static HTML
We use SSI to include static HTML (like e.g. header, footer, navigation..) into our templates in order to be able to cache these HTML snippets. We only render the part of the HTML which is dynamically created by our web application server like e.g. personalized content. This is way faster than composing the whole page for each request.
Simplify content
We used to have a lot of content on our homepage. It’s still not as lightweight as I think it should be but it got much better. Check all components on your page and ask yourself: Do I really need this? Does it benefit either me or the user? If not, trash it.
Care about performance
Our technical lead used to be a developer, so he cares about performance which is a good thing. If you’re looking for a new job, I can highly recommend to check the background of your next supervisor. It’s much easier to work with a technical person than with a manager type guy.
Conclusion
You have to keep pushing forward. Don’t rest. When you stop optimizing your site will end in a big slow mess in a few years since requirements for new features continue to grow which usually eats more CPU power as well as network bandwidth. There are still many more things we’re working on to push load times even faster, like e.g. removing dead CSS code. Unfortunately this is not an easy task and there are no best practices that I’m aware of. If you have any suggestions, let me know :-)