Вопрос или проблема
Я пытаюсь создать простой слайдер изображений с постепенным улучшением. Код здесь.
Базовая версия полностью функционирует без JavaScript: используя якорные ссылки, флексбокс и scroll-snap-align
, поведение уже довольно приятное и функционально завершенное.
В качестве прогрессивного усовершенствования я хочу избавиться от вертикальной прокрутки, которая происходит при нажатии на якорные ссылки.
Очевидная попытка — это использовать preventDefault()
при изменении хеша в URL (т.е. когда щелкают по ссылкам) и выполнить scrollTo()
на JavaScript с опцией top
, установленной на текущее положение прокрутки.
Вот мой код JavaScript:
function horizontal_anchor() {
var hash = decodeURIComponent(location.hash); // декодируем специальные символы, такие как пробелы
var element = document.getElementById(hash.substring(1));
if (element) {
var parent = element.closest(".slide");
let targetTop =
window.pageYOffset !== undefined
? window.pageYOffset
: (
document.documentElement ||
document.body.parentNode ||
document.body
).scrollTop;
parent.scrollTo({
left: element.offsetLeft,
top: targetTop,
behavior: "smooth"
});
}
}
document.addEventListener("DOMContentLoaded", function () {
// при загрузке
if (location.hash) horizontal_anchor();
// при изменении URL
window.addEventListener("hashchange", function (event) {
event.preventDefault();
horizontal_anchor();
return false;
});
});
Полный пример в контексте можно найти здесь: https://codepen.io/BernhardWebstudio/pen/eYqmaKO.
В этом примере, когда вы нажимаете на Next
или Prev
, страница прокручивается так, что изображение оказывается в верхней части окна (iframe), а не остается на месте, вертикально. Кроме того, похоже, что behavior: "smooth"
не соблюдается.
Ответ или решение
Чтобы реализовать горизонтальную прокрутку без вертикальной прокрутки при нажатии на ссылки- якоря в вашем слайдере изображений, необходимо внести несколько изменений в ваш JavaScript код. Ваша идея использовать preventDefault()
и scrollTo()
— это правильный подход, но давайте уточним некоторые моменты, которые помогут вам избежать вертикальной прокрутки и добиться плавного поведения.
Вот детализированный подход, как это сделать:
- Отмените действие по умолчанию для ссылок, которые вы используете для навигации по изображениям.
- Используйте метод
scrollLeft
для прокрутки родительского контейнера, вместо того чтобы использоватьscrollTo
, так как он может вызывать проблемы с поведением.
Вот обновленный код:
function horizontal_anchor() {
var hash = decodeURIComponent(location.hash); // декодируем специальные символы
var element = document.getElementById(hash.substring(1));
if (element) {
var parent = element.closest(".slide"); // родительский элемент для прокрутки
let targetTop = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop; // текущее вертикальное положение
// Прокрутка по горизонтали к элементу
parent.scrollTo({
left: element.offsetLeft,
top: targetTop,
behavior: "smooth" // плавная прокрутка
});
}
}
document.addEventListener("DOMContentLoaded", function () {
// При загрузке страницы
if (location.hash) horizontal_anchor();
// На изменение URL
window.addEventListener("hashchange", function (event) {
event.preventDefault(); // отменяем стандартное поведение
horizontal_anchor(); // вызываем функцию прокрутки
});
});
// Добавьте обработчики на ваши ссылки для навигации
document.querySelectorAll('a[href^="#"]').forEach(anchor => {
anchor.addEventListener('click', function(event) {
event.preventDefault(); // предотвратить переход по якорю
location.hash = this.getAttribute('href'); // обновление URL без прокрутки
});
});
Объяснение:
preventDefault()
: Отключает стандартное поведение ссылки, которое вызывает вертикальную прокрутку.location.hash
: Используется для изменения хеша URL, что вызывает событиеhashchange
, но без фактического вертикального скролла.scrollTo()
: Мы вызываем эту функцию для плавной горизонтальной прокрутки. Убедитесь, что ваш CSS настроен так, чтобыscroll-snap-align
работал корректно в вашем изображении, это поможет улучшить пользовательский опыт.
Замечания:
- Убедитесь, что ваш контейнер (на который вы вызываете
scrollTo
) имеет свойствоoverflow-x
установленное вauto
илиscroll
, иначе горизонтальная прокрутка не сработает. - Проверьте, что все ваши изображения имеют правильные размеры и настройки для корректной работы
flexbox
иscroll-snap
.
Постоянно тестируйте свою реализацию, чтобы убедиться, что поведение соответствует вашим ожиданиям и работает на разных устройствах.