Plugin Directory

Changeset 3437321


Ignore:
Timestamp:
01/12/2026 01:59:30 AM (3 months ago)
Author:
jrmora
Message:

Release 1.1.9 - Added Visual CLS Highlighter and technical guide

Location:
speed-auditor
Files:
11 added
7 edited

Legend:

Unmodified
Added
Removed
  • speed-auditor/trunk/assets/css/speed-auditor-admin.css

    r3435389 r3437321  
    1 /* Color del semáforo en la Admin Bar */
     1/* Colores de la Admin Bar */
    22#wp-admin-bar-sa-analyze.sa-ok .ab-icon:before { color: #46b450 !important; }
    33#wp-admin-bar-sa-analyze.sa-warning .ab-icon:before { color: #ffb900 !important; }
    44#wp-admin-bar-sa-analyze.sa-critical .ab-icon:before { color: #f44336 !important; }
     5
     6/* Cajas de CLS */
     7.sa-cls-box {
     8    position: absolute;
     9    border: 2px dashed #f44336;
     10    background: rgba(244, 67, 54, 0.1);
     11    z-index: 2147483647;
     12    pointer-events: none;
     13    box-sizing: border-box;
     14}
     15
     16.sa-cls-label {
     17    position: absolute;
     18    top: -24px;
     19    left: -2px;
     20    background: #c62828 !important;
     21    color: #ffffff !important;
     22    font-size: 11px !important;
     23    padding: 3px 8px !important;
     24    white-space: nowrap;
     25    font-family: 'Courier New', Courier, monospace !important;
     26    pointer-events: auto;
     27    font-weight: 600 !important;
     28    letter-spacing: 0.5px;
     29    border-radius: 2px 0 0 2px;
     30}
     31
     32.sa-cls-close {
     33    position: absolute;
     34    top: -24px;
     35    right: -2px;
     36    background: #000 !important;
     37    width: 20px !important;
     38    height: 20px !important;
     39    cursor: pointer;
     40    pointer-events: auto;
     41    border-radius: 0 2px 2px 0;
     42    display: block !important;
     43}
     44
     45.sa-cls-close::before {
     46    content: "×" !important;
     47    position: absolute; top: 50%; left: 50%;
     48    transform: translate(-50%, -50%);
     49    color: #fff !important; font-size: 18px; font-weight: bold;
     50    font-family: Arial, sans-serif;
     51}
     52
     53/* ESTADO ACTIVO DEL BOTÓN EN ADMIN BAR */
     54#wp-admin-bar-sa-cls-visualizer.sa-visualizer-on > .ab-item {
     55    background-color: #00a32a !important; /* Verde Esmeralda */
     56    color: #ffffff !important; /* Texto en blanco */
     57    font-weight: bold !important;
     58}
     59
     60/* Forzamos el icono del ojo en blanco */
     61#wp-admin-bar-sa-cls-visualizer.sa-visualizer-on > .ab-item::before {
     62    content: "\f177" !important; /* Icono Ojo */
     63    font-family: dashicons !important;
     64    margin-right: 6px;
     65    vertical-align: middle;
     66    color: #ffffff !important; /* Icono en blanco para máximo contraste */
     67    opacity: 1 !important;
     68}
  • speed-auditor/trunk/assets/js/speed-auditor.js

    r3436874 r3437321  
    11(function($) {
     2    // No ejecutar si estamos en el backend
    23    if ($('body').hasClass('wp-admin')) { return; }
    34
    45    let lcpRef = null;
    56    let clsValue = 0;
     7    let clsEntries = [];
     8    let removedNodes = new Set();
     9    let visualizerActive = localStorage.getItem('sa_cls_active') === 'true';
    610
     11    // 1. Monitoreo de Core Web Vitals (LCP y CLS)
    712    if ('PerformanceObserver' in window) {
    813        try {
     14            // Observador para LCP y actualización del icono en Admin Bar [cite: 4, 6, 43]
    915            new PerformanceObserver((list) => {
    1016                const entries = list.getEntries();
     
    2026                        else if (noPriority) $btn.addClass('sa-warning');
    2127                        else $btn.addClass('sa-ok');
    22                     } else { $btn.addClass('sa-ok'); }
     28                    } else {
     29                        $btn.addClass('sa-ok');
     30                    }
    2331                }
    2432            }).observe({ type: 'largest-contentful-paint', buffered: true });
    2533
     34            // Observador para CLS y recolección de fuentes de desplazamiento
    2635            new PerformanceObserver((list) => {
    2736                for (const entry of list.getEntries()) {
    28                     if (!entry.hadRecentInput) clsValue += entry.value;
     37                    if (!entry.hadRecentInput) {
     38                        clsValue += entry.value;
     39                        if (entry.sources) {
     40                            entry.sources.forEach(s => {
     41                                if(s.node && s.node.nodeType === 1) {
     42                                    clsEntries.push({node: s.node, value: entry.value});
     43                                }
     44                            });
     45                        }
     46                    }
    2947                }
     48                if (visualizerActive) drawBoxes();
    3049            }).observe({ type: 'layout-shift', buffered: true });
    3150        } catch (e) {}
    3251    }
    3352
    34     $(document).on('click', '.sa-analyze-button', function(e) {
    35         e.preventDefault();
     53    $(document).ready(function() {
     54        if (visualizerActive) {
     55            $('#wp-admin-bar-sa-cls-visualizer').addClass('sa-visualizer-on');
     56            $(window).on('scroll.sa resize.sa', drawBoxes);
     57        }
     58    });
     59
     60    // 2. Lógica del Botón de Auditoría e Informe Técnico [cite: 3, 9]
     61    $(document).on('click', '.sa-analyze-button > a', function(e) {
     62        // Evitar que el clic en el botón principal dispare el toggle de CLS
     63        if ($(e.target).closest('.sa-cls-toggle').length) return;
     64        e.preventDefault(); e.stopPropagation();
     65       
    3666        const now = new Date();
    3767        const pageSlug = window.location.pathname.replace(/\//g, '') || 'home';
    3868        const fileName = `audit_${pageSlug}_${now.toISOString().slice(0,10)}.txt`;
    3969
    40         let r = "SPEED AUDITOR - TECHNICAL REPORT\n========================================\n\n";
    41         r += "URL: " + window.location.href + "\nDate: " + now.toLocaleString() + "\n\n";
     70        let r = "SPEED AUDITOR - TECHNICAL REPORT\n";
     71        r += "========================================\n\n";
     72        r += "URL: " + window.location.href + "\n";
     73        r += "Date: " + now.toLocaleString() + "\n\n";
    4274
     75        // --- ESTRUCTURA DEL DOM  ---
    4376        r += "1. DOM STRUCTURE\n----------------------------------------\n";
    4477        const allNodes = document.getElementsByTagName('*');
    4578        r += "Total Nodes: " + allNodes.length + (allNodes.length > 1500 ? " [!] High node count\n" : " [OK]\n");
     79       
    4680        let maxDepth = 0;
    4781        function getDepth(el) {
    48             let depth = 0; while (el.parentElement) { el = el.parentElement; depth++; } return depth;
     82            let depth = 0;
     83            while (el.parentElement) { el = el.parentElement; depth++; }
     84            return depth;
    4985        }
    50         for (let n of allNodes) { const d = getDepth(n); if (d > maxDepth) maxDepth = d; }
     86        for (let n of allNodes) {
     87            const d = getDepth(n);
     88            if (d > maxDepth) maxDepth = d;
     89        }
    5190        r += "Max DOM Depth: " + maxDepth + (maxDepth > 15 ? " [!] Deep nesting detected\n" : " [OK]\n");
    5291
     92        // --- DISTRIBUCIÓN POR ZONAS  ---
    5393        r += "\n2. DOM ZONES (Node Distribution)\n----------------------------------------\n";
    5494        const headerNodes = $('header').find('*').length || 0;
     
    5797        r += `Header: ${headerNodes} nodes\nMain Content: ${mainNodes} nodes\nFooter: ${footerNodes} nodes\n`;
    5898
     99        // --- LATENCIA DE MEDIOS  ---
    59100        r += "\n3. MEDIA LATENCY (Top 5 Slowest Images)\n----------------------------------------\n";
    60101        const resources = performance.getEntriesByType('resource');
     
    62103            .filter(res => res.initiatorType === 'img' || (res.name.match(/\.(jpg|jpeg|png|webp|gif|svg)/)))
    63104            .map(img => ({ name: img.name.split('/').pop(), time: Math.round(img.duration), type: img.initiatorType }))
    64             .sort((a, b) => b.time - a.time).slice(0, 5);
     105            .sort((a, b) => b.time - a.time)
     106            .slice(0, 5);
    65107
    66108        if (images.length > 0) {
     
    71113        } else { r += "No image resources detected.\n"; }
    72114
     115        // --- CORE WEB VITALS [cite: 6, 35, 36, 51] ---
    73116        r += "\n4. CORE WEB VITALS (LCP & CLS)\n----------------------------------------\n";
    74117        if (lcpRef) {
    75             const isImg = lcpRef.tagName === 'IMG' || lcpRef.tagName === 'PICTURE';
    76             r += "LCP Element: " + getSelector(lcpRef) + "\n";
    77             if (isImg) {
    78                 const isLazy = lcpRef.getAttribute('loading') === 'lazy';
    79                 const noPriority = lcpRef.getAttribute('fetchpriority') !== 'high';
    80                 r += "LCP Type: Image\n";
    81                 r += "LCP Lazy Load: " + (isLazy ? "[!] BAD: LCP images should not be lazy loaded." : "[OK] Correct.") + "\n";
    82                 r += "LCP Priority: " + (!noPriority ? "[OK] High Priority detected." : "[!] WARNING: Standard priority.") + "\n";
    83                
    84                 if (isLazy || noPriority) {
    85                     r += "\n>>> HOW TO FIX THE ORANGE/RED ICON:\n";
    86                     if (isLazy) {
    87                         r += "- ACTION: Remove 'loading=\"lazy\"' from this specific element. Lazy loading the LCP element delays its discovery, which significantly hurts your LCP score. It should be one of the first things the browser downloads.\n";
    88                     }
    89                     if (noPriority) {
    90                         r += "- ACTION: Add 'fetchpriority=\"high\"' to this image tag. This tells the browser to prioritize this image over others, reducing the time it takes to render the main content and helping you achieve a 'Green' status.\n";
    91                     }
    92                 }
    93             } else { r += "LCP Type: Text/Block [OK]\n"; }
    94         } else { r += "LCP Element: Not detected yet.\n"; }
    95         r += "\nCLS Score: " + clsValue.toFixed(4) + (clsValue > 0.1 ? " [!] Review layout shifts (visual instability)." : " [OK] Visual stability is good.") + "\n\n";
     118            let selector = lcpRef.tagName.toLowerCase();
     119            if (lcpRef.id) selector = '#' + lcpRef.id;
     120            else if (lcpRef.className) selector += '.' + lcpRef.className.split(' ').join('.');
     121           
     122            r += "LCP Element: " + selector + "\n";
     123            r += "LCP Lazy Load: " + (lcpRef.getAttribute('loading') === 'lazy' ? "[!] BAD: Do not use lazy load on LCP" : "[OK] Correct") + "\n";
     124            r += "LCP Priority: " + (lcpRef.getAttribute('fetchpriority') === 'high' ? "[OK] High" : "[!] Tip: Use fetchpriority='high'") + "\n";
     125        } else {
     126            r += "LCP Element: Not detected yet (Wait for full load).\n";
     127        }
     128        r += "CLS Total Score: " + clsValue.toFixed(4) + (clsValue > 0.1 ? " [!] Review layout shifts" : " [OK]") + "\n\n";
    96129
    97         r += "----------------------------------------\nFOR DETAILED GUIDELINES AND OPTIMIZATION TIPS:\n";
    98         r += "Visit 'Tools > Speed Auditor' in your WordPress Dashboard.\n----------------------------------------\n";
     130        r += "----------------------------------------\n";
     131        r += "FOR DETAILED GUIDELINES AND OPTIMIZATION TIPS:\n";
     132        r += "Visit 'Tools > Speed Auditor' in your WordPress Dashboard.\n";
     133        r += "----------------------------------------\n";
    99134        r += "Generated: " + now.toLocaleString() + "\n";
    100135
     
    102137        const link = document.createElement('a');
    103138        link.href = URL.createObjectURL(blob);
    104         link.download = fileName; link.click();
     139        link.download = fileName;
     140        link.click();
    105141    });
    106142
    107     function getSelector(el) {
    108         if (el.id) return '#' + el.id;
    109         let selector = el.tagName.toLowerCase();
    110         if (el.className) selector += '.' + el.className.split(' ').join('.');
    111         return selector;
     143    // 3. Lógica del Visualizador CLS [cite: 31, 33, 46]
     144    $(document).on('click', '.sa-cls-toggle', function(e) {
     145        e.preventDefault(); e.stopPropagation();
     146        visualizerActive = !visualizerActive;
     147        localStorage.setItem('sa_cls_active', visualizerActive);
     148        $('#wp-admin-bar-sa-cls-visualizer').toggleClass('sa-visualizer-on', visualizerActive);
     149       
     150        if (visualizerActive) {
     151            removedNodes.clear();
     152            drawBoxes();
     153            $(window).on('scroll.sa resize.sa', drawBoxes);
     154        } else {
     155            $('.sa-cls-box').remove();
     156            $(window).off('scroll.sa resize.sa');
     157        }
     158    });
     159
     160    function drawBoxes() {
     161        if (!visualizerActive) return;
     162        $('.sa-cls-box').remove();
     163        const processed = new Set();
     164        clsEntries.forEach(item => {
     165            if (!item.node || processed.has(item.node) || removedNodes.has(item.node)) return;
     166            const rect = item.node.getBoundingClientRect();
     167            if (rect.width > 0 && rect.height > 0) {
     168                processed.add(item.node);
     169                const $box = $('<div class="sa-cls-box"></div>').css({
     170                    top: rect.top + window.scrollY, left: rect.left + window.scrollX,
     171                    width: rect.width, height: rect.height
     172                }).data('node-ref', item.node);
     173                $box.append(`<span class="sa-cls-label">${item.node.tagName.toLowerCase()} | CLS: ${item.value.toFixed(4)}</span><span class="sa-cls-close"></span>`);
     174                $('body').append($box);
     175            }
     176        });
    112177    }
     178
     179    $(document).on('click', '.sa-cls-close', function(e) {
     180        e.preventDefault(); e.stopPropagation();
     181        const node = $(this).parent().data('node-ref');
     182        if (node) removedNodes.add(node);
     183        $(this).parent().remove();
     184    });
     185
    113186})(jQuery);
  • speed-auditor/trunk/readme.txt

    r3436874 r3437321  
    66Requires at least: 5.0
    77Tested up to: 6.9
    8 Stable tag: 1.1.8
     8Stable tag: 1.1.9
    99License: GPLv2 or later
    1010License URI: http://www.gnu.org/licenses/gpl-2.0.html
     
    1616Speed Auditor helps WordPress site owners identify performance bottlenecks in real-time while browsing their site. It generates a downloadable technical report that pinpoints critical elements for Core Web Vitals and structural efficiency.
    1717
     18Speed Auditor now includes a powerful **Visual CLS Highlighter**. Stop guessing which elements are causing layout shifts; activate the real-time radar from your Admin Bar to see problematic elements highlighted with red boxes as you browse.
     19
    1820Main Features:
     21* **Visual CLS Radar: Activate a real-time toggle to draw red boxes around elements causing layout shifts. Perfect for catching unstable ads, images, or jumping text.
    1922* **Visual Performance Signal:** Real-time color-coded icons (Green/Yellow/Red) in the Admin Bar based on LCP optimization status.
    2023* **Technical Knowledge Base:** New guide under Tools > Speed Auditor to help users understand metrics like DOM depth, LCP, and Media Latency.
     24* **Technical Glossary: A new built-in guide explaining HTML tags like <ins>, <div>, and <img> specifically in the context of CLS and performance.
    2125* **Accurate LCP Identification:** Detects the Largest Contentful Paint element and validates its optimization.
    2226* **Structural DOM Audit:** Breakdown of nodes by zones (Header, Content, Footer) and maximum nesting depth analysis.
     
    33374. Access the technical guide under Tools > Speed Auditor.
    3438
     39== Frequently Asked Questions ==
     40
     41= What does "ins" or "div" mean in the red boxes? =
     42These are HTML tags often used by ad networks like Google AdSense. If you see a red box labeled "ins", it means an advertisement is shifting your content and hurting your CLS score.
     43
     44= Why do the red boxes appear only after I scroll? =
     45The browser's Performance API often detects layout shifts only when the element enters the viewport or when dynamic content (like ads) is triggered by scrolling. This ensures the auditor shows you real-world user experience impacts.
     46
     47= Does the "Show CLS" feature affect my site speed? =
     48No. The visualizer only runs for logged-in administrators and uses the browser's native Performance API, which is extremely lightweight and has zero impact on your visitors.
     49
     50= How do I stop the red boxes from appearing? =
     51Simply click the "Show CLS" button again in the Admin Bar to toggle it off. The plugin will remember your preference for the next page you visit.
     52
    3553== Screenshots ==
    3654
    37 1. Real-time performance indicator in the Admin Bar. The icon changes color dynamically: Grey (Standby), Green (Optimal), Orange (Warning), and Red (Critical) based on LCP and DOM thresholds.
    38 2. Example of the technical report generated by the auditor including DOM zones and media latency.
    39 3. New Knowledge Base page under the Tools menu explaining performance thresholds.
     551. Visual CLS Radar: Highlighting unstable elements (ads, images, text) with red boxes directly on the site.
     562. Real-time performance indicator in the Admin Bar. The icon changes color dynamically (Green, Orange, Red) based on LCP health.
     573. Example of the technical report generated by the auditor including DOM zones and media latency.
     584. New technical glossary and knowledge base page under the Tools menu.
    4059
    4160== Changelog ==
     61
     62= 1.1.9 =
     63* New: Visual CLS Highlighter button. Added Toggle button in the Admin Bar to activate/deactivate visual boxes. Persistent visualizer mode using localStorage. Audit multiple pages seamlessly. Identify exactly which elements are moving on your page. Stop guessing which elements are moving; see them highlighted in red boxes.
     64* Improved: Boxes now follow elements during scroll and stay above ads using extreme z-index.
     65* New: Technical Glossary in the admin guide explaining HTML tags like <ins>, <div> and <img> in the context of CLS.
    4266
    4367= 1.1.8 =
     
    6286== Update Notice ==
    6387
     88= 1.1.9 =
     89Major Update. New visual tool! You can now highlight elements causing layout shifts (CLS) directly on your site from the Speed Auditor menu. Visualize your Layout Shifts! This version adds a real-time radar to catch elements that hurt your CLS score. Essential for sites using AdSense or dynamic content.
     90
    6491= 1.1.8 =
    6592This version improves the technical report with actionable tips to help you move from an Orange/Red icon to a Green one by optimizing your LCP elements.
  • speed-auditor/trunk/speed-auditor.php

    r3437019 r3437321  
    22/**
    33 * Plugin Name: Speed Auditor
    4  * Plugin URI:   https://jrmora.com/speed-auditor-descubre-frena-wordpress/
    5 
    64 * Description: Audit LCP, DOM structure, and image optimization directly from the admin bar. Includes a technical guide in Tools.
    7  * Version:     1.1.8
     5 * Version:     1.1.9
    86 * Author:      JRMora
    97 * Author URI:  https://jrmora.com
     
    1715function sa_enqueue_assets() {
    1816    if ( ! current_user_can( 'manage_options' ) ) { return; }
    19     wp_enqueue_style('sa-admin-styles', plugins_url( 'assets/css/speed-auditor-admin.css', __FILE__ ), array(), '1.1.8');
    20     wp_enqueue_script('speed-auditor-script', plugins_url( 'assets/js/speed-auditor.js', __FILE__ ), array( 'jquery' ), '1.1.8', true);
     17    wp_enqueue_style('sa-admin-styles', plugins_url( 'assets/css/speed-auditor-admin.css', __FILE__ ), array(), '1.1.9');
     18    wp_enqueue_script('speed-auditor-script', plugins_url( 'assets/js/speed-auditor.js', __FILE__ ), array( 'jquery' ), '1.1.9', true);
    2119}
    2220add_action( 'wp_enqueue_scripts', 'sa_enqueue_assets' );
     
    2725    $is_frontend = ! is_admin();
    2826    $button_class = $is_frontend ? 'sa-analyze-button' : 'sa-disabled-icon';
     27   
    2928    $wp_admin_bar->add_node( array(
    3029        'id'    => 'sa-analyze',
    3130        'title' => '<span class="ab-icon dashicons dashicons-performance"></span> ' . __( 'Speed Auditor', 'speed-auditor' ),
    3231        'href'  => '#',
    33         'meta'  => array(
    34             'class' => $button_class,
    35             'title' => $is_frontend ? __( 'Run performance audit', 'speed-auditor' ) : __( 'Speed Auditor (Frontend only)', 'speed-auditor' )
    36         ),
     32        'meta'  => array( 'class' => $button_class )
    3733    ));
     34
     35    if ($is_frontend) {
     36        $wp_admin_bar->add_node( array(
     37            'id'     => 'sa-cls-visualizer',
     38            'parent' => 'sa-analyze',
     39            'title'  => __( 'Show CLS', 'speed-auditor' ),
     40            'href'   => '#',
     41            'meta'   => array( 'class' => 'sa-cls-toggle' )
     42        ));
     43    }
    3844}, 100 );
    3945
     
    5157    ?>
    5258    <div class="wrap">
    53         <h1><?php esc_html_e( 'Speed Auditor: Technical Guide', 'speed-auditor' ); ?></h1>
    54         <p><?php esc_html_e( 'This guide explains the metrics analyzed in the real-time report.', 'speed-auditor' ); ?></p>
     59        <h1>
     60            <span class="dashicons dashicons-performance" style="font-size: 30px; width: 30px; height: 30px; margin-right: 10px;"></span>
     61            <?php esc_html_e( 'Speed Auditor: Technical Guide', 'speed-auditor' ); ?>
     62        </h1>
     63        <p style="font-size: 1.1em; color: #50575e;">
     64            <?php esc_html_e( 'This guide explains the metrics analyzed in the real-time report and the elements identified by the CLS visualizer.', 'speed-auditor' ); ?>
     65        </p>
     66
     67        <div class="sa-glossary-card" style="background: #fff; border: 1px solid #ccd0d4; border-left: 4px solid #c62828; padding: 20px; margin: 25px 0; border-radius: 4px; box-shadow: 0 1px 1px rgba(0,0,0,.04);">
     68            <h3 style="margin-top: 0; display: flex; align-items: center;">
     69                <span class="dashicons dashicons-editor-help" style="margin-right: 10px; color: #c62828;"></span>
     70                <?php echo __( 'CLS Element Glossary', 'speed-auditor' ); ?>
     71            </h3>
     72            <p style="color: #646970; font-size: 14px;">
     73                <?php echo __( 'When the "Show CLS" radar is active, the red boxes identify elements that moved. Here is what they mean:', 'speed-auditor' ); ?>
     74            </p>
     75
     76            <div style="display: grid; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); gap: 15px; margin-top: 15px;">
     77               
     78                <div style="background: #f6f7f7; padding: 12px; border-radius: 4px; border: 1px solid #e5e5e5;">
     79                    <strong style="font-family: monospace; font-size: 1.1em; color: #c62828;">ins / div</strong>
     80                    <p style="margin: 5px 0 0; font-size: 13px; color: #50575e;">
     81                        <?php echo __( 'Used by Google AdSense and ad managers. These usually shift when an ad is injected late into the layout.', 'speed-auditor' ); ?>
     82                    </p>
     83                </div>
     84
     85                <div style="background: #f6f7f7; padding: 12px; border-radius: 4px; border: 1px solid #e5e5e5;">
     86                    <strong style="font-family: monospace; font-size: 1.1em; color: #c62828;">img / picture</strong>
     87                    <p style="margin: 5px 0 0; font-size: 13px; color: #50575e;">
     88                        <?php echo __( 'Images missing width/height attributes. They cause content to "jump" once the file is downloaded.', 'speed-auditor' ); ?>
     89                    </p>
     90                </div>
     91
     92                <div style="background: #f6f7f7; padding: 12px; border-radius: 4px; border: 1px solid #e5e5e5;">
     93                    <strong style="font-family: monospace; font-size: 1.1em; color: #c62828;">iframe / video</strong>
     94                    <p style="margin: 5px 0 0; font-size: 13px; color: #50575e;">
     95                        <?php echo __( 'Third-party embeds (YouTube, Maps) that resize their container after initialization.', 'speed-auditor' ); ?>
     96                    </p>
     97                </div>
     98
     99                <div style="background: #f6f7f7; padding: 12px; border-radius: 4px; border: 1px solid #e5e5e5;">
     100                    <strong style="font-family: monospace; font-size: 1.1em; color: #c62828;">p / h1-h6 / span</strong>
     101                    <p style="margin: 5px 0 0; font-size: 13px; color: #50575e;">
     102                        <?php echo __( 'Text shifts caused by Web Fonts loading (FOUT) or dynamic content like "Related Posts".', 'speed-auditor' ); ?>
     103                    </p>
     104                </div>
     105
     106            </div>
     107
     108            <p style="margin-top: 20px; padding-top: 15px; border-top: 1px solid #f0f0f1; font-style: italic; font-size: 12px; color: #a7aaad;">
     109                <strong><?php echo __( 'Optimization Tip:', 'speed-auditor' ); ?></strong>
     110                <?php echo __( 'Elements with high CLS values should have a reserved space (min-height) in your CSS to prevent shifting.', 'speed-auditor' ); ?>
     111            </p>
     112        </div>
     113       
    55114        <div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 20px; margin-top: 20px;">
     115           
    56116            <div class="card" style="max-width: 100%; margin: 0; padding: 15px;">
    57117                <h2>1. DOM Structure & Depth</h2>
     
    59119                <p><strong><?php esc_html_e( 'Zone Breakdown:', 'speed-auditor' ); ?></strong> <?php esc_html_e( 'Shows node count in Header, Content, and Footer.', 'speed-auditor' ); ?></p>
    60120            </div>
     121
    61122            <div class="card" style="max-width: 100%; margin: 0; padding: 15px;">
    62123                <h2>2. Media Latency (Transfer Time)</h2>
     
    74135                </table>
    75136            </div>
     137
    76138            <div class="card" style="max-width: 100%; margin: 0; padding: 15px;">
    77                 <h2>3. LCP & CLS</h2>
     139                <h2>3. LCP & CLS Visualizer</h2>
    78140                <p><strong><?php esc_html_e( 'LCP (Largest Contentful Paint):', 'speed-auditor' ); ?></strong> <?php esc_html_e( 'Marks when the main content has likely loaded.', 'speed-auditor' ); ?></p>
    79                 <p><strong><?php esc_html_e( 'CLS (Cumulative Layout Shift):', 'speed-auditor' ); ?></strong> <?php esc_html_e( 'Measures visual stability. A score under 0.1 is good.', 'speed-auditor' ); ?></p>
     141                <p><strong><?php esc_html_e( 'CLS Visualizer:', 'speed-auditor' ); ?></strong> <?php esc_html_e( 'Use the "Show CLS" button in the frontend admin bar to highlight layout shifts.', 'speed-auditor' ); ?></p>
    80142            </div>
     143
    81144        </div>
     145
    82146        <p style="margin-top: 30px; border-top: 1px solid #ccc; padding-top: 10px;">
    83147            <?php esc_html_e( 'Looking for more optimization tips?', 'speed-auditor' ); ?>
Note: See TracChangeset for help on using the changeset viewer.