Introduction
When I started as a frontend developer in Faisalabad, I thought a fast website only means small images. I would compress images on TinyPNG and think my work is done. My website would still load in 6 or 7 seconds on my own Infinix mobile phone with Jazz 4G. I did not know what else to do.
Last month I got a project from a small clothing store owner in my city. He had a Shopify style store made in plain HTML CSS and JavaScript. He told me Waqas bhai my customers are leaving because website is too slow. I checked his website on my phone and he was right. It took almost 8 seconds to load fully. On slow internet it was taking more than 12 seconds. He was losing sales every day.
I decided to fix it. I did not use any paid tool. I used only free Chrome tools and modern CSS and JavaScript techniques. After two days of work, I made his website load in just 1.5 seconds on the same slow 4G connection. His Google PageSpeed score went from 34 to 97. And his sales increased by 40 percent in one week.
In this article I will share exactly what I did step by step. This is not theory from a book. This is from my real client work in Pakistan where internet is slow and every second counts.
Problem Number One - The Website Was Loading Everything at Once
The first problem I found was that the website was loading all images at once. The homepage had 25 product images. Each image was around 500 kilobytes. So total 12 megabytes of images were loading on page load, even though user could only see first 4 images at the top.
This is a very common mistake. Most junior developers load all images together. This kills performance on mobile.
The solution is lazy loading. Lazy loading means load only those images which are visible on screen now. Load other images later when user scrolls down.
I used native lazy loading which is very simple. I just added loading equals lazy attribute to all images below the fold.
Before my code was like this
img src http://product1.jpg
After I changed it to
img src http://product1.jpg loading lazy
For background images and for more control I also used Intersection Observer API in JavaScript. This API watches when an image comes near the screen and then it loads it.
Here is the code I used for background images
const lazyBackgrounds = http://document.querySelectorAll .lazy-bg
const observer = new IntersectionObserver entries => {
http://entries.forEach entry => {
if http://entry.isIntersecting {
http://entry.target.style.backgroundImage = http://entry.target.dataset.bg
http://observer.unobserve http://entry.target
}
}
}
http://lazyBackgrounds.forEach bg => http://observer.observe bg
With this one change my initial page load went from 12 megabytes to only 1.2 megabytes. That is 90 percent saving. The website started loading in 4 seconds instead of 8 seconds. Half problem was solved.
Problem Number Two - Big JavaScript and CSS Files Were Blocking the Page
The second problem was render blocking resources. The website had one big CSS file of 400 kilobytes and one big JavaScript file of 600 kilobytes. The browser was waiting to download and read these full files before showing anything on screen. So user was seeing blank white screen for 3 to 4 seconds.
I learned about critical CSS. Critical CSS means the CSS which is needed for the top part of the website that user sees first. Only that small CSS should load first. Rest of CSS should load later.
I opened my website, inspected the hero section and header, and copied only that CSS which is needed for that part. I put that critical CSS inside style tag in the head. And I made my main CSS file load later with media print trick.
Here is what I did
In head I added
style
header hero styles only around 10kb
style
And for main CSS file I changed from
link rel stylesheet href http://style.css
To this modern way
link rel preload href http://style.css as style
link rel stylesheet href http://style.css media print onload http://this.media equals all
This media print trick tells browser this CSS is for printing so do not block rendering. And when it loads, onload changes it to all media.
For JavaScript I did same. I added defer attribute to all non important scripts.
script src http://app.js defer script
Defer means download the JavaScript in background but run it only after HTML is fully loaded. So it never blocks the page.
I also removed unused JavaScript. The client had added a full slider library of 200 kilobytes just for one small image slider. I replaced that library with only 20 lines of pure JavaScript slider.
After these changes my PageSpeed Insights blocking time went from 1800 milliseconds to only 90 milliseconds. Now the website was showing content in less than 1 second.
Problem Number Three - Fonts and Third Party Scripts Were Killing Speed
The third and most hidden problem was Google Fonts and Facebook Pixel and WhatsApp chat widget. These third party scripts were adding more than 2 seconds of extra load time.
I was using 3 Google Fonts, Poppins with 6 different weights. Each weight was a separate file of around 20 kilobytes. So fonts alone were 120 kilobytes.
I fixed fonts with two steps.
First I reduced font weights. I was using 300 400 500 600 700 800. But in design I only needed 400 and 700. So I removed 4 extra weights. That saved 80 kilobytes.
Second I used font-display swap and I hosted fonts locally instead of calling Google servers every time. I downloaded the font files and put them in my own hosting with preload.
link rel preload href fonts/poppins-400.woff2 as font type font/woff2 crossorigin
And in CSS I added font-display swap
@font-face {
font-family Poppins
src url http://pons-400.woff2 format woff2
font-weight 400
font-display swap
}
Font-display swap tells browser show system font immediately and swap to custom font when ready. So user never sees blank text.
Then I fixed third party scripts. The client had Facebook Pixel, Google Analytics, and a WhatsApp chat widget. All three were loading at the same time on page load. I delayed them with setTimeout.
I loaded them only after user interacts or after 3 seconds.
setTimeout () => {
loadFacebookPixel
loadWhatsAppWidget
}, 3000
And I also added event listener for first scroll
http://window.addEventListener scroll loadThirdPartyScripts once true
This means if user scrolls, then load those scripts immediately. So important scripts still load but they do not block initial page.
After fixing fonts and third party scripts my total load time went from 4 seconds to 1.5 seconds on my Infinix phone with Jazz 4G.
Conclusion and My Performance Checklist for Slow Internet
After all these three fixes my client's website went from 8 seconds to 1.5 seconds. Google PageSpeed mobile score went from 34 to 97. The client called me and said Waqas bhai now my customers are not complaining. His online orders increased.
What did I learn? I learned that performance is not about one big trick. It is about many small smart tricks.
Now for every new project I follow this checklist.
First I always use lazy loading for all images and videos below the fold. I never load all images at once.
Second I extract critical CSS and put it inline in head and I defer all non critical CSS and JavaScript.
Third I reduce font weights and I preload fonts and I use font-display swap. And I delay all third party scripts like Facebook Pixel by 3 seconds or on first user interaction.
Fourth I compress all images to WebP format which is 30 percent smaller than JPG and I use proper width and height attributes.
Fifth I test my website not on fast WiFi but on real slow 4G with Chrome DevTools throttling set to Slow 4G. Because in Pakistan India and many Asian countries most users are on slow mobile internet. If it works on slow 4G it will work everywhere.
If you are a developer and your website is slow, please try these three steps. I am sure you will see same results as me.
Thank you for reading my case study. I hope this helps you make your websites faster for your clients.
Top comments (0)