Как перейти к определенному индексу текста внутри <div>

тл;др

Как прокрутить до определенного места на веб-странице с учетом индекса текстового содержимого, находящегося в одном <div>? (Нет JQuery!)

<div>
    Lorem ipsum dolor sit amet, consectetur adipiscing elit,
    ...
    Sed ut  <!-- Say I want to scroll to this point using the char index --> perspiciatis unde omnis iste natus error
</div>

История

Существуют якорные ссылки, помогающие перейти к определенному разделу веб-страницы, содержащему довольно длинный текст, например полный отрывок lorem-ipsum. Однако они неизменяемы и определяются с помощью html-тегов: они являются частью статической разметки.

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

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

Итак, я задумался о том, чтобы сохранить индекс текста для пользователя, никакая другая светлая идея не преследовала меня. Теперь мне интересно, как это возможно с Vanilla JS.

Существует два способа прокрутки к элементу: именованные привязки и координаты. Запрещая изменение разметки, вы не можете использовать метод 1. Это оставляет вас с координатами... поэтому вам нужно иметь дело с позициями курсора, что может быть чем-то вроде кросс-браузерного кошмара. Посмотрите здесь: stackoverflow.com/questions/17427973/…

Diodeus - James MacFarlane 23.07.2019 20:59

@nick zoum спасибо за разработку. Соберу и проверю ответы сегодня вечером.

vahdet 13.08.2019 11:35
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
0
2
578
5
Перейти к ответу Данный вопрос помечен как решенный

Ответы 5

Этот ответ будет работать на хроме. Возможно, вам придется немного повозиться, чтобы быть совместимым с браузером, просмотрев свойства MouseEvent.

<script>
var pointer = 0;

function myFunction(e) {
pointer = e.screenY;
}

function scrollToPointer(){
//This is how you would "scroll to pointer"
let mainContent = document.getElementById('wrapper')
mainContent.scrollTop = pointer;
}
</script>

    <div id = "wrapper">
        <div onmousedown = "myFunction(event)">
            Lorem ipsum dolor sit amet, consectetur adipiscing elit,
            ...
            Sed ut
            <!-- Say I want to scroll to this point using the char index --> perspiciatis unde omnis iste natus error
        </div>
    </div>

Хороший фрагмент, но действительно ли здесь необходимо вложение еще одного div? Или можно упростить как <div id = "wrapper" onmousedown = "myFunction(event)">?

vahdet 23.07.2019 21:11

Если вся страница представляет собой один div, то это сработает. Тем не менее, я бы предположил, что в #wrapper будет куча вещей вместе с div lorem ipsum. Вы хотели бы, чтобы scrollTop был установлен в оболочку div, чтобы соответствовать позиции screenY.

cWerning 23.07.2019 21:19

Примечание: если на странице нет переполнения, не будет и «прокрутки» до определенной точки, потому что прокручивать нечего. Это полезно, если у вас высокая веб-страница, т.е. "довольно длинный текст, как полный отрывок lorem-ipsum"

cWerning 23.07.2019 21:23

Вы можете обернуть разделы вашего текста (абзацы, предложения, слова, возможно) в теги <span> с увеличивающимися идентификаторами, и пока пользователь настраивает закладку, сохраните этот идентификатор в локальном хранилище. А затем прокрутите до этого идентификатора при загрузке (или используйте перенаправление закладок). Но наличие смехотворного количества узлов может повлиять на производительность вашего приложения.

<script>
window.addEventListener('load', function() {
    const bookmarkId = localStorage.getItem('user-bookmark');
    if (bookmarkId) {
        const bookmarkedNode = document.getElementById(bookmarkId);
        const bookmarkPosition = bookmarkedNode.offsetTop;
        window.scrollTo(0, bookmarkPosition);
    }
});

function myFunction(e) {
    const targetId = e.target.getAttribure('id');
    if (targetId.includes('text-section')) {
        e.stopPropagation();
        localStorage.setItem('user-bookmark', targetId);
    }
}
</script>

<div onmousedown = "myFunction(event)">
    <span id = "text-secton-0">Lorem ipsum dolor sit amet, consectetur adipiscing elit,</span>
    ...
    <span id = "text-secton-46">Sed ut</span>   <!-- Say I want to scroll to this point using the char index -->
    <span id = "text-secton-47">perspiciatis unde omnis iste natus error</span>
</div>

В качестве альтернативы вы можете сохранить положение щелчка аналогичным образом и использовать его таким же образом. Вы можете проверить, как надежно получить позицию клика здесь

Ответ принят как подходящий

Этот ответ содержит 3 фрагмента и объяснения того, как они работают.

  1. Получение индекса символа по клику
  2. Прокрутка до символа, указав его индекс
  3. Прокрутка к элементу, содержащему символ, путем предоставления его индекса

Получение индекса нажатого символа

  1. Получите узел, который был нажат, и индекс символа на этом узле, используя getSelection
  2. Перебрать все текстовые узлы статьи с помощью document.querySelectorAll("*") и получить все дочерние узлы с помощью nodeType === 3
    • Проверьте, совпадает ли node текущей итерации с выбранным узлом.
    • Если да, то остановитесь и верните index
    • Если это не так, увеличьте index на lengthtext этого узла.

Получение индекса рабочего примера нажатого символа

document.getElementById("article").addEventListener("click", function(event) {
  var {
    baseOffset: nodeIndex,
    baseNode: textNode
  } = window.getSelection();

  Array.prototype.some.call(document.querySelectorAll("#article *"), function(dom) {
    return Array.prototype.some.call(dom.childNodes, function(node) {
      if (node.nodeType !== 3) return false;
      if (node !== textNode) return nodeIndex += node.textContent.length, false;
      return true;
    });
  });

  console.info(nodeIndex);
});
<div id = "article"><div>Lorem ipsum dolor sit amet, consectetur adipiscing elit. In nec malesuada urna, eget egestas orci. Quisque gravida justo nunc, sit amet blandit risus tempus a. Integer justo justo, luctus non porttitor et, porta ut neque. Sed elit dui, ornare vitae mi</div><div>et, posuere vestibulum ex. Aliquam erat volutpat. Donec tempor dolor ligula, at consequat dui egestas id. Proin sem lorem, molestie ac imperdiet egestas, tincidunt nec leo. Phasellus sed laoreet mi. Suspendisse non neque ut turpis venenatis pulvinar.</div><div>Vestibulum egestas magna ullamcorper ligula ultrices, quis pretium sem venenatis. Etiam volutpat vel diam posuere pharetra. Donec eget commodo leo.</div><div>Lorem ipsum dolor sit amet, consectetur adipiscing elit. In nec malesuada urna, eget egestas orci. Quisque gravida justo nunc, sit amet blandit risus tempus a. Integer justo justo, luctus non porttitor et, porta ut neque. Sed elit dui, ornare vitae mi</div><div>et, posuere vestibulum ex. Aliquam erat volutpat. Donec tempor dolor ligula, at consequat dui egestas id. Proin sem lorem, molestie ac imperdiet egestas, tincidunt nec leo. Phasellus sed laoreet mi. Suspendisse non neque ut turpis venenatis pulvinar.</div><div>Vestibulum egestas magna ullamcorper ligula ultrices, quis pretium sem venenatis. Etiam volutpat vel diam posuere pharetra. Donec eget commodo leo.</div><div>Lorem ipsum dolor sit amet, consectetur adipiscing elit. In nec malesuada urna, eget egestas orci. Quisque gravida justo nunc, sit amet blandit risus tempus a. Integer justo justo, luctus non porttitor et, porta ut neque. Sed elit dui, ornare vitae mi</div><div>et, posuere vestibulum ex. Aliquam erat volutpat. Donec tempor dolor ligula, at consequat dui egestas id. Proin sem lorem, molestie ac imperdiet egestas, tincidunt nec leo. Phasellus sed laoreet mi. Suspendisse non neque ut turpis venenatis pulvinar.</div><div>Vestibulum egestas magna ullamcorper ligula ultrices, quis pretium sem venenatis. Etiam volutpat vel diam posuere pharetra. Donec eget commodo leo.</div><div>Lorem ipsum dolor sit amet, consectetur adipiscing elit. In nec malesuada urna, eget egestas orci. Quisque gravida justo nunc, sit amet blandit risus tempus a. Integer justo justo, luctus non porttitor et, porta ut neque. Sed elit dui, ornare vitae mi</div><div>et, posuere vestibulum ex. Aliquam erat volutpat. Donec tempor dolor ligula, at consequat dui egestas id. Proin sem lorem, molestie ac imperdiet egestas, tincidunt nec leo. Phasellus sed laoreet mi. Suspendisse non neque ut turpis venenatis pulvinar.</div><div>Vestibulum egestas magna ullamcorper ligula ultrices, quis pretium sem venenatis. Etiam volutpat vel diam posuere pharetra. Donec eget commodo leo.</div></div>

Прокрутка до указателя

  1. Перебрать все текстовые узлы статьи с помощью document.querySelectorAll("*") и получить все дочерние узлы с помощью nodeType === 3
    • Получите length из text из node
    • Проверьте, больше ли это length, чем index, которое вы ищете.
    • Если length больше, это означает, что вы нашли текстовый узел, содержащий символ.
    • В противном случае уменьшите index на length и продолжайте цикл
  2. Создайте копию этого узла с помощью substring(0, index) и добавьте его сразу после узла.
  3. Создайте HTMLElement, до которого вы можете прокручивать, и сразу после узла, упомянутого выше.
  4. Создайте еще одну копию исходного узла, на этот раз с substring(index), и добавьте ее сразу после нового HTMLElement.
  5. Удалить исходный узел
  6. Прокрутите до HTMLElement, используя scrollTo

Прокрутка до рабочего примера индекса

document.getElementById("move").addEventListener("click", function() {
  onLoad(+document.getElementById("get-index").value);
});

function onLoad(index) {
  // remove old bookmark
  var bookmark = document.getElementById("bookmark-pointer");
  if (bookmark) bookmark.remove();

  var textNode;

  // Loop through all the text nodes and sum up their lengths, once the sum is bigger than the index, get that node
  Array.prototype.some.call(document.querySelectorAll("#article *"), function(dom) {
    return textNode = Array.prototype.find.call(dom.childNodes, function(node) {
      if (node.nodeType !== 3) return false;
      if (index >= node.textContent.length) return index -= node.textContent.length, false;
      return true;
    });
  });

  if (!textNode) throw Error("Index out of bounds");

  bookmark = document.createElement("div");
  bookmark.id = "bookmark-pointer";

  // Split the node based on the remaining index and add the bookmark in the middle
  var nextNode = textNode.nextSibling;
  insertBefore(textNode.parentElement, document.createTextNode(textNode.textContent.substring(0, index)), nextNode);
  insertBefore(textNode.parentElement, bookmark, textNode);
  insertBefore(textNode.parentElement, document.createTextNode(textNode.textContent.substring(index)), nextNode);
  textNode.remove();

  // Wait for the changes to be rendered and then scroll to the bookmark
  setTimeout(function() {
    scrollTo(0, bookmark.offsetTop);
  }, 0);
}

function insertBefore(parentElement, newNode, referenceNode) {
  if (referenceNode) parentElement.insertBefore(newNode, referenceNode);
  else parentElement.appendChild(newNode);
}
#bookmark-pointer {
  display: inline;
}
<input id = "get-index" type = "number" placeholder = "Type Index here">
<button id = "move">Go</button>

<div id = "article"><div>Lorem ipsum dolor sit amet, consectetur adipiscing elit. In nec malesuada urna, eget egestas orci. Quisque gravida justo nunc, sit amet blandit risus tempus a. Integer justo justo, luctus non porttitor et, porta ut neque. Sed elit dui, ornare vitae mi</div><div>et, posuere vestibulum ex. Aliquam erat volutpat. Donec tempor dolor ligula, at consequat dui egestas id. Proin sem lorem, molestie ac imperdiet egestas, tincidunt nec leo. Phasellus sed laoreet mi. Suspendisse non neque ut turpis venenatis pulvinar.</div><div>Vestibulum egestas magna ullamcorper ligula ultrices, quis pretium sem venenatis. Etiam volutpat vel diam posuere pharetra. Donec eget commodo leo.</div><div>Lorem ipsum dolor sit amet, consectetur adipiscing elit. In nec malesuada urna, eget egestas orci. Quisque gravida justo nunc, sit amet blandit risus tempus a. Integer justo justo, luctus non porttitor et, porta ut neque. Sed elit dui, ornare vitae mi</div><div>et, posuere vestibulum ex. Aliquam erat volutpat. Donec tempor dolor ligula, at consequat dui egestas id. Proin sem lorem, molestie ac imperdiet egestas, tincidunt nec leo. Phasellus sed laoreet mi. Suspendisse non neque ut turpis venenatis pulvinar.</div><div>Vestibulum egestas magna ullamcorper ligula ultrices, quis pretium sem venenatis. Etiam volutpat vel diam posuere pharetra. Donec eget commodo leo.</div><div>Lorem ipsum dolor sit amet, consectetur adipiscing elit. In nec malesuada urna, eget egestas orci. Quisque gravida justo nunc, sit amet blandit risus tempus a. Integer justo justo, luctus non porttitor et, porta ut neque. Sed elit dui, ornare vitae mi</div><div>et, posuere vestibulum ex. Aliquam erat volutpat. Donec tempor dolor ligula, at consequat dui egestas id. Proin sem lorem, molestie ac imperdiet egestas, tincidunt nec leo. Phasellus sed laoreet mi. Suspendisse non neque ut turpis venenatis pulvinar.</div><div>Vestibulum egestas magna ullamcorper ligula ultrices, quis pretium sem venenatis. Etiam volutpat vel diam posuere pharetra. Donec eget commodo leo.</div><div>Lorem ipsum dolor sit amet, consectetur adipiscing elit. In nec malesuada urna, eget egestas orci. Quisque gravida justo nunc, sit amet blandit risus tempus a. Integer justo justo, luctus non porttitor et, porta ut neque. Sed elit dui, ornare vitae mi</div><div>et, posuere vestibulum ex. Aliquam erat volutpat. Donec tempor dolor ligula, at consequat dui egestas id. Proin sem lorem, molestie ac imperdiet egestas, tincidunt nec leo. Phasellus sed laoreet mi. Suspendisse non neque ut turpis venenatis pulvinar.</div><div>Vestibulum egestas magna ullamcorper ligula ultrices, quis pretium sem venenatis. Etiam volutpat vel diam posuere pharetra. Donec eget commodo leo.</div></div>

Прокрутка до элемента, содержащего индекс (вместо точного символа)

  1. Перебрать все текстовые узлы статьи с помощью document.querySelectorAll("*") и получить все дочерние узлы с помощью nodeType === 3
    • Получите length из text из node
    • Проверьте, больше ли это length, чем index, которое вы ищете.
    • Если length больше, это означает, что вы нашли текстовый узел, содержащий символ.
    • В противном случае уменьшите index на length и продолжайте цикл
  2. Прокрутите до родителя HTMLElement узла, используя scrollTo

Прокрутка до элемента, содержащего рабочий пример индекса

document.getElementById("move").addEventListener("click", function() {
  onLoad(+document.getElementById("get-index").value);
});

function onLoad(index) {
  // remove old bookmark
  var bookmark = document.getElementById("bookmark-pointer");
  if (bookmark) bookmark.remove();

  var textNode;

  // Loop through all the text nodes and sum up their lengths, once the sum is bigger than the index, get that node
  Array.prototype.some.call(document.querySelectorAll("#article *"), function(dom) {
    return textNode = Array.prototype.find.call(dom.childNodes, function(node) {
      if (node.nodeType !== 3) return false;
      if (index >= node.textContent.length) return index -= node.textContent.length, false;
      return true;
    });
  });

  if (!textNode) throw Error("Index out of bounds");
  scrollTo(0, textNode.parentElement.offsetTop);
}
#bookmark-pointer {
  display: inline;
}

div {
  margin-bottom: 10px;
  margin-top: 10px;
}
<input id = "get-index" type = "number" placeholder = "Type Index here">
<button id = "move">Go</button>

<div id = "article"><div>Lorem ipsum dolor sit amet, consectetur adipiscing elit. In nec malesuada urna, eget egestas orci. Quisque gravida justo nunc, sit amet blandit risus tempus a. Integer justo justo, luctus non porttitor et, porta ut neque. Sed elit dui, ornare vitae mi</div><div>et, posuere vestibulum ex. Aliquam erat volutpat. Donec tempor dolor ligula, at consequat dui egestas id. Proin sem lorem, molestie ac imperdiet egestas, tincidunt nec leo. Phasellus sed laoreet mi. Suspendisse non neque ut turpis venenatis pulvinar.</div><div>Vestibulum egestas magna ullamcorper ligula ultrices, quis pretium sem venenatis. Etiam volutpat vel diam posuere pharetra. Donec eget commodo leo.</div><div>Lorem ipsum dolor sit amet, consectetur adipiscing elit. In nec malesuada urna, eget egestas orci. Quisque gravida justo nunc, sit amet blandit risus tempus a. Integer justo justo, luctus non porttitor et, porta ut neque. Sed elit dui, ornare vitae mi</div><div>et, posuere vestibulum ex. Aliquam erat volutpat. Donec tempor dolor ligula, at consequat dui egestas id. Proin sem lorem, molestie ac imperdiet egestas, tincidunt nec leo. Phasellus sed laoreet mi. Suspendisse non neque ut turpis venenatis pulvinar.</div><div>Vestibulum egestas magna ullamcorper ligula ultrices, quis pretium sem venenatis. Etiam volutpat vel diam posuere pharetra. Donec eget commodo leo.</div><div>Lorem ipsum dolor sit amet, consectetur adipiscing elit. In nec malesuada urna, eget egestas orci. Quisque gravida justo nunc, sit amet blandit risus tempus a. Integer justo justo, luctus non porttitor et, porta ut neque. Sed elit dui, ornare vitae mi</div><div>et, posuere vestibulum ex. Aliquam erat volutpat. Donec tempor dolor ligula, at consequat dui egestas id. Proin sem lorem, molestie ac imperdiet egestas, tincidunt nec leo. Phasellus sed laoreet mi. Suspendisse non neque ut turpis venenatis pulvinar.</div><div>Vestibulum egestas magna ullamcorper ligula ultrices, quis pretium sem venenatis. Etiam volutpat vel diam posuere pharetra. Donec eget commodo leo.</div><div>Lorem ipsum dolor sit amet, consectetur adipiscing elit. In nec malesuada urna, eget egestas orci. Quisque gravida justo nunc, sit amet blandit risus tempus a. Integer justo justo, luctus non porttitor et, porta ut neque. Sed elit dui, ornare vitae mi</div><div>et, posuere vestibulum ex. Aliquam erat volutpat. Donec tempor dolor ligula, at consequat dui egestas id. Proin sem lorem, molestie ac imperdiet egestas, tincidunt nec leo. Phasellus sed laoreet mi. Suspendisse non neque ut turpis venenatis pulvinar.</div><div>Vestibulum egestas magna ullamcorper ligula ultrices, quis pretium sem venenatis. Etiam volutpat vel diam posuere pharetra. Donec eget commodo leo.</div></div>

Вы можете использовать метод getClientRects для спектр, чтобы получить позицию выбора. См. этот вопрос Координаты выделенного текста на странице браузера По сути, getClientRects дает вам графические прямоугольники данного выделения, позволяя вам узнать координаты выделения.

Теперь проблема заключается в сохранении самого выбора вне DOM. Объект диапазона имеет дело с узлами, на которые нет ссылок за пределами DOM, поэтому вам нужен механизм для сохранения и воссоздания данного выбора. В зависимости от структуры HTML он может быть очень простым или довольно сложным. Посмотрите этот ответ, чтобы узнать, как сохранить выбор в JSON: Сохраните выбранный текст и покажите его позже в html и javascript Это решение работает со сложными случаями, у вас может быть сложный HTML и при этом сохранить выбор.

Объедините 2 ответа, и вы получите поведение wnated, ничего не добавляя в свою HTML-структуру. Чтобы фрагмент работал, выберите точку или выделение в тексте. Используйте кнопку, чтобы скопировать выбранный JSON. С помощью кнопки вставки вы вставляете JSON, чтобы имитировать то, что произойдет, когда ваша страница откроется: вы извлекаете сохраненные данные и повторно вставляете их в виде диапазона, а затем используете scrollTo, чтобы перейти к координате y вашего выбора. Обратите внимание, что вам не нужно ничего выбирать, просто щелкнув текст, вы создадите свернутое выделение, которого достаточно для работы.

var key = 0;

// this is to handle complex html it's easier with ids
function addKey(element) {
  if (element.children.length > 0) {
    Array.prototype.forEach.call(element.children, function(each, i) {
      each.dataset.key = key++;
      addKey(each)
    });
  }
};

addKey(document.body);

// this allows you to save selection as JSON, so you can save in a db for example
function rangeToObj(range) {
  return {
    startKey: range.startContainer.parentNode.dataset.key,
    startTextIndex: Array.prototype.indexOf.call(range.startContainer.parentNode.childNodes, range.startContainer),
    endKey: range.endContainer.parentNode.dataset.key,
    endTextIndex: Array.prototype.indexOf.call(range.endContainer.parentNode.childNodes, range.endContainer),
    startOffset: range.startOffset,
    endOffset: range.endOffset
  }
}


document.getElementById('getSelectionString').addEventListener('click', function() {
  var range = document.getSelection().getRangeAt(0);
  var objFromRange = rangeToObj(range);
  document.getElementById('textarea').value = JSON.stringify(objFromRange);
  document.getElementById('textarea').select();
  document.execCommand('copy');
});

// this recreates the range from your saved selection in JSON
function objToRange(rangeStr) {
  range = document.createRange();
  range.setStart(document.querySelector('[data-key = "' + rangeStr.startKey + '"]').childNodes[rangeStr.startTextIndex], rangeStr.startOffset);
  range.setEnd(document.querySelector('[data-key = "' + rangeStr.endKey + '"]').childNodes[rangeStr.endTextIndex], rangeStr.endOffset);
  return range;
}

document.getElementById('setSelection').addEventListener('click', function() {
  var selStr = prompt('Paste string');
  var seavedSelection = JSON.parse(selStr);
  var sel = getSelection();
  sel.removeAllRanges();
  sel.addRange(objToRange(seavedSelection));
  // this is where the scroll happens, getClientRects gives you coordinates of the selection,
  // so you can scrolll at the y position
  // getClientRects gives an array because you can have complex selection but in your case
  // I guess you only need one point
  window.scrollTo(0, sel.getRangeAt(0).getClientRects()[0].y)

});
div:nth-child(1) {
  color: blue;
}

div:nth-child(2) {
  color: red;
}

div:nth-child(3) {
  color: green;
}

div:nth-child(4) {
  color: pink;
}

div:nth-child(5) {
  color: black;
}

div:nth-child(6) {
  color: yellow;
}

html {
  scroll-behavior: smooth;
}
<button id = "getSelectionString">
  Copy selection
</button>

<button id = "setSelection">
  Paste to scroll to selection
</button>

<textarea id=textarea></textarea>
<div id=textToSelect>
  <div>Lorem ipsum
    <ul>
      <li>dolor</li>
      <li>sit</li>
    </ul> amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris <strong>nisi</strong> ut aliquip ex ea commodo consequat. Duis aute irure dolor
    in reprehenderit in voluptate velit esse cillum <a href = "https://stackoverflow.com">dolore eu fugiat</a> nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui <em>officia</em> deserunt mollit anim id est laborum.</div>
  <div>Lorem ipsum
    <ul>
      <li>dolor</li>
      <li>sit</li>
    </ul> amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris <strong>nisi</strong> ut aliquip ex ea commodo consequat. Duis aute irure dolor
    in reprehenderit in voluptate velit esse cillum <a href = "https://stackoverflow.com">dolore eu fugiat</a> nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui <em>officia</em> deserunt mollit anim id est laborum.</div>
  <div>Lorem ipsum
    <ul>
      <li>dolor</li>
      <li>sit</li>
    </ul> amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris <strong>nisi</strong> ut aliquip ex ea commodo consequat. Duis aute irure dolor
    in reprehenderit in voluptate velit esse cillum <a href = "https://stackoverflow.com">dolore eu fugiat</a> nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui <em>officia</em> deserunt mollit anim id est laborum.</div>
  <div>Lorem ipsum
    <ul>
      <li>dolor</li>
      <li>sit</li>
    </ul> amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris <strong>nisi</strong> ut aliquip ex ea commodo consequat. Duis aute irure dolor
    in reprehenderit in voluptate velit esse cillum <a href = "https://stackoverflow.com">dolore eu fugiat</a> nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui <em>officia</em> deserunt mollit anim id est laborum.</div>
  <div>Lorem ipsum
    <ul>
      <li>dolor</li>
      <li>sit</li>
    </ul> amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris <strong>nisi</strong> ut aliquip ex ea commodo consequat. Duis aute irure dolor
    in reprehenderit in voluptate velit esse cillum <a href = "https://stackoverflow.com">dolore eu fugiat</a> nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui <em>officia</em> deserunt mollit anim id est laborum.</div>
  <div>Lorem ipsum
    <ul>
      <li>dolor</li>
      <li>sit</li>
    </ul> amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris <strong>nisi</strong> ut aliquip ex ea commodo consequat. Duis aute irure dolor
    in reprehenderit in voluptate velit esse cillum <a href = "https://stackoverflow.com">dolore eu fugiat</a> nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui <em>officia</em> deserunt mollit anim id est laborum.</div>
  <div>Lorem ipsum
    <ul>
      <li>dolor</li>
      <li>sit</li>
    </ul> amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris <strong>nisi</strong> ut aliquip ex ea commodo consequat. Duis aute irure dolor
    in reprehenderit in voluptate velit esse cillum <a href = "https://stackoverflow.com">dolore eu fugiat</a> nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui <em>officia</em> deserunt mollit anim id est laborum.</div>
  <div>Lorem ipsum
    <ul>
      <li>dolor</li>
      <li>sit</li>
    </ul> amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris <strong>nisi</strong> ut aliquip ex ea commodo consequat. Duis aute irure dolor
    in reprehenderit in voluptate velit esse cillum <a href = "https://stackoverflow.com">dolore eu fugiat</a> nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui <em>officia</em> deserunt mollit anim id est laborum.</div>
</div>

Ключевым моментом вашего вопроса является получение точки, которую вам нужно прокрутить, вот пример получения относительной точки указанного элемента html по заданному смещению:

<html lang = "en" xmlns = "http://www.w3.org/1999/xhtml">
<head>
    <meta charset = "utf-8" />
    <title></title>
    <script type = "text/javascript">
        function getPointByOffset(element, offset) {
            if (arguments.length == 1) {
                offset = element;
                element = document.querySelector("div");
            }
            if (element.nodeType == 1) {
                element = element.firstChild;
            }

            var range = document.createRange();
            range.setStart(element, 0);
            range.setEnd(element, offset);
            var boundary = range.getBoundingClientRect();
            return { x: boundary.left + boundary.width, y: boundary.top + boundary.height };
        }
    </script>
</head>
<body>
    <div>
        Lorem ipsum dolor sit amet, consectetur adipiscing elit,
    </div>
</body>
</html>

Другие вопросы по теме