Подтвердить что ты не робот

ScrollIntoView Свитки слишком далеко

У меня есть страница, где в базе данных динамически создается полоса прокрутки, содержащая строки таблицы с divs в них. Каждая строка таблицы действует как ссылка, вроде как вы видели в плейлисте YouTube рядом с видеопроигрывателем.

Когда пользователь посещает страницу, параметр, в котором они находятся, должен идти вверху прокрутки div. Эта функциональность работает. Проблема в том, что она идет слишком далеко. Подобно тому, как они установлены, это примерно на 10 пикселей выше. Таким образом, страница посещается, url используется для определения того, какой параметр был выбран, а затем прокручивает эту опцию до вершины прокручиваемого div. Примечание. Это не полоса прокрутки для окна, это div с полосой прокрутки.

Я использую этот код, чтобы переместить выбранную опцию в верхнюю часть div:

var pathArray = window.location.pathname.split( '/' );

var el = document.getElementById(pathArray[5]);

el.scrollIntoView(true);

Он перемещает его в верхнюю часть div, но примерно на 10 пикселей слишком далеко. Кто-нибудь знает, как это исправить?

4b9b3361

Ответ 1

Если это примерно 10px, то, я думаю, вы могли бы просто вручную отрегулировать смещение прокрутки div, как это:

el.scrollIntoView(true);
document.getElementById("containingDiv").scrollTop += 10;

Ответ 2

Вы можете сделать это в два этапа:

el.scrollIntoView(true);
window.scrollBy(0, -10); // Adjust scrolling with a negative value here

Ответ 3

Положение привязки абсолютным методом

Другой способ сделать это - расположить привязки именно там, где вы хотите на странице, а не использовать прокрутку по смещению. Я считаю, что это позволяет лучше контролировать каждый элемент (например, если вы хотите различное смещение для определенных элементов), а также может быть более устойчивым к изменениям/различиям API браузера.

<div id="title-element" style="position: relative;">
  <div id="anchor-name" style="position: absolute; top: -100px; left: 0" />
</div>

Теперь смещение указывается как -100px относительно элемента. Создайте функцию для создания этой привязки для повторного использования кода, или, если вы используете современную среду JS, такую как React, сделайте это, создав компонент, который визуализирует вашу привязку, и передайте имя привязки и выравнивание для каждого элемента, который может или может не быть таким же.

Тогда просто используйте:

const element = document.getElementById('anchor-name')
element.scrollIntoView({ behavior: 'smooth', block: 'start' });

Для плавной прокрутки со смещением 100 пикселей.

Ответ 4

Плавно прокрутите до нужной позиции

Получите правильную координату y и используйте window.scrollTo({top: y, behavior: 'smooth'})

const id = 'profilePhoto';
const yOffset = -10; 
const element = document.getElementById(id);
const y = element.getBoundingClientRect().top + window.pageYOffset + yOffset;

window.scrollTo({top: y, behavior: 'smooth'});

Ответ 5

Это работает для меня в Chrome (с плавной прокруткой и без синхронизации времени)

Он просто перемещает элемент, запускает прокрутку, а затем перемещает его назад.

Нет видимых "всплывающих окон", если элемент уже находится на экране.

pos = targetEle.style.position;
top = targetEle.style.top;
targetEle.style.position = 'relative';
targetEle.style.top = '-20px';
targetEle.scrollIntoView({behavior: 'smooth', block: 'start');
targetEle.style.top = top;
targetEle.style.position = pos;

Ответ 6

Вы также можете использовать element.scrollIntoView() опции

el.scrollIntoView(
  { 
    behavior: 'smooth', 
    block: 'start' 
  },
);

который поддерживает большинство браузеров support

Ответ 7

Основываясь на предыдущем ответе, я делаю это в проекте Angular5.

Началось с:

// el.scrollIntoView(true);
el.scrollIntoView({
   behavior: 'smooth',
   block: 'start'
});
window.scrollBy(0, -10); 

Но это породило некоторые проблемы и потребовало setTimeout для scrollBy() следующим образом:

//window.scrollBy(0,-10);
setTimeout(() => {
  window.scrollBy(0,-10)
  }, 500);

И это прекрасно работает в MSIE11 и Chrome 68+. Я не проверял в FF. 500 мс было самой короткой задержкой, которую я рискну. Спуск иногда не удался, поскольку плавная прокрутка еще не завершилась. Отрегулируйте как требуется для вашего собственного проекта.

+1 до Fred727 за это простое, но эффективное решение.

Ответ 8

Предполагая, что вы хотите прокрутить до элементов div, которые находятся на одном уровне в DOM и имеют имя класса "scroll-with-offset", этот CSS решит проблему:

.scroll-with-offset {    
  padding-top: 100px;
  margin-bottom: -100px;
}

Смещение от верхней части страницы составляет 100 пикселей. Он будет работать только так, как задумано с блоком: 'start':

element.scrollIntoView({ behavior: 'smooth', block: 'start' });

Что происходит, так это то, что верхняя точка div находится в нормальном месте, но их внутреннее содержимое начинается на 100px ниже нормального места. Вот для чего нужен padding-top: 100px. margin-bottom: -100px должен компенсировать дополнительный запас ниже div. Чтобы завершить решение, также добавьте этот CSS, чтобы компенсировать поля/отступы для самых верхних и самых нижних делителей:

.top-div {
  padding-top: 0;
}
.bottom-div {
  margin-bottom: 0;
}

Ответ 9

У меня есть это, и это прекрасно работает для меня:

// add a smooth scroll to element
scroll(el) {
el.scrollIntoView({
  behavior: 'smooth',
  block: 'start'});

setTimeout(() => {
window.scrollBy(0, -40);
}, 500);}

Надеюсь, поможет.

Ответ 10

используйте отступы для разделов вместо отступа

Ответ 11

Моя основная идея - создать tempDiv над видом, к которому мы хотим перейти. Это работает хорошо, не отставая в моем проекте.

scrollToView = (element, offset) => {
    var rect = element.getBoundingClientRect();
    var targetY = rect.y + window.scrollY - offset;

    var tempDiv;
    tempDiv = document.getElementById("tempDiv");
    if (tempDiv) {
        tempDiv.style.top = targetY + "px";
    } else {
        tempDiv = document.createElement('div');
        tempDiv.id = "tempDiv";
        tempDiv.style.background = "#F00";
        tempDiv.style.width = "10px";
        tempDiv.style.height = "10px";
        tempDiv.style.position = "absolute";
        tempDiv.style.top = targetY + "px";
        document.body.appendChild(tempDiv);
    }

    tempDiv.scrollIntoView({ behavior: 'smooth', block: 'start' });
}

Пример использования

onContactUsClick = () => {
    this.scrollToView(document.getElementById("contact-us"), 48);
}

Надеюсь, это поможет

Ответ 12

Самое простое решение, которое работает для меня:

 $('html, body').animate({ scrollTop: $(yourElement).offset().top - 20}, 800);

Ответ 13

Основываясь на ответе Арсения-II: у меня был сценарий использования, где прокручиваемая сущность была не самим окном, а внутренним шаблоном (в данном случае div). В этом сценарии нам нужно установить идентификатор для контейнера прокрутки и получить его через getElementById, чтобы использовать его функцию прокрутки:

<div class="scroll-container" id="app-content">
  ...
</div>
const yOffsetForScroll = -100
const y = document.getElementById(this.idToScroll).getBoundingClientRect().top;
const main = document.getElementById('app-content');
main.scrollTo({
    top: y + main.scrollTop + yOffsetForScroll,
    behavior: 'smooth'
  });

Оставьте это здесь на случай, если кто-то столкнется с подобной ситуацией!

Ответ 14

Здесь мои 2 цента.

У меня также была проблема прокрутки scrollIntoView немного за элементом, поэтому я создал скрипт (собственный javascript), который добавляет элемент к месту назначения, поместил его немного вверх с помощью css и прокрутил до него. После прокрутки я снова удаляю созданные элементы.

HTML:

//anchor tag that appears multiple times on the page
<a href="#" class="anchors__link js-anchor" data-target="schedule">
    <div class="anchors__text">
        Scroll to the schedule
    </div>
</a>

//The node we want to scroll to, somewhere on the page
<div id="schedule">
    //html
</div>

Файл Javascript:

(() => {
    'use strict';

    const anchors = document.querySelectorAll('.js-anchor');

    //if there are no anchors found, don't run the script
    if (!anchors || anchors.length <= 0) return;

    anchors.forEach(anchor => {
        //get the target from the data attribute
        const target = anchor.dataset.target;

        //search for the destination element to scroll to
        const destination = document.querySelector('#${target}');
        //if the destination element does not exist, don't run the rest of the code
        if (!destination) return;

        anchor.addEventListener('click', (e) => {
            e.preventDefault();
            //create a new element and add the 'anchors__generated' class to it
            const generatedAnchor = document.createElement('div');
            generatedAnchor.classList.add('anchors__generated');

            //get the first child of the destination element, insert the generated element before it. (so the scrollIntoView function scrolls to the top of the element instead of the bottom)
            const firstChild = destination.firstChild;
            destination.insertBefore(generatedAnchor, firstChild);

            //finally fire the scrollIntoView function and make it animate "smoothly"
            generatedAnchor.scrollIntoView({
                behavior: "smooth",
                block: "start",
                inline: "start"
            });

            //remove the generated element after 1ms. We need the timeout so the scrollIntoView function has something to scroll to.
            setTimeout(() => {
                destination.removeChild(generatedAnchor);
            }, 1);
        })
    })
})();

CSS:

.anchors__generated {
    position: relative;
    top: -100px;
}

Надеюсь, это кому-нибудь поможет!