1

tl;dr

How to scroll to a particular point in a web page given the index of text content residing on a single <div>? (No JQuerys!)

<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>

The story

There are anchor links helping scroll to a specific section of a web page containing a quite long text like a complete lorem-ipsum passage. However they are immutable and determined with html tags: they are a part of the static markup.

The behavior I want to get is, on the other hand, making users of a web page individually mark the any point of text they desire, and when that user reloads or refreshes the page, it should scroll to the point s/he has bookmarked before.

Sure, inserting per-user anchors to page source is not desirable. I also do not have elements to match and jump to. If I were to think about keeping the line number user marks, well, it alters with the display size.

So, I pondered keeping the index of the text for the user, no other bright idea haunted me. Now, I wonder how is it possible with Vanilla JS.

vahdet
  • 6,357
  • 9
  • 51
  • 106
  • 1
    There are two ways to scroll to an element: named anchors, and coordinates. By disallowing the mark-up to be mutable, you can't use method 1. That leaves you with coordinates...so you'll need to deal with cursor positions, which can be a bit of a cross-browser nightmare. Take a look here: https://stackoverflow.com/questions/17427973/position-of-selection-in-javascript – Diodeus - James MacFarlane Jul 23 '19 at 18:59
  • @nick zoum thanks for the elaboration. Gonna collect and check the answers this evening. – vahdet Aug 13 '19 at 09:35

5 Answers5

3

This answer contains 3 snippets and explanations on how they work

  1. Getting the index of a character on click
  2. Scrolling to a character by supplying its index
  3. Scrolling to the containing element of a character by supplying its index

Getting the index of the clicked character

  1. Get the node that was clicked and the index of the character on that node using getSelection
  2. Loop through all the text-nodes of the article using document.querySelectorAll("*") and getting all the child-nodes with nodeType === 3
    • Check if the node of the current iteration is the same as the clicked node
    • If it is then stop and return the index
    • If it isn't then increase the index by the length of the text of that node

Getting the index of the clicked character working example

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.log(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>

Scrolling to the index

  1. Loop through all the text-nodes of the article using document.querySelectorAll("*") and getting all the child-nodes with nodeType === 3
    • Get the length of the text of the node
    • Check if that length is larger than the index you are looking for
    • If the length is bigger then that means you have found the text node that contains the character.
    • Else reduce index by length and keep looping
  2. Create a copy with of that node with substring(0, index) and add it right after the node
  3. Create an HTMLElement that you can scroll to and it right after the node mentioned above
  4. Create another copy of the original node, this time with substring(index) and add it right after the new HTMLElement.
  5. Remove the original node
  6. Scroll to the HTMLElement using scrollTo

Scrolling to the index working example

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>

Scrolling to the element that contains the index (instead of exact character)

  1. Loop through all the text-nodes of the article using document.querySelectorAll("*") and getting all the child-nodes with nodeType === 3
    • Get the length of the text of the node
    • Check if that length is larger than the index you are looking for
    • If the length is bigger then that means you have found the text node that contains the character.
    • Else reduce index by length and keep looping
  2. Scroll to the parent HTMLElement of the node using scrollTo

Scrolling to the element that contains the index working example

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>
nick zoum
  • 7,216
  • 7
  • 36
  • 80
2

This answer would work on chrome. You may have to do some messing around to be browser compatable by looking at the MouseEvent properties.

<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>
cWerning
  • 583
  • 1
  • 5
  • 15
  • Good snippet, but is nesting another `div` really necessary here? Or can it be simplified as `
    `?
    – vahdet Jul 23 '19 at 19:11
  • 1
    If the entire page is that single div, then it would work. However, I would assume there would be a bunch of things in #wrapper along with the lorem ipsum div. You would want to scrollTop to be set to the wrapper div to match the screenY position. – cWerning Jul 23 '19 at 19:19
  • Note: if there is no overflow to the page, there will be no "scrolling" to the particular point because there is nothing to scroll. This is beneficial if you have a tall webpage, I.E. "quite long text like a complete lorem-ipsum passage" – cWerning Jul 23 '19 at 19:23
1

You could wrap sections of your text (paragraphs, sentences, words maybe) in <span> tags with incrementing ids and while user is setting up a bookmark store this id in local storage. And then scroll to this id on load (or use a bookmark redirect). But having a ridiculous amount of nodes might influence your application performance.

<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>

Alternatively you could store click position in a similar manner and use it in the same way. You can check how to reliably get click position here

1

You can use getClientRects method of range to get the position of a selection. See this question Coordinates of selected text in browser page Basically, getClientRects gives you the graphical rectangles of a given selection, allowing you to know the coordinates of a selection.

Now the problem is saving the selection itself outside of the DOM. The range object deals with nodes that are not referenced outside the DOM so you need a mechanism to save and recreate a given selection. Depending on the structure of the HTML it can be very simple, or quite complex. See this answer for how to save a selection in JSON: Save selection text and show it later in html and javascript This solution handles complicated cases, you can have complex HTML and still manage to save selection.

Combine the 2 answers and you have the wnated behavior, without adding anything to your HTML structure. To make the snippetwork, choose a point or a selection in the text. Use the button to copy the JSON of your selection. The with the paste button you paste the JSON to simulate what would happen when your page opens: you fetch the saved data and reinject it as a range, and then use scrollTo to go to the y coordinate of your selection. Note that you don't need to select anything, simply clicking in the text will create a collapsed selection which is enough for this to work.

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>
Julien Grégoire
  • 16,864
  • 4
  • 32
  • 57
0

The key point of your question is to get the point that you needs to scroll, here is the example to get the relative point of specified html element by given offset:

<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>
dexiang
  • 1,345
  • 16
  • 23