• Skip to secondary menu
  • Skip to main content
  • Skip to primary sidebar
  • Home
  • Projects
  • Products
  • Themes
  • Tools
  • Request for Quote

Vengala Vinay

Having 12+ Years of Experience in Software Development

  • Home
  • WordPress
  • PHP
    • Codeigniter
  • Django
  • Magento
  • Selenium
  • Server
Home » Optimizing Performance in Lazy Loading Assets and Critical CSS Optimizations for Optimized Core Web Vitals (LCP/INP)

Optimizing Performance in Lazy Loading Assets and Critical CSS Optimizations for Optimized Core Web Vitals (LCP/INP)

Diagnosing and Optimizing Lazy Loading for WordPress Assets

Lazy loading is a cornerstone of modern web performance, deferring the loading of non-critical assets until they are needed. In WordPress, this primarily applies to images and iframes. While native browser lazy loading is now widely supported, understanding its implementation and potential pitfalls is crucial for advanced optimization. We’ll start by diagnosing existing lazy loading behavior and then explore advanced techniques.

Inspecting Native Browser Lazy Loading

The first step is to verify if native lazy loading is actually being applied. Open your WordPress site in a browser, right-click on an image that is below the fold (not immediately visible without scrolling), and select “Inspect” or “Inspect Element.” Look for the loading="lazy" attribute on the <img> tag. If it’s absent, your theme or a plugin might be interfering, or you might be using an older WordPress version that doesn’t enable it by default (though this is rare now).

Conversely, if you see loading="lazy" but the image loads immediately, it might be considered “in the viewport” by the browser’s heuristics, or a JavaScript-based lazy loader is overriding it. To confirm if JavaScript is involved, disable JavaScript in your browser’s developer tools and reload the page. If images that were previously lazy-loaded now load instantly, a JavaScript solution is at play.

Advanced Lazy Loading Strategies and Code Snippets

While WordPress core handles native lazy loading for images and iframes since version 5.5, custom implementations or specific scenarios might require more granular control. For instance, you might want to exclude certain images or apply lazy loading to background images via CSS. Here’s how you can programmatically influence lazy loading behavior.

Programmatic Exclusion of Images from Native Lazy Loading

If you need to prevent specific images from being lazy-loaded (e.g., critical above-the-fold images that should load immediately), you can filter the wp_img_tag_attributes hook. This hook allows you to modify attributes of image tags before they are rendered.

/**
 * Exclude specific images from native lazy loading.
 *
 * @param array  $attr       The HTML attributes for the image tag.
 * @param WP_Post $post       The post object.
 * @param int    $attachment_id The attachment ID.
 * @param bool   $size       The image size.
 * @param bool   $icon       Whether to include the icon.
 * @return array Modified attributes.
 */
function my_exclude_images_from_lazy_load( $attr, $post, $attachment_id, $size, $icon ) {
    // Example: Exclude images with a specific CSS class.
    if ( isset( $attr['class'] ) && strpos( $attr['class'], 'no-lazy-load' ) !== false ) {
        $attr['loading'] = 'eager'; // Or simply remove the attribute to let browser default.
    }

    // Example: Exclude images that are the first image in a post's content.
    // This is more complex and might require parsing content.
    // For simplicity, let's assume we're targeting a specific image ID.
    $specific_image_id_to_exclude = 123; // Replace with actual image ID.
    if ( $attachment_id === $specific_image_id_to_exclude ) {
        $attr['loading'] = 'eager';
    }

    return $attr;
}
add_filter( 'wp_img_tag_attributes', 'my_exclude_images_from_lazy_load', 10, 5 );

To use this, add the PHP code to your theme’s functions.php file or a custom plugin. For class-based exclusion, add the class no-lazy-load to your <img> tags. For ID-based exclusion, replace 123 with the actual Media Library ID of the image you want to exempt.

Lazy Loading Background Images (CSS-based)

Native lazy loading is for <img> and <iframe> tags. For background images defined in CSS, you’ll need a JavaScript-based solution. A common approach is to use a Intersection Observer API to detect when an element with a background image enters the viewport and then apply the actual background image URL.

First, mark your elements with a placeholder or a low-resolution image and a data attribute containing the actual background image URL.

<div class="lazy-background" data-bg-image-url="https://example.com/path/to/your/high-res-image.jpg"></div>

Then, use JavaScript to observe these elements and apply the background image.

document.addEventListener("DOMContentLoaded", function() {
    var lazyBackgrounds = document.querySelectorAll(".lazy-background");

    if ("IntersectionObserver" in window) {
        var lazyBackgroundObserver = new IntersectionObserver(function(entries, observer) {
            entries.forEach(function(entry) {
                if (entry.isIntersecting) {
                    entry.target.style.backgroundImage = "url(" + entry.target.dataset.bgImageUrl + ")";
                    entry.target.classList.add("loaded"); // Optional: add a class for styling loaded state
                    lazyBackgroundObserver.unobserve(entry.target);
                }
            });
        });

        lazyBackgrounds.forEach(function(lazyBg) {
            lazyBackgroundObserver.observe(lazyBg);
        });
    } else {
        // Fallback for browsers that don't support IntersectionObserver
        lazyBackgrounds.forEach(function(lazyBg) {
            lazyBg.style.backgroundImage = "url(" + lazyBg.dataset.bgImageUrl + ")";
            lazyBg.classList.add("loaded");
        });
    }
});

This script should be enqueued properly in WordPress using wp_enqueue_script and should depend on wp-util if you need access to WordPress’s AJAX utilities or other core scripts. Ensure it’s loaded asynchronously or deferred to avoid blocking rendering.

Critical CSS: Isolating and Inlining for Optimized Core Web Vitals

Critical CSS refers to the minimal set of CSS rules required to render the above-the-fold content of a webpage. Inlining this critical CSS directly into the <head> of your HTML document allows the browser to render the initial view of the page much faster, significantly improving perceived load time and metrics like Largest Contentful Paint (LCP) and Interaction to Next Paint (INP).

Identifying Critical CSS

Manually identifying critical CSS is tedious and error-prone. Several tools can automate this process:

  • Penthouse: A popular Node.js module that uses a headless browser (like Chrome) to analyze your page and extract the CSS needed for the viewport.
  • CriticalCSS (Python): Similar to Penthouse, this Python library can generate critical CSS.
  • Online Tools: Websites like jonathan.dev/critical-css-generator or uncss-online.com offer web-based interfaces.

The general workflow involves pointing the tool to a specific URL and defining the viewport dimensions. The tool then renders the page, captures the CSS used for that viewport, and outputs it.

Implementing Critical CSS in WordPress

The most effective way to implement critical CSS in WordPress is by inlining it within the wp_head action. This ensures it’s delivered as early as possible.

Method 1: Manual Inlining (for static critical CSS)

If your critical CSS is relatively static and doesn’t change drastically per page template, you can generate it once and hardcode it into your theme’s header.php or via a function in functions.php hooked to wp_head.

/**
 * Inline critical CSS.
 */
function my_inline_critical_css() {
    // Ensure this is only for the front-end and not during AJAX requests etc.
    if ( is_admin() || wp_doing_ajax() || wp_is_block_editor() ) {
        return;
    }

    // Replace with your actual generated critical CSS.
    $critical_css = "
        /* Critical CSS for above-the-fold content */
        body { font-family: sans-serif; margin: 0; }
        .header { background-color: #f0f0f0; padding: 20px; }
        .hero-section { background-image: url('path/to/hero-bg.jpg'); height: 400px; display: flex; justify-content: center; align-items: center; }
        .hero-title { font-size: 2.5em; color: #333; }
        /* ... more critical styles ... */
    ";

    echo '<style id="critical-css">' . $critical_css . '</style>';
}
add_action( 'wp_head', 'my_inline_critical_css', 0 ); // Priority 0 to ensure it's very early.

Important Considerations:

  • Minification: Ensure the inlined CSS is minified to reduce its size.
  • Caching: This inline CSS is served with every HTML request. If it changes frequently, it can impact caching efficiency.
  • Viewport Specificity: The critical CSS should be generated for the most common viewport sizes (e.g., desktop).

Method 2: Dynamic Critical CSS Generation (Advanced)

For highly dynamic sites or when you need to generate critical CSS per page template or even per page, you can integrate a tool like Penthouse into your build process or use a server-side script. This is significantly more complex and often involves a custom plugin or a sophisticated build pipeline.

A simplified server-side approach might look like this (conceptual Python example, not directly runnable in WordPress without a framework):

import requests
from bs4 import BeautifulSoup
# Assume 'penthouse' or a similar library is installed and configured
# from penthouse import Penthouse

def get_critical_css(url, width, height):
    # In a real scenario, you'd use a headless browser like Puppeteer or Playwright
    # to render the page and then extract CSS. Penthouse does this.
    # This is a placeholder for the actual critical CSS generation logic.
    try:
        # Example using a hypothetical Penthouse call
        # critical_css_output = Penthouse(url=url, css='path/to/your/main.css', width=width, height=height).generate()
        # return critical_css_output

        # For demonstration, let's simulate fetching and parsing
        response = requests.get(url)
        response.raise_for_status()
        soup = BeautifulSoup(response.text, 'html.parser')
        
        # This is NOT actual critical CSS generation. It's a placeholder.
        # Real critical CSS generation involves analyzing computed styles.
        styles = soup.find_all('style')
        all_css = "".join([s.string for s in styles if s.string])
        
        # Placeholder: In reality, you'd use a tool to extract only above-the-fold CSS.
        # For now, we'll just return a snippet.
        return "/* Placeholder critical CSS for " + url + " */\nbody { margin: 0; }"

    except Exception as e:
        print(f"Error generating critical CSS: {e}")
        return ""

# Example usage within a WordPress context (conceptual)
# This would typically be triggered by a hook or a request to a specific endpoint.
# For instance, you might have a WP REST API endpoint that returns critical CSS.

# if __name__ == "__main__":
#     page_url = "https://your-wordpress-site.com/"
#     viewport_width = 1200
#     viewport_height = 800
#     critical_styles = get_critical_css(page_url, viewport_width, viewport_height)
#
#     # In WordPress, you'd hook this into wp_head
#     # echo '';
#     print(critical_styles)

To implement this dynamically in WordPress, you could:

  • Create a WP REST API Endpoint: Expose an endpoint that takes a URL and viewport dimensions, runs the critical CSS generation, and returns the CSS. Your theme’s functions.php would then fetch this dynamically.
  • Server-Side Caching: Store generated critical CSS in a transient or custom database table to avoid regenerating it on every request.
  • Build Process Integration: Use tools like Gulp or Webpack with Penthouse during your theme/plugin development to pre-generate critical CSS for key templates and include them as static files.

Deferring Non-Critical CSS

Once critical CSS is inlined, all other CSS files should be deferred. This prevents them from blocking the initial rendering of the page. The standard method is to remove the media="all" (or similar) attribute and replace it with media="print", then use JavaScript to change it to media="all" once the page has loaded.

/**
 * Defer loading of non-critical CSS.
 */
function my_defer_non_critical_css( $html, $handle, $href, $media ) {
    // Only defer stylesheets that are not critical.
    // You might need a more sophisticated way to identify critical vs non-critical.
    // For simplicity, we'll defer all external stylesheets here.
    // You can add checks based on $handle if you know which ones are critical.

    if ( 'stylesheet' === $media && ! empty( $href ) && strpos( $href, is_ssl() ? 'https://' : 'http://' ) === 0 ) {
        // Add 'media="print"' and a 'onload' event handler via JavaScript.
        $html = str_replace( "media='all'", "media='print'", $html );
        $html = str_replace( "media=\"all\"", "media='print'", $html ); // Handle double quotes too
        $html .= "<script>
            (function(d, h, s) {
                var l = d.createElement('link'); l.rel = 'stylesheet';
                l.href = s; l.media = 'only x'; d.head.appendChild(l);
                function r() {
                    if (l.media !== 'only x') {
                        if (l.media === 'all') {
                            d.body.removeChild(l);
                        } else {
                            var n = d.createElement('link'); n.rel = 'stylesheet';
                            n.href = s; d.head.appendChild(n); l.media = 'all';
                        }
                    }
                }
                l.onload = r;
                setTimeout(r, 3000); // Fallback for browsers that don't support onload
            })(document, 'head', '" . esc_url( $href ) . "');
        </script>";
    }

    return $html;
}
add_filter( 'style_loader_tag', 'my_defer_non_critical_css', 10, 4 );

This script modifies the output of wp_enqueue_style. It changes the media attribute to print and appends a small JavaScript snippet. This snippet creates a new link element with media="only x", which effectively hides the stylesheet. When the stylesheet loads (detected by l.onload or a timeout), the media attribute is changed to all, making the CSS visible. The setTimeout acts as a fallback for browsers that might not fire the onload event reliably.

Advanced Diagnostics for LCP and INP

Optimizing lazy loading and critical CSS directly impacts LCP and INP. Here’s how to diagnose issues:

Largest Contentful Paint (LCP)

LCP measures the time it takes for the largest content element (image, video, or text block) within the viewport to become visible.

Common Causes & Diagnostics:

  • Slow Server Response Time: Use tools like GTmetrix, WebPageTest, or Chrome DevTools (Network tab) to check the Time To First Byte (TTFB). If TTFB is high, optimize your server, database, or use a better hosting provider.
  • Render-Blocking Resources: Critical CSS inlining and deferring non-critical CSS directly address this. Use the Performance tab in Chrome DevTools to record a page load and look for long tasks or blocking scripts/styles.
  • Slow Resource Load Time: If the LCP element itself is a large image, ensure it’s optimized (compressed, correct format like WebP) and served efficiently (CDN, HTTP/2 or HTTP/3).
  • Lazy Loading Interference: If your LCP element is an image that’s being lazy-loaded incorrectly (e.g., it’s below the fold but the browser thinks it’s in the viewport, or it’s an image that *should* be LCP but is deferred), you need to adjust your lazy loading exclusions.

Interaction to Next Paint (INP)

INP measures the latency of all user interactions (clicks, taps, key presses) throughout the page’s lifecycle. It aims to capture the responsiveness of the page.

Common Causes & Diagnostics:

  • Long JavaScript Tasks: This is the most common culprit. Heavy JavaScript execution, especially in the main thread, blocks user interactions. Use the Performance tab in Chrome DevTools to identify long tasks (tasks taking over 50ms).
  • Inefficient Event Handlers: Complex or unoptimized event handlers can lead to high INP. Ensure event listeners are attached efficiently (e.g., using event delegation) and that the code within them is performant.
  • Third-Party Scripts: External scripts (analytics, ads, widgets) can often hog the main thread. Audit and defer or lazy-load these scripts where possible.
  • CSS Rendering: While less common than JS, complex CSS or frequent style recalculations can contribute to INP.
  • Lazy Loading Scripts: If your lazy loading implementation relies on heavy JavaScript, it could impact INP. Ensure your Intersection Observer implementation is efficient and that fallback mechanisms are not overly burdensome.

By systematically diagnosing these areas and implementing the advanced techniques for lazy loading and critical CSS, you can significantly enhance your WordPress site’s performance and achieve better Core Web Vitals scores.

Primary Sidebar

A little about the Author

Having 12+ Years of Experience in Software Development, Vinay is a principal software architect, senior systems engineer, and elite technical consultant. He specializes in bespoke PHP/WordPress development, high-performance Magento 2 & Shopify architectures, custom plugin/theme development from scratch, and legacy code modernization (including VB6, VB.NET, PyQt, and Crystal Reports). Known for solving complex database bottlenecks, speed optimization (Core Web Vitals), and advanced security code auditing, Vinay engineers production-ready systems designed to scale under heavy concurrent load conditions.



Chat on WhatsApp

Recent Posts

  • Top 100 Automated PDF & Document Generation Tool Ideas for Developers that Will Dominate the Software Industry in 2026
  • Top 5 Automated PDF & Document Generation Tool Ideas for Developers in Highly Competitive Technical Niches
  • Top 50 Automated PDF & Document Generation Tool Ideas for Developers without Relying on Paid Advertising Budgets
  • Top 50 Automated PDF & Document Generation Tool Ideas for Developers to Double User Engagement and Session Duration
  • Building a Reactive Frontend Framework inside Theme Security Auditing: Mitigating XSS, CSRF, and SQLi Vulnerabilities under Heavy Concurrent Load Conditions

Categories

  • apache (1)
  • Business & Monetization (390)
  • Centos (4)
  • Comparisons & Decision Making (55)
  • Debian (2)
  • Debugging & Troubleshooting (580)
  • DevOps (7)
  • DevOps & Cloud Scaling (955)
  • Django (1)
  • Migration & Architecture (185)
  • MySQL (1)
  • Performance & Optimization (779)
  • PHP (5)
  • Plugins & Themes (239)
  • Security & Compliance (543)
  • SEO & Growth (488)
  • Server (23)
  • Ubuntu (9)
  • WordPress (22)
  • WordPress Plugin Development (7)
  • WordPress Theme Development (343)

Recent Posts

  • Top 100 Automated PDF & Document Generation Tool Ideas for Developers that Will Dominate the Software Industry in 2026
  • Top 5 Automated PDF & Document Generation Tool Ideas for Developers in Highly Competitive Technical Niches
  • Top 50 Automated PDF & Document Generation Tool Ideas for Developers without Relying on Paid Advertising Budgets
  • Top 50 Automated PDF & Document Generation Tool Ideas for Developers to Double User Engagement and Session Duration
  • Building a Reactive Frontend Framework inside Theme Security Auditing: Mitigating XSS, CSRF, and SQLi Vulnerabilities under Heavy Concurrent Load Conditions
  • Deep Dive: Memory Leak Prevention in Virtual CSS Variables and Dynamic Style Interpolation Using Custom Action and Filter Hooks

Top Categories

  • DevOps & Cloud Scaling (955)
  • Performance & Optimization (779)
  • Debugging & Troubleshooting (580)
  • Security & Compliance (543)
  • SEO & Growth (488)
  • Business & Monetization (390)

Our Products

  • School Management & Student Administration System
  • Integrated Hospital & Clinic Management System
  • Real Estate Directory & Agent Portal
  • Restaurant POS & Table Booking System
  • Retail Inventory POS & Billing System
  • Pharmacy Inventory & Clinic Billing System

Our Services

  • Vibe Engineering & AI Code Auditing Services
  • Prompt Engineering & "Vibe Coding" Workflow Consulting
  • AI-Augmented "Vibe Coding" & Rapid MVP Development
  • Figma to Shopify Liquid Theme Customization
  • Figma to WooCommerce Frontend Development
  • Figma to Magento 2 Theme Development

Copyright © 2026 · Vinay Vengala