feat(critical-css): implementar TIPO 4 y TIPO 5 - CSS Below-the-fold y Lazy Loading

## TIPO 4: CSS Below-the-fold (Critical Variables + Responsive)
- Inyecta variables CSS críticas inline en wp_head P:-1
- Inyecta media queries críticas inline en wp_head P:2 (corregido de P:1)
- Auto-regeneración cuando archivos fuente cambian (filemtime check)
- Cache en Assets/CriticalCSS/ para evitar lecturas repetidas
- Comando WP-CLI: wp roi-theme generate-critical-css

Archivos TIPO 4:
- Public/CriticalCSS/Domain/Contracts/ - Interfaces (DIP)
- Public/CriticalCSS/Application/UseCases/GetCriticalCSSUseCase.php
- Public/CriticalCSS/Infrastructure/Cache/CriticalCSSFileCache.php
- Public/CriticalCSS/Infrastructure/Services/CriticalCSSExtractor.php
- Public/CriticalCSS/Infrastructure/Services/CriticalCSSInjector.php
- bin/generate-critical-css.php

## TIPO 5: CSS No Crítico (Lazy Loading)
- Animaciones CSS: carga 2s después de page load via requestIdleCallback
- Print CSS: carga solo al imprimir via beforeprint event
- Fallback <noscript> para usuarios sin JavaScript
- Safari fallback: setTimeout cuando requestIdleCallback no disponible

Archivos TIPO 5:
- Assets/Js/lazy-css-loader.js
- Public/LazyCSSLoader/Infrastructure/Contracts/LazyCSSRegistrarInterface.php
- Public/LazyCSSLoader/Infrastructure/Services/LazyCSSRegistrar.php

## Fix: Colisión de prioridades wp_head
Antes: TIPO 1 (P:1), TIPO 4 responsive (P:1), TIPO 3 (P:2) - CONFLICTO
Después: TIPO 1 (P:1), TIPO 4 responsive (P:2), TIPO 3 (P:3) - OK

Nuevo orden de prioridades:
P:-1 roi-critical-variables (TIPO 4)
P:0  roi-critical-bootstrap (TIPO 2)
P:1  roi-critical-css (TIPO 1)
P:2  roi-critical-responsive (TIPO 4)
P:3  roi-custom-critical-css (TIPO 3)
P:5  roi-theme-layout-css (ThemeSettings)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
FrankZamora
2025-12-01 23:06:12 -06:00
parent e1923b630d
commit e01605ec37
15 changed files with 961 additions and 17 deletions

View File

@@ -0,0 +1,135 @@
/**
* TIPO 5: Lazy CSS Loader
*
* Carga CSS no critico despues del evento load usando:
* - requestIdleCallback para CSS de baja prioridad
* - Event listeners para CSS condicional
*
* @package ROITheme
* @since 1.0.20
*/
(function() {
'use strict';
// Configuracion de CSS lazy (inyectada desde PHP)
var config = window.roiLazyCSSConfig || {
baseUrl: '',
version: '1.0.0',
idleTimeout: 2000,
cssFiles: []
};
/**
* Carga un archivo CSS de forma asincrona
*
* @param {string} href URL del archivo CSS
* @param {string} id ID del elemento link
* @returns {Promise}
*/
function loadCSS(href, id) {
// Evitar duplicados
if (document.getElementById(id)) {
return Promise.resolve();
}
return new Promise(function(resolve, reject) {
var link = document.createElement('link');
link.id = id;
link.rel = 'stylesheet';
link.href = href;
link.onload = resolve;
link.onerror = reject;
document.head.appendChild(link);
});
}
/**
* Carga CSS cuando el navegador esta idle
*
* @param {Array} files Lista de archivos a cargar
*/
function loadOnIdle(files) {
var load = function() {
files.forEach(function(file) {
loadCSS(
config.baseUrl + file.path + '?ver=' + config.version,
'roi-lazy-' + file.id
);
});
};
if ('requestIdleCallback' in window) {
requestIdleCallback(load, { timeout: config.idleTimeout });
} else {
// Fallback para Safari
setTimeout(load, config.idleTimeout);
}
}
/**
* Carga CSS de print solo cuando se va a imprimir
*
* @param {Object} file Archivo de print CSS
*/
function setupPrintCSS(file) {
var loaded = false;
var load = function() {
if (loaded) return;
loaded = true;
loadCSS(
config.baseUrl + file.path + '?ver=' + config.version,
'roi-lazy-print'
);
};
// Evento antes de imprimir
window.addEventListener('beforeprint', load);
// Fallback: detectar Ctrl+P / Cmd+P
document.addEventListener('keydown', function(e) {
if ((e.ctrlKey || e.metaKey) && e.key === 'p') {
load();
}
});
}
/**
* Inicializacion
*/
function init() {
var idleFiles = [];
var printFile = null;
config.cssFiles.forEach(function(file) {
switch (file.trigger) {
case 'idle':
idleFiles.push(file);
break;
case 'print':
printFile = file;
break;
}
});
// Cargar CSS idle despues de que la pagina este lista
if (idleFiles.length > 0) {
if (document.readyState === 'complete') {
loadOnIdle(idleFiles);
} else {
window.addEventListener('load', function() {
loadOnIdle(idleFiles);
});
}
}
// Configurar CSS de print
if (printFile) {
setupPrintCSS(printFile);
}
}
// Iniciar
init();
})();