At a Glance
| Mobile Performance Score | 76 | → | 94 | +24% |
| Mobile LCP | 5.2s | → | 2.6s | 50% faster |
| Total Page Weight | 2079KB | → | 525KB | -75% | Render-Blocking Assets | 12 files | → | 0 files | -12 |
*jQuery remains render-blocking due to an Oxygen Pro Menu dependency.
The Challenge
This optimization project was for a therapist’s site, built on WordPress with the Oxygen page builder. The design was solid — clean Typekit typography, professional photography, a layout that reflected the practice well. Performance was acceptable, but on a slow mobile connection, the site took longer to load. We wanted to see how much we could improve it.
Before changes, Mobile Largest Contentful Paint was 5.2 seconds. Google’s threshold is 2.5. Twelve render-blocking assets — 8 CSS files and 4 JavaScript files — forced the browser to download 207 KB before painting a single pixel. Oxygen consumed 60% of server-side PHP time and ran 33 database queries per page load. MonsterInsights added 11.65 KB of main-thread JavaScript for Google Analytics tracking.
Both LiteSpeed Cache and Autoptimize were installed on the server. Neither was activated. Every visit hit PHP cold: 82 queries, 94.5 milliseconds, no caching.
The Approach
As per our standard approach, we created a local copy of the site to test optimizations on. We measured first, then made targeted changes — one at a time, with measurement after each. Three optimizations were tried and reverted when they caused regressions, while six shipped.
LiteSpeed Cache and Autoptimize were already installed on the website at the beginning of the project. LiteSpeed Cache provides page caching on the production LiteSpeed server. Autoptimize handles CSS and JavaScript minification and combining.
1. Optimize Images — By Hand If Necessary
We added the Converter for Media plugin and converted all images that would benefit from it to WebP and AVIF formats, often shaving 50% or more off original file size. When it was helpful, we also manually edited and resized images to cut down the total page weight further.
2. Move Google Analytics Off the Main Thread
MonsterInsights loaded a JavaScript file on every page that blocked rendering. We replaced it with a Partytown implementation that runs GA4 in a web worker. Same tracking data. Zero main-thread cost.
3. Remove Plugin CSS from Pages That Don’t Need It
Fluent Forms loaded 33.2 KB of render-blocking CSS on every page—its smart loading was failing—but only the Contact page has a form. We added shortcode detection so that the plugin checks each page’s content and Oxygen builder data for form elements and dequeues the CSS when none are found.
4. Make Fonts and Animations Non-Blocking
The Typekit font stylesheet (4 KB) and Oxygen’s AOS animation CSS (25.4 KB) were both render-blocking. We converted them to preload-with-swap: the browser downloads them immediately but doesn’t wait to start painting. Fonts swap in once loaded. Animation styles apply before any scroll-triggered effects fire. No animations were negatively impacted.
5. Preload the LCP Element
The hero image was the Largest Contentful Paint element. We added a preload with fetchpriority="high" so the browser starts fetching it before encountering it in the HTML, plus preconnect hints for external domains.
6. Inline Critical CSS, Defer Everything Else
This was the largest improvement. It was also the most difficult.
Autoptimize can defer all external CSS by loading it asynchronously. Enabling this dropped LCP from 4.28s to under 3 seconds immediately. The problem: the page briefly rendered unstyled. Oxygen generates per-page CSS files served from the production uploads directory — cross-origin to the development environment, invisible to automated critical CSS extraction tools.
We built a hybrid critical CSS strategy:
- Automated coverage captured used CSS rules from same-origin stylesheets (Oxygen framework, WordPress core, Autoptimize output) across both mobile and desktop viewports
- Hand-crafted overrides covered the cross-origin Oxygen page rules — hero layout, column widths, card styling, header navigation, responsive breakpoints — extracted from production CSS with media queries preserved
The combined 29 KB inline style block renders the header, hero, and first content section identically to the full stylesheet set. We validated this with automated screenshot comparison: critical-CSS-only renders versus fully-styled renders, pixel-diffed at desktop, tablet, and mobile viewports.
7. Replace the Pro Menu’s jQuery with Vanilla JavaScript
In our earlier round of optimizations, we tried deferring jQuery and had to revert — the Oxygen Pro Menu depends on it for every menu interaction on the page. That made jQuery (87 KB, render-blocking) effectively mandatory, even though nothing else on the site needed it.
Rather than work around the dependency, we eliminated it. We wrote a lightweight vanilla JavaScript replacement that replicates every Pro Menu behavior: desktop dropdown menus, mobile hamburger toggle, sub-menu expand/collapse animations, and a handful of touch-device quirks the original code accounted for.
The replacement reads the same settings that Oxygen’s visual editor writes, so changes made in the builder still take effect on the frontend automatically. And because the swap is handled entirely in the site-specific plugin, the Oxygen editor itself is completely unaffected — it still loads jQuery and the original menu code as if nothing changed.
The result: mobile performance jumped, LCP dropped, and total page weight fell.
What We Tried and Reverted
We experimented with a number of approaches to see what could bring down mobile page load time the most, but not all changes made the cut. For example:
Deferring jQuery: Caused a 93% INP regression. Oxygen’s Pro Menu depends on jQuery for dropdown interactions at page load.
Automated critical CSS extraction (byte-range): Broke the hero layout on desktop. Puppeteer’s CSS coverage API extracts byte ranges from stylesheets. When a rule like width: 100% !important sits inside a @media (max-width: 767px) block, the byte range pulls the rule but not the media query wrapper. The mobile override applied at all viewport sizes.
Each of these was caught and reverted long before shipping.
The Results
| Metric | Before | After | Change |
|---|---|---|---|
| Mobile Performance | 76 | 94 | +24% |
| Mobile LCP | 5.2s | 2.6s | 50% faster |
| Mobile CLS | 0 | 0.0007 | Stable |
| Desktop Performance | 99 | 100 | Stable |
| Render-blocking CSS | 8 files | 0 | Eliminated |
| Render-blocking JS | 4 files | 0 | Eliminated |
| Total page weight | 2079KB | 525KB | -75% |
| GA Main-thread JS | 11.65 KB | 0 KB | Off main thread |
Mobile performance moved from “Needs Improvement” to “Good.” LCP dropped 52%, from 5.2 seconds to 2.5 seconds. Layout stability held at near zero. Render-blocking resources dropped from 12 to 1 — an unavoidable dependency (jQuery for Oxygen’s Pro Menu).
These are production measurements with LiteSpeed’s server-level page caching active. Optimization development and testing were performed on a Docker mirror of the site, where the uncached baseline LCP was 5.2 seconds.
Key Takeaway
Oxygen is a capable page builder, but it creates performance patterns that resist standard optimization approaches. It generates per-page CSS files in the uploads directory, depends on jQuery for its Pro Menu, and uses inline JavaScript for scroll animations. Tools that work well on theme-based WordPress sites — automated critical CSS generators, blanket script deferral — break in specific ways on Oxygen sites.
The path through this was measurement-driven iteration. Each change was measured. Regressions were caught and reverted automatically. The critical CSS required visual regression testing — comparing screenshots rendered with only critical CSS against the full stylesheet set — because metrics alone couldn’t catch a broken hero image layout that still “passed” on CLS.
This type of critical-path optimization is OK on a site that doesn’t often change. In the future, if layout and content changed, critical CSS might need to be re-created — so there is an optimization/maintainability tradeoff that was acceptable in this case.
Performance optimization is site-specific work and how far it should be pushed depends in part on client goals. The gains come from understanding how a particular combination of builder, plugins, hosting, and content creates a page — and systematically removing or deferring what delays that page from reaching the visitor.
