You'll end up calling visiblityPosition() twice on the element that is before the first visible, right?

I'm not sure that is a big deal, but you might think about tweaking the algorithm to avoid that.  If you don't hit the prev === null case in the loop above, this loop is always going to run exactly once, right?