Sheraz AhmadSenior Web Developer
Let's talk

Improve LCP in WordPress Elementor: 5 Step-by-Step Fixes

Struggling with a slow Elementor site? Learn how to improve LCP in WordPress Elementor with these 5 practical, developer-focused fixes for hero images, CSS bloat, and server lag.

If you want to improve lcp wordpress elementor metrics, you must address how Elementor handles DOM generation, asset loading, and image prioritization. This guide provides five direct, developer-tested fixes to optimize your Largest Contentful Paint (LCP) and pass Core Web Vitals without stripping away your layout.

Quick answer

  • Fix the Hero Image: Disable lazy-loading for the first image on the page and preload it using a custom header link or hook.
  • Eliminate CSS Bloat: Enable Elementor's "Improved Asset Loading" and "Inline Font Icons" experiments, then dequeue unused global stylesheets.
  • Prevent Web Font Delay: Set font-display: swap for all Google Fonts and local fonts, and preload the primary body font file.
  • Optimize DOM Depth: Avoid nesting columns inside sections inside inner sections; use CSS Grid or Flexbox containers instead.
  • Reduce TTFB: Implement page caching, use object caching for database queries, and route traffic through a CDN with Edge caching.

1. Prioritize the above-the-fold hero image

By default, WordPress and performance plugins lazy-load all images. This is a major mistake for your hero image or featured banner. When the browser has to wait for JavaScript to calculate if the hero image is in the viewport before fetching it, your LCP score tanks.

To fix this, you must programmatically exclude the first image (usually the LCP candidate) from lazy-loading and preload it.

Exclude the hero image from lazy-loading

If you are using WordPress core lazy-loading, you can use the wp_img_animation_and_lazy_loading_choices or wp_get_attachment_image_attributes filter to disable the loading="lazy" attribute on the first image.

Add this code to your child theme's functions.php file:

function custom_exclude_hero_from_lazy_load( $attributes, $attachment ) {
    // Replace 1234 with your actual hero image attachment ID
    if ( isset( $attachment->ID ) && 1234 === $attachment->ID ) {
        $attributes['loading'] = 'eager';
        $attributes['fetchpriority'] = 'high';
    }
    return $attributes;
}
add_filter( 'wp_get_attachment_image_attributes', 'custom_exclude_hero_from_lazy_load', 10, 2 );

Preload the hero image in the document head

Preloading tells the browser to fetch the image immediately, even before it parses the CSS and discovers the image tag. Add this hook to inject a preload link tag into your site's header:

function custom_preload_hero_image() {
    if ( is_front_page() || is_home() ) {
        $hero_image_url = 'https://example.com/wp-content/uploads/hero-banner.webp';
        echo '<link rel="preload" fetchpriority="high" as="image" href="' . esc_url( $hero_image_url ) . '" type="image/webp">' . "\n";
    }
}
add_action( 'wp_head', 'custom_preload_hero_image', 1 );

Using fetchpriority="high" alongside the preload link instructs modern browsers to prioritize this asset above stylesheets and scripts, drastically reducing LCP.

2. Eliminate Elementor CSS bloat and unused assets

Elementor loads a large suite of stylesheets on every page, regardless of whether you use the corresponding widgets. This blocks the main thread and delays the rendering of the LCP element.

Enable Elementor performance experiments

Navigate to Elementor > Settings > Features in your WordPress dashboard. Turn on these features:

  1. Improved Asset Loading: Loads widget-specific JS/CSS files only when those widgets are used on the page.
  2. Inline Font Icons: Replaces the heavy Font Awesome icon library stylesheet with inline SVG icons.
  3. Optimized Gutenberg Loading: Prevents Gutenberg block styles from loading where they are not needed.

Dequeue unused styles programmatically

If you do not use certain Elementor features, dequeue their stylesheets. For example, if you do not use Elementor's global animations or frontend icons, dequeue them with this snippet:

function custom_dequeue_elementor_bloat() {
    // Dequeue Elementor icons if you use SVGs instead
    wp_dequeue_style( 'elementor-icons' );
    
    // Dequeue animations if you do not use entry animations
    wp_dequeue_style( 'elementor-animations' );
}
add_action( 'wp_enqueue_scripts', 'custom_dequeue_elementor_bloat', 20 );
Keep in mind that dequeuing styles can break layouts if you accidentally target an active style. Always test these changes on a staging environment first.

3. Optimize web font loading to prevent layout shifts

When a browser loads web fonts, it often hides the text until the font file is fully downloaded (Flash of Invisible Text, or FOIT), or it displays a fallback system font and then jumps when the custom font loads (Flash of Unstyled Text, or FOUT). Both delay LCP and degrade your Cumulative Layout Shift (CLS) score.

Apply font-display: swap

To ensure text renders immediately using a system font while the custom font loads, add font-display: swap to your font declarations.

If you use Google Fonts through Elementor, add this filter to your functions.php file to append the display=swap query parameter to the Google Fonts API request URL:

function custom_add_subsets_to_google_fonts( $url ) {
    if ( strpos( $url, 'fonts.googleapis.com' ) !== false ) {
        $url = add_query_arg( 'display', 'swap', $url );
    }
    return $url;
}
add_filter( 'style_loader_src', 'custom_add_subsets_to_google_fonts', 10, 1 );

Preload local fonts

If you host your fonts locally (which is recommended for GDPR compliance and speed), preload the primary font file used for your body text and headings. Add this to your header:

function custom_preload_local_fonts() {
    $font_url = get_stylesheet_directory_uri() . '/assets/fonts/main-font.woff2';
    echo '<link rel="preload" href="' . esc_url( $font_url ) . '" as="font" type="font/woff2" crossorigin>' . "\n";
}
add_action( 'wp_head', 'custom_preload_local_fonts', 1 );

4. Flatten your DOM structure

Elementor historically created deeply nested HTML structures (e.g., div > div > div > div). A deep DOM tree increases memory usage, slows down style calculations, and delays rendering of the LCP element.

Switch to Flexbox and Grid Containers

If your site still uses the legacy Section/Column structure, convert your layouts to Flexbox Containers.

  1. Go to Elementor > Settings > Features and ensure Flexbox Container is active.
  2. Open your pages in the Elementor editor.
  3. Click on a legacy Section and click the Convert button in the sidebar panel.
  4. Delete the old Section once you verify the new Container replica looks correct.

This single change can reduce your DOM depth by up to 40%, allowing the browser to parse and paint the LCP element much faster.

5. Reduce server response time (TTFB)

Your LCP can never load faster than your initial HTML document. If your Time to First Byte (TTFB) is 1.2 seconds, your LCP will inevitably be poor. Elementor sites require robust hosting and caching strategies to keep TTFB under 200ms.

Implement page caching and object caching

Ensure you have a page caching layer active. If your host does not provide server-level caching (like Nginx FastCGI cache or LiteSpeed Cache), use a plugin like WP Rocket or Cache Enabler.

Additionally, enable Redis or Memcached on your server to cache database queries. This prevents Elementor from querying the database for global settings and page metadata on every single request.

Optimize your database

Elementor saves a new revision every time you update a page. Over time, these revisions clutter your database, slowing down queries. Run this WP-CLI command to clean up old revisions:

wp post delete $(wp post list --post_type=revision --format=ids) --force

Alternatively, limit the number of revisions WordPress keeps by adding this line to your wp-config.php file:

define( 'WP_POST_REVISIONS', 5 );

Checklist

  • Identify the LCP element using PageSpeed Insights or Chrome DevTools Performance panel.
  • Exclude the hero image from lazy-loading using the wp_get_attachment_image_attributes filter.
  • Preload the hero image URL in the document head using fetchpriority="high".
  • Turn on "Improved Asset Loading" and "Inline Font Icons" in Elementor Features.
  • Dequeue unused Elementor stylesheets and icon libraries using PHP hooks.
  • Apply font-display: swap to all custom and Google fonts.
  • Preload your primary local font files in WOFF2 format.
  • Convert legacy Elementor Sections and Columns to Flexbox Containers.
  • Clean up the WordPress database by limiting and deleting old post revisions.
  • Verify that your TTFB is under 200ms using a server-level caching solution.

Frequently asked questions

Why is my Elementor LCP so high even with optimization plugins?

Optimization plugins often apply blanket rules like lazy-loading to all images or delaying all JavaScript. If your hero image is lazy-loaded, or if critical CSS is delayed, your LCP score will drop. You must target the specific LCP element and exclude it from generic optimization scripts.

Does converting to Flexbox containers actually improve LCP?

Yes. Flexbox containers reduce the number of nested HTML tags (DOM depth) by up to 40%. A lighter DOM means the browser spends less time parsing HTML and calculating styles, which directly accelerates the rendering of your LCP element.

How do I find out which element is triggering my LCP?

Run your page through Google PageSpeed Insights or Chrome DevTools Lighthouse. Under the 'Diagnostics' section, look for 'Largest Contentful Paint element'. It will highlight the exact HTML element (usually an image or heading) that you need to optimize.

Reference documentation

Drafted with AI assistance. Code targets current WordPress, WooCommerce and Next.js APIs; test changes on a staging site before production.

Need a fast, modern website?

I'm Sheraz Ahmad, a senior WordPress and headless Next.js developer with 7+ years of shipping high-performance sites. Open to permanent roles, contracts and freelance projects.

Let's talk