ع Start your project
Start your project
Published
Updated
AuthorThe Nexdune team
Sources8
Web design in Riyadh

What we measured building a fast Arabic-English website

The short answerWe built nexdune.com in Arabic and English and measured its speed at the key steps instead of guessing. The biggest gain came from starting the 3D scenes only after the page had loaded: on the English page, Largest Contentful Paint (LCP) fell from 2,771 to 2,426 ms, in one trace before the change and one after, on an emulated phone. The thing we first blamed for the slower Arabic page, balanced heading lines, made no real difference once we measured again, so we kept it.

How we measured

Every figure here comes from the build reports we write after each step, with the tool, the settings and the date. We measured the production build running on our own machine, not the development server. These are the three tools we relied on:1

ToolSettingsWhat it measured
Browser performance tracePhone emulation, 4× slower CPU, slow 4G, empty cacheLCP and layout shift (CLS), before and after
Lighthouse 12.8.2Mobile, production build served locally without compressionScore, LCP, Total Blocking Time (TBT)
Playwright4× slower CPU, about 1.6 Mbps, 150 ms latency, 8 runs per variant, interleavedTwo versions of the same page side by side

To be plain about it: the machine was busy with other programs while we measured, with 36–60 % CPU load that was not ours. So we say how many runs stand behind each number: the LCP before and after moving the 3D is one trace on each side, while the Arabic heading comparison alternated the two variants on the same machine at the same time. The site is not live yet; once it is, it will be served compressed, so its numbers will differ from these.1

Starting the 3D after load: the biggest gain

The home page has four 3D scenes. Before the change, the three.js library (about 660 KB), one 3D model (1.96 MB) and the WebGL setup all loaded before the page finished loading, competing with the text a visitor sees first. We changed that: no 3D scene starts until the load event has fired.1

One performance trace each side, emulated phone, 26 October 2026.
PageLCP beforeLCP afterCLS after
English /en/2,771 ms2,426 ms0.00

Google’s threshold for a good LCP is 2.5 seconds from when the page starts loading.5 In this trace the new figure is under it, with little to spare. Our largest element is the main heading itself, text rather than an image, and the server answered in 13–15 ms. So the delay was in drawing the page on the device, not in the network.1

Arabic headings: a hypothesis that did not hold

In the first measurements the Arabic page was slower. Tracing it, the first layout took 1.58 s on the slowed CPU, against 6 ms for a later re-layout, on a page of about 1,100 elements. When we removed the six heading rules that balance line lengths (text-wrap: balance) from a test copy, the text appeared in 2.2, 2.0 and 2.1 s.1

The idea made sense. Balancing spreads words evenly across lines, which is costly enough that browsers limit it to short blocks, six lines or fewer in Chromium.7 But that measurement was taken before the 3D moved after load. So we measured again on the current build, alternating the two variants:2

Arabic page, 26 October 2026.
VariantLighthouse LCP (median of 5)Playwright first contentful paint (median of 8)
Balanced headings2156 ms1212 ms
No balancing2206 ms1228 ms

The difference sits inside the run-to-run noise, which was over 300 ms. Worse, removing the balancing hurt the design: on phones 320 to 376 px wide, the Arabic main heading ended with one word alone on its last line. We checked every width from 320 to 432 px in 4 px steps so we would not miss a case.2

Decision: we kept the balancing. The lesson we now apply on every project: an old number is not enough to act on. Measure the current version before you change anything, because the cause can move after every change.

What still slows the page

We ran Lighthouse on the production build. This is the first run, the only one that finished with complete values for both pages:1

Lighthouse 12.8.2, mobile, 26 October 2026.
PageScoreLCPTBTCLS
Arabic /702.0 s1,950 ms0.004
English /en/721.8 s1,580 ms0.002

Our target of 90 was not met in these measurements, and we are not hiding it. Layout shift was excellent in every run. LCP met 2.5 s only in this first run; on the busy machine the other runs gave 3.4–8.8 s. The bigger problem is Total Blocking Time, the total time the page cannot respond to a click, tap or key press.6 It comes from what runs after load: WebGL setup and model parsing, then the 3D render loops and the animation ticker that drives scrolling and motion, all of which keep running. In the test browser WebGL is drawn by the CPU rather than a graphics card, so in some later runs the CPU never went quiet, and Lighthouse scored 0 because it found no idle window to measure at.1

The options we are weighing: start the 3D on the visitor’s first interaction or when the browser is idle, rather than on load, and compress that 1.96 MB model. We will measure the launch build the same way.

Two languages, two real pages

Each language is its own pre-rendered page at its own address: / for Arabic and /en/ for English. Nothing swaps text inside a single page. Each page names itself and its twin with hreflang tags, as Google asks: every language version lists itself and all the others.8

The language button is an ordinary link to the other page, and it carries what the visitor had in front of them: one snapshot in session storage, used once on arrival only if it is under 60 seconds old and meant for that page, then deleted. Before building it we measured the original design and found that the raw scroll position does not survive the switch (10549 px became 10428), because the browser and the scroll effects recalculate positions after the switch. So we bring the visitor back to the section that was at the top of their screen, at the same offset into it. The switch fades over 420 ms, and the fade is dropped for anyone who has reduced motion turned on.3

When sending fails

The “Start your project” card sends each request to Telegram and to email at the same time. If either one gets through, the visitor sees the success message. If both fail (the server answers 502), the card shows a failure pane with a Try again button and a WhatsApp button carrying the request (services, budget, timing, contact details and the first 500 characters of the message), so the request is not lost. 34 unit tests cover this part, including Telegram down while email still works.4

Building a bilingual site? What we would tell you

  • Measure on an emulated phone before and after every change, and write the date and settings next to the number.
  • Defer anything heavy that is not the first content, such as 3D or video, until after load.
  • Never act on an old number: measure the current version again.
  • Check Arabic headings at 320 to 376 px wide; that is where a single word ends up alone on a line.
  • Give each language its own address, with hreflang tags that point both ways.
  • Plan a fallback for when the form fails to send, so a customer’s request is never lost.