тл;др
Как прокрутить до определенного места на веб-странице с учетом индекса текстового содержимого, находящегося в одном <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.
@nick zoum спасибо за разработку. Соберу и проверю ответы сегодня вечером.



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Этот ответ будет работать на хроме. Возможно, вам придется немного повозиться, чтобы быть совместимым с браузером, просмотрев свойства 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)">?
Если вся страница представляет собой один div, то это сработает. Тем не менее, я бы предположил, что в #wrapper будет куча вещей вместе с div lorem ipsum. Вы хотели бы, чтобы scrollTop был установлен в оболочку div, чтобы соответствовать позиции screenY.
Примечание: если на странице нет переполнения, не будет и «прокрутки» до определенной точки, потому что прокручивать нечего. Это полезно, если у вас высокая веб-страница, т.е. "довольно длинный текст, как полный отрывок lorem-ipsum"
Вы можете обернуть разделы вашего текста (абзацы, предложения, слова, возможно) в теги <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 фрагмента и объяснения того, как они работают.
getSelectiondocument.querySelectorAll("*") и получить все дочерние узлы с помощью nodeType === 3node текущей итерации с выбранным узлом.indexindex на 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>document.querySelectorAll("*") и получить все дочерние узлы с помощью nodeType === 3length из text из nodelength, чем index, которое вы ищете.length больше, это означает, что вы нашли текстовый узел, содержащий символ.index на length и продолжайте циклsubstring(0, index) и добавьте его сразу после узла.HTMLElement, до которого вы можете прокручивать, и сразу после узла, упомянутого выше.substring(index), и добавьте ее сразу после нового HTMLElement.HTMLElement, используя scrollTodocument.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>document.querySelectorAll("*") и получить все дочерние узлы с помощью nodeType === 3length из text из nodelength, чем index, которое вы ищете.length больше, это означает, что вы нашли текстовый узел, содержащий символ.index на length и продолжайте циклHTMLElement узла, используя scrollTodocument.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>
Существует два способа прокрутки к элементу: именованные привязки и координаты. Запрещая изменение разметки, вы не можете использовать метод 1. Это оставляет вас с координатами... поэтому вам нужно иметь дело с позициями курсора, что может быть чем-то вроде кросс-браузерного кошмара. Посмотрите здесь: stackoverflow.com/questions/17427973/…