Why your website loads slowly (and how to fix it)
The cost of being slow
Every extra second of load time costs you visitors. Google measures this: a page that loads in 3 seconds has 32% more abandonment than one that loads in 1 second. At 5 seconds, 90% are gone.
Those numbers feel abstract until you do the math. If your site gets 1,000 visitors a month via Google Ads at R$3 per click, and 30% give up because the page takes too long to load, you’re throwing away R$900 per month. R$10,800 per year. To fix a problem that an afternoon of work solves.
If you’re not paying for traffic, the cost is different but just as real: the visitor who came from organic Google, Instagram, or a referral left without seeing the content. You’ll never know they existed.
There’s the SEO factor too. Google has been using Core Web Vitals as a ranking signal since 2021. A slow site loses position to a competitor with equivalent content but faster loading. It’s not the main ranking factor, but in competitive niches where everyone has similar content, performance becomes the tiebreaker.
The 3 most common culprits
I’ve audited dozens of sites over the past few years. The problems repeat. In 90% of cases, it’s the same three.
1. Unoptimized images
The number one reason for slow sites. A photo taken with a phone is 3 to 5 MB. It gets uploaded to the site in its original format (4000x3000px JPG), no compression, no resizing. Result: the homepage alone has 15-20 MB of images.
On the Family Pilates project, the original studio photos totaled almost 20 MB. After converting to WebP and resizing to the actual display size, the total dropped to 800 KB. Same visual quality, 96% lighter.
On Soline (renewable energy), the challenge was bigger: lots of field photos with solar panels, installations, and the team. High volume of images that need to be there. All were optimized in WebP with real dimensions and lazy loading. The site scored Lighthouse 95+ despite being visually dense.
How to fix it:
Convert to WebP. WebP delivers 60-80% less weight than JPG at the same visual quality. The browser doesn’t notice the difference. Your Lighthouse score will. Free tool: squoosh.app (runs in the browser, no installation needed).
Resize to the actual resolution. A 4000px image in an 800px container is pure waste. The browser downloads 5 MB and displays it at 800px. Resize to 2x the display resolution (1600px for an 800px container, to stay sharp on retina screens) and you’re done.
Use native lazy loading. loading="lazy" in HTML makes the browser load the image only when the user scrolls to it. Images below the fold (what’s not visible on the initial screen) don’t need to load in the first second. This improves LCP significantly.
Set width and height in HTML. Without explicit dimensions, the browser doesn’t know the image size before loading it. The layout “jumps” when the image appears. This causes CLS (Cumulative Layout Shift), one of the metrics Google penalizes. If you use CSS to make the image responsive (width: 100%; height: auto), the width and height attributes in HTML still serve a purpose — the browser calculates the aspect ratio before download and reserves the correct space.
In Astro, image optimization is built in. The <Image> component in Astro converts, resizes, and optimizes automatically at build time. That’s why all my Astro projects hit Lighthouse 95+ without manual effort.
2. Too much JavaScript
A 5-page business website doesn’t need React, Vue, or Angular. But many are built with a heavy framework because “the dev knew how to use it” or “we might need interactivity in the future.”
The result: 200-500 KB of JavaScript to render static text and images. The browser downloads, parses, and executes all that code before displaying the page. Wasted time.
I once audited a law firm website built in Next.js that shipped 287 KB of JS to the browser. Zero interactivity. Zero forms. Zero state. Just text and photos. That’s what made me switch to Astro for this type of project.
How to fix it:
If it’s a static site, use Astro. Zero JS by default. The browser gets pure HTML. All my site/LP projects in Astro ship 0 KB of client-side JavaScript.
If it’s WordPress, audit your plugins. Each plugin can load its own CSS and JS on every page. Form plugin? Loads JS on the blog. Analytics plugin? Loads a script in the footer. Deactivate what you don’t use, and configure the ones you need to load only where they’re needed.
Remove dead libraries. jQuery in 2026? Animate.css imported but unused? The entire Font Awesome package for 3 icons (which is 400 KB+ of fonts and CSS to render 3 SVGs)? Every library added and forgotten is dead weight. A quick test: open the Webpack or Vite bundle analyzer and see which dependencies take up the most space. There’s almost always a surprise.
Load scripts with defer or async. defer makes the script execute after the HTML is parsed. async downloads in parallel. Without either, the script blocks the entire page from loading.
Quick test: Chrome DevTools, Network tab, filter by JS. If the total exceeds 200 KB on a business site, there’s excess. If it exceeds 100 KB, it’s already worth investigating.
3. Bad hosting
Shared hosting at R$15/month splits a server with hundreds of other sites. If one of them gets a traffic spike, yours gets slow too. If the server is in Virginia and your audience is in Brazil, that adds 150ms of latency to every request.
Tok Final is a case where hosting matters more than usual. Construction managers access the site from the job site, on their phone, with unreliable 3G. If the hosting is slow and the site takes 5 seconds to load, it won’t get opened. Deploying on Vercel with global CDN fixes it: the site is served from the closest point to the visitor.
How to fix it:
Static site? Deploy on Vercel or Netlify. Free tier, global CDN, automatic HTTPS, deploy by pushing to Git. It’s the default choice for any Astro project. Zero server configuration.
WordPress? WP-optimized hosting (Cloudways, DigitalOcean with a cache plugin) instead of generic shared hosting. The difference is significant.
Webapp? Supabase cloud (backend) + Vercel (frontend). The database sits in an optimized region, the frontend on the global CDN.
CDN makes a difference. A CDN (Content Delivery Network) copies your site to servers spread around the world. A visitor from Sao Paulo gets served from the Sao Paulo server. A visitor from Lisbon gets served from the European server. Without a CDN, everyone gets served from the same server regardless of where they’re accessing from. In practice, the difference between serving from a Virginia datacenter vs. the edge in Sao Paulo can be 120-180ms per request. Sounds small, but a page with 20 resources (HTML, CSS, fonts, images) accumulates that delay on each one.
Fonts add weight too
A point many people forget. External fonts (Google Fonts, Adobe Fonts) add extra HTTP requests and block text rendering.
How to fix it:
Self-host them. Download the fonts in woff2 and serve them from your own server. Eliminates the request to Google/Adobe. That’s what I do on every project — my site uses Degular Display and Aktiv Grotesk self-hosted.
font-display: swap. The browser shows text with a fallback font immediately and swaps when the custom font loads. The visitor sees content instantly, the font appears 200ms later. Better than a blank screen waiting for the font.
Preload critical fonts. <link rel="preload" href="/fonts/font.woff2" as="font" type="font/woff2" crossorigin> in the <head> makes the browser start downloading the font before it needs it.
How to measure your site’s speed
Google PageSpeed Insights (pagespeed.web.dev): enter the URL and it analyzes it. Above 90 is good. Below 50 needs urgent attention. Between 50 and 90, there are easy optimizations to make.
Lighthouse (Chrome DevTools): same engine as PageSpeed, but runs locally. More reliable because it doesn’t depend on an external connection. Lighthouse tab in DevTools, run a full audit.
What to look at in the results:
- LCP (Largest Contentful Paint) measures how long it takes for the main content to appear. Target: under 2.5 seconds. Common culprit: heavy hero image, font blocking render
- INP (Interaction to Next Paint) measures how long it takes to respond to the first click. Target: under 200ms. Common culprit: heavy JavaScript blocking the main thread
- CLS (Cumulative Layout Shift) measures how much the page “jumps” during loading. Target: under 0.1. Common culprit: image without width/height, font that loads late and changes text size
Quick checklist
- Images in WebP with correct dimensions
- Lazy loading on images below the fold
- JavaScript with defer/async (or zero JS if possible)
- Self-hosted fonts with font-display: swap and preload
- Hosting with CDN (Vercel, Netlify, or equivalent)
- Lighthouse above 90 in Performance
- HTTPS active (Google penalizes sites without it)
- No unnecessary JS libraries
- Images with width and height in HTML
If you check all of these, your site loads in under 2 seconds. If you check none, it probably takes over 5. Most of these problems can be fixed in an afternoon. The return on investment easily pays off.