fix(adsense): corregir posicionamiento de Rail Ads

- Usar CSS max() para evitar rail izquierdo cortado fuera del viewport
- Agregar JavaScript inteligente para detectar navbar/hero dinámicamente
- Rail ads se posicionan debajo del hero cuando es visible
- Usar requestAnimationFrame para throttle de scroll
- Eliminar dependencia de valores fijos en pixels

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

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
FrankZamora
2025-11-27 20:55:18 -06:00
parent 55f061df67
commit 2fa112ab7f

View File

@@ -310,16 +310,18 @@ final class AdsensePlacementRenderer
'top' => $topOffset . 'px', 'top' => $topOffset . 'px',
'width' => $width . 'px', 'width' => $width . 'px',
'z-index' => '100', 'z-index' => '100',
'transition' => 'top 0.2s ease-out',
]); ]);
// Posicion rail izquierdo // Posicion rail izquierdo - usar max() para evitar valores negativos
// Formula: max(10px, calc((100vw - 1320px) / 2 - (width + 20)px))
$cssRules[] = $this->cssGenerator->generate('.roi-rail-ad-left', [ $cssRules[] = $this->cssGenerator->generate('.roi-rail-ad-left', [
'left' => 'calc((100vw - 1320px) / 2 - ' . ($width + 20) . 'px)', 'left' => 'max(10px, calc((100vw - 1320px) / 2 - ' . ($width + 20) . 'px))',
]); ]);
// Posicion rail derecho // Posicion rail derecho - usar max() para consistencia
$cssRules[] = $this->cssGenerator->generate('.roi-rail-ad-right', [ $cssRules[] = $this->cssGenerator->generate('.roi-rail-ad-right', [
'right' => 'calc((100vw - 1320px) / 2 - ' . ($width + 20) . 'px)', 'right' => 'max(10px, calc((100vw - 1320px) / 2 - ' . ($width + 20) . 'px))',
]); ]);
// Media query para ocultar en pantallas < 1600px // Media query para ocultar en pantallas < 1600px
@@ -329,7 +331,81 @@ final class AdsensePlacementRenderer
}"; }";
$css = implode("\n", $cssRules); $css = implode("\n", $cssRules);
$html = "<style>{$css}</style>\n";
// JavaScript para posicionamiento inteligente de Rail Ads
// Detecta dinamicamente el header/hero y ajusta posicion sin valores fijos
$js = "
<script>
(function() {
var railAds = document.querySelectorAll('.roi-rail-ad');
if (!railAds.length) return;
// Buscar elementos de referencia (en orden de prioridad)
var navbar = document.querySelector('.navbar-fixed-top, .roi-navbar, .site-header, nav.navbar');
var hero = document.querySelector('.roi-hero, .hero-section, .hero, [class*=\"hero\"]');
var mainContent = document.querySelector('main, .site-main, .main-content, article');
function getNavbarHeight() {
if (navbar) {
var style = window.getComputedStyle(navbar);
if (style.position === 'fixed' || style.position === 'sticky') {
return navbar.offsetHeight;
}
}
return 0;
}
function adjustRailPosition() {
var navHeight = getNavbarHeight();
var gap = 20; // Espacio minimo de separacion
var newTop = navHeight + gap;
// Si hay hero visible, posicionar debajo de el
if (hero) {
var heroRect = hero.getBoundingClientRect();
// Si el bottom del hero esta visible (> navbar height), rails debajo del hero
if (heroRect.bottom > navHeight) {
newTop = heroRect.bottom + gap;
}
}
// Limitar el top maximo para que no quede muy abajo
var maxTop = window.innerHeight * 0.25; // Max 25% del viewport
newTop = Math.min(newTop, maxTop);
// Asegurar minimo respetando navbar
newTop = Math.max(newTop, navHeight + gap);
railAds.forEach(function(rail) {
rail.style.top = newTop + 'px';
});
}
// Throttle para mejor rendimiento
var ticking = false;
function onScroll() {
if (!ticking) {
requestAnimationFrame(function() {
adjustRailPosition();
ticking = false;
});
ticking = true;
}
}
window.addEventListener('scroll', onScroll, { passive: true });
window.addEventListener('resize', adjustRailPosition, { passive: true });
// Ejecutar despues de que el DOM este listo
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', adjustRailPosition);
} else {
adjustRailPosition();
}
})();
</script>";
$html = "<style>{$css}</style>\n{$js}\n";
/** /**
* EXCEPCION DOCUMENTADA: CSS inline requerido por Google AdSense * EXCEPCION DOCUMENTADA: CSS inline requerido por Google AdSense