Beautiful Websites Shouldn’t Be Slow: 98 on Mobile, 100 on Desktop

How I built prabir.dev for design and speed: 98 mobile and 100 desktop PageSpeed results, practical Next.js lessons, code examples and a launch checklist.

Prabir Singh, profile photoPrabir Singh·
·18 min read
Editorial composite of prabir.dev homepage PageSpeed reports: mobile performance 98 and desktop 100, with accessibility, best practices and SEO scores of 100.
In this article
  1. 01The PageSpeed results, with the context that matters
  2. 02What those numbers mean to the person visiting
  3. 03What changed in this portfolio
  4. 04A small Next.js example: enhance the page without holding it hostage
  5. 05A practical way to diagnose a slow website
  6. 06Keep the design, remove the unnecessary waiting
  7. 07Does a 100 SEO score mean the site will rank first?
  8. 08What I deliver beyond a good-looking screenshot
  9. 09A launch checklist you can use on your own site
  10. 10Questions worth asking before you hire a developer
  11. 11A few honest answers
  12. 12Build something worth waiting for. Then reduce the waiting.

A website can look wonderful on a designer’s laptop and still make someone on a phone wait for the privilege of seeing it.

That is an expensive first impression. You have already asked for their attention. Asking them to admire a loading screen as well feels a little ambitious.

On 24 October 2026, the PageSpeed Insights reports I captured for the prabir.dev homepage showed 98 for mobile performance and 100 for desktop performance. Both also showed 100 for accessibility, best practices and SEO.

The site still has its visual personality: a cinematic hero, animated typography, project interactions and carefully considered motion. The useful part of this story is how to give those details room without making the essential experience wait behind them.

This is a practical account of the work behind this portfolio. If you build websites, you’ll find decisions and examples you can apply. If you’re hiring someone to build yours, you’ll find better questions to ask than “Will it look modern?”

The principle I keep coming back to: deliver the useful page first, then add the experience around it.

The PageSpeed results, with the context that matters

These are the values visible in the two homepage reports, not averages across the site:

MeasurementMobileDesktop
Performance98 / 100100 / 100
Accessibility100 / 100100 / 100
Best practices100 / 100100 / 100
SEO100 / 100100 / 100
First Contentful Paint1.6 seconds0.5 seconds
Largest Contentful Paint2.1 seconds0.7 seconds
Total Blocking Time60 milliseconds40 milliseconds
Cumulative Layout Shift0.0020

The featured image combines the two reports into an AI-assisted editorial composite. For the actual evidence, open the untouched mobile report screenshot and desktop report screenshot.

The screenshots show “No Data” in the real-user section. That matters. These are Lighthouse lab results generated by PageSpeed Insights, not a completed real-user Core Web Vitals assessment. PageSpeed separates controlled lab diagnostics from field data collected from real visits. Google’s explanation of PageSpeed Insights.

I’m also auditing other page types separately. A strong homepage does not automatically make every article, service page or contact flow fast. The figures above apply to the homepage runs shown here.

Why I’m not promising 98 on every run

A test result belongs to a URL, a version of a page and a set of testing conditions. Network routing, browser versions and the machine running the test can change the result. Google explicitly describes Lighthouse performance as a distribution of scores rather than one permanent number. How Lighthouse performance scoring works.

For that reason, I save the report and inspect the underlying timings. “The main content appeared in 2.1 seconds in this mobile test” tells us more than “the circle is green.”

Neither figure establishes a conversion increase, a revenue gain or a ranking improvement. Those would need their own evidence.

What those numbers mean to the person visiting

The report is technical. The experience it describes is familiar.

First Contentful Paint, or FCP, is the first visible content. It answers the visitor’s earliest question: has anything arrived?

Largest Contentful Paint, or LCP, tracks when the largest visible image or text block appears. It is often a better signal of whether the page feels meaningfully ready. A large heading can be the LCP element; it is not always the hero image. Google’s LCP optimization guide.

Total Blocking Time, or TBT, describes blocking work during the lab loading test. Low TBT is encouraging, but it does not prove that every later click will be responsive. For real interactions, the relevant Core Web Vital is Interaction to Next Paint, or INP, which looks at the responsiveness of qualifying interactions over the visit. Understanding and improving INP.

Cumulative Layout Shift, or CLS, measures unexpected layout movement. Think of the button that relocates just as you tap it. Nobody requested that particular game.

The homepage’s mobile CLS of 0.002 shows very little layout movement in that recorded load. It does not mean I can stop checking what happens when the menu opens, an image fails or a form returns an error.

What changed in this portfolio

An earlier local mobile Lighthouse audit of this homepage recorded 52 performance, with 6.7-second LCP and about 510 milliseconds of TBT. That was a separate CLI test, not the same PageSpeed Insights run as the screenshots above. It gave me a useful baseline for finding problems; it would be misleading to present the two tools as a perfectly controlled experiment.

Several changes followed. I did not isolate every change in a formal experiment, so I’m not assigning an invented percentage improvement to each one.

1. Stop making complete content wait behind a blanket loader

A root-level loading boundary was putting already prepared static content behind a reveal step. The page could have useful HTML available while still waiting for JavaScript to show it.

I removed that blanket skeleton. Navigation still has progress feedback, and components such as the booking calendar retain their own loading and error states.

The distinction is practical: a calendar waiting for availability needs a loading state. An entire article that is already ready to read usually does not need to wait with it.

Try this: inspect the first HTML response and the performance trace. Is the main content there and visible? Or does a script, a loading screen or an animation have to finish before it can appear?

This is one reason I like thinking about React Server Components as a division of responsibilities. Prepare the readable material where it makes sense; reserve browser work for things that actually need the browser.

2. Give simple motion a simpler implementation

The header’s small settling movement and the hero video’s crossfade did not each need an animation library on the startup path. Those effects now use CSS and a small amount of browser logic. The navigation progress indicator uses the Web Animations API.

Richer effects still exist. The important change was choosing the right mechanism for each job.

This is not a rule that animation libraries are bad. A coordinated sequence or complex interactive scene may justify one. A short opacity transition probably does not need the same machinery.

Try this: list the effects visible before the first scroll. For each, write down what the visitor gains and what must load to make it happen. That tiny inventory can reveal a surprisingly large dependency chain.

3. Load enhancements near the point of use

The booking calendar now starts loading its availability and calendar interface near the viewport. Its introduction and permanent appointment anchor remain available first.

The scrolling technology bands and rotating contact badge also load as nearby enhancements. Static text or reserved dimensions preserve the initial layout.

There is a balance here. Loading an interface only after someone clicks can create a frustrating pause. Loading it when they approach the section can make it ready without charging every visitor for it at the start. Next.js supports splitting client components and libraries so they can load when needed. Official Next.js lazy-loading guide.

Try this: classify page features as “needed immediately,” “needed near this section,” and “needed after an action.” Start with the largest optional component, not the smallest icon.

A logo link to the homepage seems harmless. In this site, its automatic prefetching could bring homepage resources into another page’s loading work.

I disabled that prefetch, alongside selected other links where the early work was not helpful. Visitors can still navigate normally.

Prefetching is a tradeoff: spend resources now to make a likely next step faster. That can be worthwhile for an important journey. It is less helpful when every visible link competes with the content someone came to read.

Try this: open the Network panel on an article before clicking anything. If resources for other routes are arriving, check which links requested them and whether that prediction is useful.

5. Render the calendar the device actually needs

The GitHub contribution comparison originally had room to do unnecessary rendering work. The responsive version now renders the appropriate calendar for the current viewport: a shorter view on phones and the larger year-to-date view on desktop.

Its cached data is requested near the section. The public/private comparison remains, while the phone avoids carrying both calendar presentations at once.

Try this: look beyond download sizes. Two large interfaces hidden behind CSS breakpoints can still mean extra DOM, rendering and hydration work. “Hidden” and “free” are different words for a reason.

6. Check that the cache can actually store anything

The wider audit exposed an operational problem that a homepage screenshot did not reveal: a 128 MB temporary cache was full. Generated page entries had used the available space, and server logs showed ENOSPC errors when Next.js tried to save optimized images.

The images still appeared, but repeat requests kept doing expensive work. A cache that cannot write is mostly a very optimistic folder name.

I moved the runtime cache to disk, separated reusable image variants from release-specific page entries, and set a 500 MB image-cache limit. A direct diagnostic request then changed from a miss to hits on repeat requests. That confirms the caching behaviour; it does not establish a universal speed improvement for every visitor.

Try this: check cache response headers, write errors, available space and permissions together. Also test after a deployment, when a temporary container filesystem may have disappeared. For a self-hosted Next.js app, read the deployment and caching guidance and the image disk-cache limit documentation. Choose storage and limits for your workload; copying my number is not capacity planning.

A small Next.js example: enhance the page without holding it hostage

Here is an illustrative example, not a copy of this portfolio’s production code. Imagine a case study with a useful written explanation and an optional interactive diagram.

Keep the explanation in the page. Load the interactive component shortly before its reserved area becomes visible:

"use client";
 
import dynamic from "next/dynamic";
import { useEffect, useRef, useState } from "react";
 
const InteractiveDiagram = dynamic(
  () => import("./interactive-diagram"),
  { ssr: false, loading: () => <p>Preparing the interactive view…</p> }
);
 
export function OptionalDiagram() {
  const region = useRef<HTMLDivElement>(null);
  const [nearby, setNearby] = useState(false);
 
  useEffect(() => {
    const element = region.current;
    if (!element) return;
 
    const observer = new IntersectionObserver(([entry]) => {
      if (!entry.isIntersecting) return;
      setNearby(true);
      observer.disconnect();
    }, { rootMargin: "240px" });
 
    observer.observe(element);
    return () => observer.disconnect();
  }, []);
 
  return (
    <div ref={region} style={{ minHeight: 280 }}>
      {nearby
        ? <InteractiveDiagram />
        : <p>The written explanation above covers the full process.</p>}
    </div>
  );
}

The 240px margin starts the work before the visitor reaches the region. It is a starting point to test, not a magic number. The reserved height should match the real component closely enough to avoid a jump.

There are three important limits to this example:

  • The diagram must be optional. Don’t hide the only useful explanation inside a client-only component.
  • The imported module must exist, and a production implementation should handle a failed download with a useful fallback or retry.
  • Check the keyboard experience and reduced-motion preference inside the diagram itself. Lazy loading does not provide accessibility automatically.

If the enhancement is tiny, this extra machinery may cost more complexity than it saves. Measure before adopting it everywhere.

A practical way to diagnose a slow website

Start with the symptom, then use the report to choose the investigation. Randomly adding lazy and preload attributes is a surprisingly effective way to create a different problem.

What you noticeInspect firstA useful next stepAvoid this shortcut
The page takes time to show anythingHTML response and render-blocking resourcesCheck server response, styles and visible server-rendered contentBlaming the hero image before identifying the delay
Main content arrives lateThe actual LCP element and its timing breakdownSeparate discovery, download and render delaysCompressing an already tiny image while a reveal script blocks it
Taps feel delayedMain-thread tasks and an interaction traceFind expensive handlers, rendering or third-party workAssuming a good loading score proves every interaction is fast
Content jumpsLayout-shift recordsReserve image space and examine late insertsMoving the problem below the fold
An article fetches unrelated resourcesNetwork initiators and route prefetchesReview speculative downloadsDisabling every useful prefetch without checking navigation
The desktop looks fine but mobile strugglesThe mobile layout and its startup workTest the smaller device experience independentlyMerely shrinking the desktop design

For an image-related LCP problem, examine the full sequence. The browser must discover the resource, request it, receive it and render the element. Improving one stage does not remove a bottleneck in another. How to break down LCP.

Also check the response that reaches the browser. A server setting can look sensible while a reverse proxy changes the actual compression or caching behaviour. I investigated that in this project too. I’m not counting that experiment as a proven improvement in the reported result; the browser measurements have to support the claim.

Keep the design, remove the unnecessary waiting

A performance pass should preserve the reasons someone remembers the website.

For this portfolio, that includes the personality of the hero, the typography, the project storytelling and the small interactions that make navigation feel considered. The work is deciding which parts deserve early resources and which can wait.

My working rules are:

  1. The headline must be readable without an entrance routine. Animation can add character after content is available.
  2. Motion needs an alternative. Reduced motion should leave a complete, understandable interface.
  3. Reserve space before content arrives. This includes images and late-loading widgets.
  4. A hover cannot be the only explanation. Touch and keyboard visitors need the same destination and meaning.
  5. An effect must fail gracefully. A failed video, diagram or script must not take navigation with it.

These decisions are easier when the site has a coherent design system. Reusing a clear set of behaviours beats solving every button, card and loading state from scratch.

Does a 100 SEO score mean the site will rank first?

No. The SEO score is useful evidence about the checks performed by that audit. It is not a ranking forecast.

Google uses Core Web Vitals in its ranking systems, but good results do not guarantee top positions. Relevance, helpful content and the wider page experience still matter. Google’s guidance on page experience.

For this article, sensible SEO means a descriptive title, readable content, a canonical URL, relevant internal links, accurate metadata and a share image that represents the actual subject. It also means answering the question that brought someone here.

The same care applies to 100 accessibility. Lighthouse’s automated score does not include every manual accessibility check. A green report does not replace keyboard testing, careful focus behaviour or checking whether the interface makes sense. What the Lighthouse accessibility score covers.

And 100 best practices is not a security certificate. Authentication, authorization, business logic and operational security require their own review.

What I deliver beyond a good-looking screenshot

This portfolio is my own project, not a client result I’m borrowing. It shows how I approach the combined job of design and development.

For a founder, the useful output is a site that communicates the offer, works on a phone and helps someone take the next step. The engineering should support those goals rather than becoming an invisible collection of assumptions.

These are the deliverables I discuss when scoping that work:

Part of the workWhat it should give you
Design and content structureClear hierarchy, readable copy and a path to the important action
Responsive implementationAn experience checked on mobile and desktop, including navigation and forms
Performance workSaved measurements, identified bottlenecks and changes tested on the deployed build
Search foundationsCrawlable content, relevant metadata, canonical URLs and useful internal links
Interaction qualityVisible focus, meaningful loading states, recovery from errors and reduced-motion behaviour
HandoverAn explanation of how the site works, what was verified and what needs ongoing attention

The exact scope belongs in the project agreement. A portfolio, a content-heavy publication and a logged-in application have different constraints; I would not promise identical scores before seeing the work.

If you want the broader thinking behind this approach, read Build for the Buyer, Not Just the User. A technically impressive page still has to help a person make a decision.

A launch checklist you can use on your own site

Use this before celebrating the score:

  1. Test the production URL. Development mode includes work and behaviour that do not represent the deployed experience.
  2. Save the exact URL, date and report. Keep mobile and desktop results separate.
  3. Repeat under comparable conditions. Three runs are a practical starting point. Record the range and median instead of sharing only the best run.
  4. Inspect the timings behind the score. Identify the LCP element, layout shifts and blocking tasks.
  5. Test representative page types. Include the homepage, an article, a service page, a project and the contact journey.
  6. Try a direct visit and internal navigation. They exercise different loading and caching paths.
  7. Test consent states. Optional analytics and marketing tools can change the experience after consent. See my guide to consent-first analytics in Next.js.
  8. Use the keyboard and a small screen. Open the menu, follow links, trigger validation and make sure focus stays visible.
  9. Check slow and failed resources. Does essential content survive a missing image or unavailable widget?
  10. Keep measuring after launch. New content, integrations and dependencies can change the result.

A useful review note can be as simple as this:

URL and release:
Test date and tool version:
Mobile scores across three runs:
Desktop scores across three runs:
LCP element and timing:
Layout shifts observed:
Main interaction tested:
Slow-network or failure behaviour:
Known limitations and next action:

That note is more actionable than a folder called final-final-really-fast.png.

Questions worth asking before you hire a developer

“Can you show a report from the deployed page?” A local screenshot is a useful development artifact, but the live delivery path matters.

“Which pages and interactions did you test?” One fast landing page says little about a slow booking form three clicks away.

“What happens if a third-party service is slow?” Good answers explain loading, recovery and what remains usable.

“What did you trade off?” Every meaningful optimization has context. A thoughtful answer is more reassuring than “we just optimized everything.”

“What will I be able to maintain?” You should know how to update content, where integrations live and which changes deserve another performance check.

You do not need to become a browser engineer to ask for evidence. You need a clear explanation of what was built and how it was checked.

A few honest answers

Is 90+ on mobile a reasonable target?

It is a useful lab target for many public-facing sites. Whether a particular page can sustain it depends on its content, integrations and testing conditions. Agree on the pages, test method and functionality before making the number a delivery promise.

Should I remove all animations to get there?

Start by removing unnecessary startup work. Small CSS effects and well-timed enhancements can preserve the design. Measure the expensive interactions individually before removing personality from the entire site.

Are these results a Core Web Vitals pass?

They are homepage lab results. The supplied reports have no real-user data, so they do not establish a field pass. Field assessment uses real-user LCP, INP and CLS data rather than the single Lighthouse performance score. Google’s Core Web Vitals overview.

Can I reproduce exactly 98 and 100 today?

You may get different numbers. Test the live homepage in PageSpeed Insights and save the current report. The screenshots document the runs captured on 24 October 2026.

Build something worth waiting for. Then reduce the waiting.

I’m pleased with these results because the homepage kept its character while the loading work became more deliberate.

The lesson is available without hiring me: find the real bottleneck, make useful content available early, give enhancements a sensible loading point and verify the deployed experience.

If you’re planning a site, use the checklist above to write a short brief: who it is for, what visitors need to do, and which pages matter most. If you’d like help turning that into a designed and working product, tell me about the project. Bring the awkward questions. They are usually the useful ones.

Was this useful?

No account needed. One like per browser; click again to undo.

ShareXLinkedIn
Prabir Singh, profile photo

Prabir Singh

Full-stack engineer in Mumbai. Twenty years in sales taught me why people buy; seven years of code taught me how to build what they'll pay for. I still read error messages the way I once read objections: as the most honest feedback of the day. More about me or start a project.

Keep reading