From d5fbb804c34174131736b0fc3ff178a646761726 Mon Sep 17 00:00:00 2001 From: Vladislav Kopnin Date: Tue, 29 Sep 2026 20:58:41 +0300 Subject: [PATCH] Modals: preserve page scroll position while locking background --- web/src/main/resources/static/css/app.css | 9 ++++++--- web/src/main/resources/templates/fragments/base.html | 11 +++++++++-- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/web/src/main/resources/static/css/app.css b/web/src/main/resources/static/css/app.css index a77bbdf..3f54360 100644 --- a/web/src/main/resources/static/css/app.css +++ b/web/src/main/resources/static/css/app.css @@ -241,9 +241,12 @@ dialog.modal { box-shadow: 0 20px 60px rgba(0,0,0,0.35); } dialog.modal::backdrop { background: rgba(0,0,0,0.55); } -/* Пока открыта модалка — страница не прокручивается; прокрутка остаётся внутри .modal-body */ -html.modal-open, html.modal-open body { overflow: hidden; } -html.modal-open body { padding-right: var(--modal-scrollbar, 0); } +/* Пока открыта модалка — страница не прокручивается, позиция скролла сохраняется; + прокрутка остаётся внутри .modal-body */ +html.modal-open body { + position: fixed; left: 0; right: 0; width: 100%; top: var(--modal-top, 0); + padding-right: var(--modal-scrollbar, 0); +} .modal-header { display: flex; align-items: center; justify-content: space-between; padding: 1rem 1.5rem; border-bottom: 1px solid var(--c-border); } .modal-title { margin: 0; font-size: 1.0625rem; font-weight: 600; } .modal-close { border: none; background: none; cursor: pointer; font-size: 1.25rem; color: var(--c-text-muted); padding: 0 0.25rem; } diff --git a/web/src/main/resources/templates/fragments/base.html b/web/src/main/resources/templates/fragments/base.html index 3968f32..7a66dbc 100644 --- a/web/src/main/resources/templates/fragments/base.html +++ b/web/src/main/resources/templates/fragments/base.html @@ -36,16 +36,23 @@ function closeModal(id){ var d=document.getElementById(id); if(d) d.close(); syncModalScrollLock(); } function openModalData(btn){ openModal(btn.dataset.modal); } function closeModalData(btn){ closeModal(btn.dataset.modal); } - /* Пока открыта хоть одна модалка — блокируем прокрутку страницы (внутри .modal-body прокрутка остаётся). */ + /* Пока открыта хоть одна модалка — блокируем прокрутку страницы, сохраняя позицию скролла + (внутри .modal-body прокрутка остаётся). */ + var modalScrollY = 0; function syncModalScrollLock(){ var root = document.documentElement; if (document.querySelector('dialog[open]')) { + if (root.classList.contains('modal-open')) return; + modalScrollY = window.scrollY || window.pageYOffset || 0; var sw = window.innerWidth - root.clientWidth; root.style.setProperty('--modal-scrollbar', (sw > 0 ? sw : 0) + 'px'); + root.style.setProperty('--modal-top', (-modalScrollY) + 'px'); root.classList.add('modal-open'); - } else { + } else if (root.classList.contains('modal-open')) { root.classList.remove('modal-open'); root.style.removeProperty('--modal-scrollbar'); + root.style.removeProperty('--modal-top'); + window.scrollTo(0, modalScrollY); } } document.addEventListener('toggle', function (e) {