Делал посты и захотел, чтобы фотографии из поста можно было открывать в лайтбоксе и листать все подряд, без ограничения привязки к галерее. Оказалось, стандартный лайтбокс так не умеет и побороть его крайне тяжело. По-этому Gemini сделал мне кастомный. Добавляю его, где мне нужно, как отдельный блок HTML в конце поста, при этом старые посты не ломаются. Код подкатом, разжевать можно в любой модельке.
<style>
/* Стили адаптивного лайтбокса */
.my-lightbox {
display: none; position: fixed; z-index: 9999999; left: 0; top: 0; width: 100vw; height: 100vh;
background-color: rgba(15, 15, 15, 0.95); align-items: center; justify-content: center;
touch-action: none; user-select: none; -webkit-user-select: none;
}
.my-lightbox img {
max-width: 90%; max-height: 85vh; object-fit: contain;
transition: transform 0.2s ease;
pointer-events: auto; cursor: pointer;
}
.ml-btn {
position: absolute; top: 50%; transform: translateY(-50%); background: rgba(255,255,255,0.1);
color: #fff; border: none; font-size: 28px; width: 50px; height: 50px; cursor: pointer;
border-radius: 50%; display: flex; align-items: center; justify-content: center; transition: 0.2s; z-index: 10000001;
}
.ml-btn:hover { background: rgba(255,255,255,0.3); }
.ml-prev { left: 20px; } .ml-next { right: 20px; }
.ml-close { position: absolute; top: 20px; right: 25px; color: #fff; font-size: 38px; cursor: pointer; width: 40px; height: 40px; display: flex; align-items: center; justify-content: center; z-index: 10000002; }
@media (max-width: 768px) {
.ml-btn { display: none; }
.my-lightbox img { max-width: 95%; }
}
</style>
<div id="myLightboxRoot" class="my-lightbox">
<div class="ml-close" id="mlCloseBtn">×</div>
<button class="ml-btn ml-prev" id="mlPrevBtn">❮</button>
<img id="mlMainImg" src="" alt="">
<button class="ml-btn ml-next" id="mlNextBtn">❯</button>
</div>
<script>
document.addEventListener('DOMContentLoaded', function() {
var root = document.getElementById('myLightboxRoot');
if (root) {
document.body.appendChild(root);
}
function initIsolatedGallery() {
var selectors = '.wp-block-image a[href*=".jpg"], .wp-block-image a[href*=".jpeg"], .wp-block-image a[href*=".png"], .wp-block-image a[href*=".webp"], .wp-block-gallery a[href*=".jpg"], .wp-block-gallery a[href*=".jpeg"], .wp-block-gallery a[href*=".png"], .wp-block-gallery a[href*=".webp"]';
var links = document.querySelectorAll(selectors);
if (links.length === 0) return;
var images = [];
var currentIndex = 0;
var mainImg = document.getElementById('mlMainImg');
links.forEach(function(link, index) {
if (images.indexOf(link.href) === -1) {
images.push(link.href);
}
link.removeAttribute('data-wp-on--click');
link.addEventListener('click', function(e) {
e.preventDefault();
e.stopPropagation();
currentIndex = images.indexOf(link.href);
updateLightbox();
root.style.display = 'flex';
}, true);
});
function updateLightbox() {
if (mainImg) {
mainImg.src = images[currentIndex];
}
}
function nextSlide() {
currentIndex = (currentIndex + 1) % images.length;
updateLightbox();
}
function prevSlide() {
currentIndex = (currentIndex - 1 + images.length) % images.length;
updateLightbox();
}
var nextBtn = document.getElementById('mlNextBtn');
var prevBtn = document.getElementById('mlPrevBtn');
var closeBtn = document.getElementById('mlCloseBtn');
if (nextBtn) nextBtn.onclick = function(e) { e.stopPropagation(); nextSlide(); };
if (prevBtn) prevBtn.onclick = function(e) { e.stopPropagation(); prevSlide(); };
if (closeBtn) closeBtn.onclick = function() { root.style.display = 'none'; };
root.onclick = function() { root.style.display = 'none'; };
// Клик по самой картинке (разделение 50/50 без опасных амперсандов)
if (mainImg) {
mainImg.onclick = function(e) {
e.stopPropagation();
var rect = mainImg.getBoundingClientRect();
var clientX = null;
// Безопасное определение координат мыши или тача
if (e.clientX) {
clientX = e.clientX;
} else if (e.changedTouches) {
if (e.changedTouches[0]) {
clientX = e.changedTouches[0].clientX;
}
}
if (!clientX) return;
var clickX = clientX - rect.left;
if (clickX > rect.width / 2) {
nextSlide();
} else {
prevSlide();
}
};
}
// Клавиатура
document.onkeydown = function(e) {
if (root.style.display === 'flex') {
if (e.key === 'ArrowRight') nextSlide();
if (e.key === 'ArrowLeft') prevSlide();
if (e.key === 'Escape') root.style.display = 'none';
}
};
// Свайпы на мобилках
var touchStartX = 0;
var touchEndX = 0;
root.ontouchstart = function(e) {
touchStartX = e.changedTouches[0].screenX;
};
root.ontouchend = function(e) {
touchEndX = e.changedTouches[0].screenX;
var swipeDistance = touchEndX - touchStartX;
if (swipeDistance < -50) nextSlide();
if (swipeDistance > 50) prevSlide();
};
}
initIsolatedGallery();
setTimeout(initIsolatedGallery, 500);
});
</script>
Пришлось переделать без &&, а то WordPress ломает скрипт, при прямой вставке через HTML блок.
