mirror of
https://github.com/imfing/hextra.git
synced 2025-09-16 05:38:40 -04:00
chore(image-zoom): enhance zoom functionality with improved transitions and closing behavior
- Updated CSS for smoother transitions and added closing effects for the zoom overlay. - Enhanced JavaScript to support dedicated closing transitions and improved event handling for dismissing the overlay. - Removed unnecessary scroll lock and overflow styles for better user experience.
This commit is contained in:
@@ -1,4 +1,3 @@
|
|||||||
/* Minimal styles for Hextra image zoom overlay */
|
|
||||||
.hextra-zoom-image-overlay {
|
.hextra-zoom-image-overlay {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
inset: 0;
|
inset: 0;
|
||||||
@@ -8,27 +7,40 @@
|
|||||||
justify-content: center;
|
justify-content: center;
|
||||||
z-index: 9999;
|
z-index: 9999;
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
transition: opacity 0.25s ease-out;
|
transition: opacity 260ms cubic-bezier(0.2, 0, 0, 1);
|
||||||
cursor: zoom-out;
|
cursor: zoom-out;
|
||||||
overscroll-behavior: contain;
|
overscroll-behavior: auto;
|
||||||
touch-action: none;
|
touch-action: auto;
|
||||||
|
backdrop-filter: blur(var(--hextra-image-zoom-blur, 4px));
|
||||||
|
-webkit-backdrop-filter: blur(var(--hextra-image-zoom-blur, 4px));
|
||||||
}
|
}
|
||||||
|
|
||||||
.hextra-zoom-image-overlay.show {
|
.hextra-zoom-image-overlay.show {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.hextra-zoom-image-overlay.closing {
|
||||||
|
opacity: 0;
|
||||||
|
transition: opacity 360ms cubic-bezier(0.2, 0, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
.hextra-zoom-image {
|
.hextra-zoom-image {
|
||||||
max-width: min(95vw, 1200px);
|
max-width: min(95vw, 1200px);
|
||||||
max-height: 95vh;
|
max-height: 95vh;
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
box-shadow: 0 8px 40px rgba(0, 0, 0, 0.35);
|
box-shadow: 0 8px 40px rgba(0, 0, 0, 0.35);
|
||||||
transition: transform 0.3s ease-out;
|
will-change: transform;
|
||||||
transform: scale(0.98);
|
transform: scale(0.98);
|
||||||
}
|
}
|
||||||
|
|
||||||
.hextra-zoom-image-overlay.show .hextra-zoom-image {
|
.hextra-zoom-image-overlay.show .hextra-zoom-image {
|
||||||
transform: scale(1);
|
transform: scale(1);
|
||||||
|
transition: transform 320ms cubic-bezier(0.2, 0.8, 0.2, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.hextra-zoom-image-overlay.closing .hextra-zoom-image {
|
||||||
|
transform: scale(0.98);
|
||||||
|
transition: transform 340ms cubic-bezier(0.3, 0, 0.2, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (prefers-reduced-motion: reduce) {
|
@media (prefers-reduced-motion: reduce) {
|
||||||
@@ -42,9 +54,3 @@
|
|||||||
.content img:not([data-no-zoom]) {
|
.content img:not([data-no-zoom]) {
|
||||||
cursor: zoom-in;
|
cursor: zoom-in;
|
||||||
}
|
}
|
||||||
|
|
||||||
html:has(.hextra-zoom-image-overlay.show),
|
|
||||||
body:has(.hextra-zoom-image-overlay.show) {
|
|
||||||
overflow: hidden;
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
|
@@ -1,16 +1,14 @@
|
|||||||
// Minimal, dependency-free image zoom for Hextra
|
/*!
|
||||||
// - Activates on images inside `.content`
|
* Hextra Image Zoom
|
||||||
// - Close on overlay click or Escape
|
* - Zooms images inside `.content` into a dark, blurred overlay.
|
||||||
// - Opt-out with `data-no-zoom` on <img>
|
* - Dismiss: overlay click, Esc, wheel/scroll (non-ctrl).
|
||||||
|
* - Pinch/trackpad pinch (wheel+ctrl) will NOT dismiss.
|
||||||
|
* - Opt out per image via `data-no-zoom`.
|
||||||
|
* - Customize via CSS vars: --hextra-image-zoom-backdrop, --hextra-image-zoom-blur.
|
||||||
|
*/
|
||||||
|
|
||||||
(function () {
|
(function () {
|
||||||
function ready(fn) {
|
'use strict';
|
||||||
if (document.readyState === "loading") {
|
|
||||||
document.addEventListener("DOMContentLoaded", fn, { once: true });
|
|
||||||
} else {
|
|
||||||
fn();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function createOverlay(src, alt) {
|
function createOverlay(src, alt) {
|
||||||
const overlay = document.createElement("div");
|
const overlay = document.createElement("div");
|
||||||
@@ -25,33 +23,41 @@
|
|||||||
|
|
||||||
overlay.appendChild(img);
|
overlay.appendChild(img);
|
||||||
|
|
||||||
function close() {
|
function close(immediate = false) {
|
||||||
overlay.classList.remove("show");
|
// trigger dedicated closing transitions for smoother zoom-out
|
||||||
document.documentElement.style.removeProperty("overflow");
|
overlay.classList.add("closing");
|
||||||
window.removeEventListener("keydown", onKeyDown, true);
|
window.removeEventListener("keydown", onKeyDown, true);
|
||||||
overlay.addEventListener(
|
window.removeEventListener("scroll", onScroll, true);
|
||||||
"transitionend",
|
overlay.removeEventListener("wheel", onWheel);
|
||||||
() => overlay.remove(),
|
|
||||||
{ once: true }
|
if (immediate) {
|
||||||
);
|
overlay.remove();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
overlay.addEventListener("transitionend", () => overlay.remove(), { once: true });
|
||||||
}
|
}
|
||||||
|
|
||||||
function onKeyDown(e) {
|
function onKeyDown(e) {
|
||||||
if (e.key === "Escape") close();
|
if (e.key === "Escape") close();
|
||||||
}
|
}
|
||||||
|
|
||||||
overlay.addEventListener("click", close, { once: true });
|
overlay.addEventListener("click", () => close(false), { once: true });
|
||||||
window.addEventListener("keydown", onKeyDown, true);
|
window.addEventListener("keydown", onKeyDown, true);
|
||||||
|
|
||||||
|
function onWheel(e) { if (e && e.ctrlKey) return; close(true); }
|
||||||
|
function onScroll() { close(true); }
|
||||||
|
|
||||||
|
overlay.addEventListener("wheel", onWheel, { passive: true });
|
||||||
|
window.addEventListener("scroll", onScroll, true);
|
||||||
|
|
||||||
document.body.appendChild(overlay);
|
document.body.appendChild(overlay);
|
||||||
// lock scroll
|
|
||||||
document.documentElement.style.overflow = "hidden";
|
|
||||||
|
|
||||||
// trigger fade-in
|
// trigger fade-in
|
||||||
requestAnimationFrame(() => overlay.classList.add("show"));
|
requestAnimationFrame(() => overlay.classList.add("show"));
|
||||||
}
|
}
|
||||||
|
|
||||||
ready(function () {
|
// Initialize after DOM is parsed; defer script ensures this usually fires immediately
|
||||||
|
document.addEventListener('DOMContentLoaded', function () {
|
||||||
const container = document.querySelector(".content");
|
const container = document.querySelector(".content");
|
||||||
if (!container) return;
|
if (!container) return;
|
||||||
|
|
||||||
@@ -72,5 +78,5 @@
|
|||||||
},
|
},
|
||||||
true
|
true
|
||||||
);
|
);
|
||||||
});
|
}, { once: true });
|
||||||
})();
|
})();
|
||||||
|
Reference in New Issue
Block a user