diff --git a/css/style.css b/css/style.css index f79fb69..01855e5 100644 --- a/css/style.css +++ b/css/style.css @@ -1227,26 +1227,39 @@ footer.footer-modern a:hover { position: relative; display: inline-block; cursor: zoom-in; - /* clip the overlay to the image bounds */ - overflow: hidden; + overflow: hidden; /* clips both pseudo-elements to image bounds */ } -/* Full-image dark overlay with centred magnifier on hover. - Stroke-based SVG (24×24 viewBox, no fill) stays crisp at any rendered size. */ -.zoomable-wrap::after { +/* ::before — dark overlay */ +.zoomable-wrap::before { content: ''; position: absolute; inset: 0; - background-color: rgba(0, 0, 0, 0.38); - background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='white' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='8'/%3E%3Cline x1='21' y1='21' x2='16.65' y2='16.65'/%3E%3Cline x1='11' y1='8' x2='11' y2='14'/%3E%3Cline x1='8' y1='11' x2='14' y2='11'/%3E%3C/svg%3E"); - background-position: center; - background-size: min(44px, 25%); - background-repeat: no-repeat; + background: rgba(0, 0, 0, 0.38); opacity: 0; transition: opacity 0.2s ease; pointer-events: none; + z-index: 1; } +/* ::after — stroke-based magnifier, centred, fixed 36 px. + Strokes render as vectors so no pixelation at any display size. */ +.zoomable-wrap::after { + content: ''; + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + width: 36px; + height: 36px; + background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='white' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='8'/%3E%3Cline x1='21' y1='21' x2='16.65' y2='16.65'/%3E%3Cline x1='11' y1='8' x2='11' y2='14'/%3E%3Cline x1='8' y1='11' x2='14' y2='11'/%3E%3C/svg%3E") center / contain no-repeat; + opacity: 0; + transition: opacity 0.2s ease; + pointer-events: none; + z-index: 2; +} + +.zoomable-wrap:hover::before, .zoomable-wrap:hover::after { opacity: 1; } diff --git a/index.php b/index.php index ec806fc..af9cd8a 100644 --- a/index.php +++ b/index.php @@ -368,16 +368,25 @@ document.body.style.overflow = ''; } - Array.prototype.forEach.call(images, function (el) { - // Skip icons / tiny images — not worth zooming - if (el.offsetWidth < 80 && el.offsetHeight < 80) return; + function wrapImage(el) { + // Skip icons / tiny images using natural dimensions (reliable after load) + if (el.naturalWidth > 0 && el.naturalWidth < 100) return; + if (el.naturalHeight > 0 && el.naturalHeight < 100) return; - // Wrap in a span so CSS can attach the hover overlay via ::after var wrap = document.createElement('span'); wrap.className = 'zoomable-wrap'; el.parentNode.insertBefore(wrap, el); wrap.appendChild(el); el.addEventListener('click', function () { open(el.src, el.alt); }); + } + + Array.prototype.forEach.call(images, function (el) { + // If already loaded (e.g. from cache) act immediately; otherwise wait + if (el.complete && el.naturalWidth) { + wrapImage(el); + } else { + el.addEventListener('load', function () { wrapImage(el); }); + } }); overlay.addEventListener('click', close);