最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Scroll to element inside scrollable div - Stack Overflow

programmeradmin9浏览0评论

I'm having trouble scrolling to element inside scrollable div.

My code is quite simple and it mimics exact problem I'm having in my bigger project. When I click on text on the left side it should scroll to element with the same id on the right side but its not working. It always scrolls to different position and I dont know why.

If you manage to help me can you also provide short explanation what I'm doing wrong. I'm new to jQuery. Thanks

JSFiddle

$('.left span').click(function () {
    var id = $(this).attr('id');
    var element = $('.right span[id="' + id + '"]');
    $('.right').animate({ scrollTop: element.offset().top }, 500);
});

I'm having trouble scrolling to element inside scrollable div.

My code is quite simple and it mimics exact problem I'm having in my bigger project. When I click on text on the left side it should scroll to element with the same id on the right side but its not working. It always scrolls to different position and I dont know why.

If you manage to help me can you also provide short explanation what I'm doing wrong. I'm new to jQuery. Thanks

JSFiddle

$('.left span').click(function () {
    var id = $(this).attr('id');
    var element = $('.right span[id="' + id + '"]');
    $('.right').animate({ scrollTop: element.offset().top }, 500);
});
Share Improve this question edited Mar 10, 2015 at 18:40 apaul 16.2k8 gold badges49 silver badges82 bronze badges asked Mar 10, 2015 at 16:54 HnusHnus 9793 gold badges9 silver badges28 bronze badges 2
  • dont give same id to element first fix that. – Pushker Yadav Commented Mar 10, 2015 at 17:02
  • This should be an example which simulate my problem. In my project I have more clever way how to target these elements. Fixing the same ids doesnt change anything. – Hnus Commented Mar 10, 2015 at 17:05
Add a ment  | 

4 Answers 4

Reset to default 17

Ok... So you had a few issues with your original code.

First don't duplicate ID's, it is bad practice and it is invalid.

The next issue you were having is that you were getting the offset top of your spans. Offset will:

Get the current coordinates of the first element, or set the coordinates of every element, in the set of matched elements, relative to the document.

Emphasis on "relative to the document."

What you need is position. Position will:

Get the current coordinates of the first element in the set of matched elements, relative to the offset parent.

Emphasis on "relative to the offset parent."

Now, the main issue was that you were getting the offset after the click. Which sort of worked for your first click, but after that all of the values for offset top were skewed by the new scroll position.

To fix this you need to loop through the elements and get their position before you start clicking.

Try something like this:

$('.js_scrollTo').each(function () { // for each span
    var target = $(this).text(); // get the text of the span
    var scrollPos = $('#' + target).position().top; // use the text of the span to create an ID and get the top position of that element
    $(this).click(function () { // when you click each span 
        $('.right').animate({ // animate your right div
            scrollTop: scrollPos // to the position of the target 
        }, 400); 
    });
});
.left {
    position: fixed;
    top: 0;
    left: 0;
}
.right {
    position: relative; /* you'll need some position here for jQuery's position to work, otherwise it will be based on the document */
    width: 50%;
    height: 200px;
    overflow: scroll;
    float: right;
    display: block;
}
.right span {
    background-color: red;
}
<script src="https://ajax.googleapis./ajax/libs/jquery/2.1.0/jquery.min.js"></script>
<div class="left">
    <div class="js_scrollTo">test1</div>
    <div class="js_scrollTo">test2</div>
    <div class="js_scrollTo">test3</div>
</div>
<div class="right">Contrary to popular belief, Lorem Ipsum is not simply random text. It has roots in a piece of classical Latin literature from 45 BC, making it over 2000 years old. Richard McClintock, a Latin professor at Hampden-Sydney College in Virginia, looked up one of the more obscure Latin words, consectetur, from a Lorem Ipsum passage, and going through the cites of the word in classical literature, discovered the undoubtable source. Lorem Ipsum es from sections 1.10.32 and 1.10.33 of "de Finibus Bonorum et Malorum" (The Extremes of Good and Evil) by Cicero, written in 45 BC. This book is a treatise on the theory of ethics, very popular during the Renaissance. The first line of Lorem Ipsum, "Lorem ipsum dolor sit ameContrary to popular belief, Lorem Ipsum is not simply random text. It has roots in a piece of classical Latin literature from 45 BC, making it over 2000 years old. Richard McClintock, a Latin professor at Hampden-Sydney College in Virginia, looked up one of the more obscure Latin words, consectetur, from a Lorem Ipsum passage, and going through the cites of the word in classical literature, discovered the undoubtable source. Lorem Ipsum es from sections 1.10.32 and 1.10.33 of "de Finibus Bonorum et Malorum" (The Extremes of Good and Evil) by Cicero, written in 45 BC. This book is a treatise on the theory of ethics, very popular during the Renaissance. The first line of Lorem Ipsum, "Lorem ipsum dolor sit ame<span id="test1">test1</span>Contrary to popular belief, Lorem Ipsum is not simply random text. It has roots in a piece of classical Latin literature from 45 BC, making it over 2000 years old. Richard McClintock, a Latin professor at Hampden-Sydney College in Virginia, looked up one of the more obscure Latin words, consectetur, from a Lorem Ipsum passage, and going through the cites of the word in classical literature, discovered the undoubtable source. Lorem Ipsum es from sections 1.10.32 and 1.10.33 of "de Finibus Bonorum et Malorum" (The Extremes of Good and Evil) by Cicero, written in 45 BC. This book is a treatise on the theory of ethics, very popular during the Renaissance. The first line of Lorem Ipsum, "Lorem ipsum dolor sit ameContrary to popular belief, Lorem Ipsum is not simply random text. It has roots in a piece of classical Latin literature from 45 BC, making it over 2000 years old. Richard McClintock, a Latin professor at Hampden-Sydney College in Virginia, looked up one of the more obscure Latin words, consectetur, from a Lorem Ipsum passage, and going through the cites of the word in classical literature, discovered the undoubtable source. Lorem Ipsum es from sections 1.10.32 and 1.10.33 of "de Finibus Bonorum et Malorum" (The Extremes of Good and Evil) by Cicero, written in 45 BC. This book is a treatise on the theory of ethics, very popular during the Renaissance. The first line of Lorem Ipsum, "Lorem ipsum dolor sit ame<span id="test2">test2</span> 1.10.32 and 1.10.33 of "de Finibus Bonorum et Malorum" (The Extremes of Good and Evil) by Cicero, written in 45 BC. This book is a treatise on the theory of ethics, very popular during the Renaissance. The first line of Lorem Ipsum, "Lorem ipsum dolor sit ameContrary to popular belief, Lorem Ipsum is not simply random text. It has roots in a piece of classical Latin literature from 45 BC, making it over 2000 years old. Richard McClintock, a Latin professor at Hampden-Sydney College in Virginia, looked up one of the more obscure Latin words, consectetur, from a Lorem Ipsum passage, and going through the cites of the word in classical literature, discovered the undoubtable source. Lorem Ipsum es from sections 1.10.32 and 1.10.33 of "de Finibus Bonorum et Malorum" (The Extremes of Good and Evil) by Cicero, written in 45 BC. This book is a treatise on the theory of ethics, very popular during the Renaissance. The first line of Lorem Ipsum, "Lorem ipsum dolor sit ame<span id="test3">test3</span>Contrary to popular belief, Lorem Ipsum is not simply random text. It has roots in a piece of classical Latin literature from 45 BC, making it over 2000 years old. Richard McClintock, a Latin professor at Hampden-Sydney College in Virginia, looked up one of the more obscure Latin words, consectetur, from a Lorem Ipsum passage, and going through the cites of the word in classical literature, discovered the undoubtable source. Lorem Ipsum es from sections 1.10.32 and 1.10.33 of "de Finibus Bonorum et Malorum" (The Extremes of Good and Evil) by Cicero, written in 45 BC. This book is a treatise on the theory of ethics, very popular during the Renaissance. The first line of Lorem Ipsum, "Lorem ipsum dolor sit ameContrary to popular belief, Lorem Ipsum is not simply random text. It has roots in a piece of classical Latin literature from 45 BC, making it over 2000 years old. Richard McClintock, a Latin professor at Hampden-Sydney College in Virginia, looked up one of the more obscure Latin words, consectetur, from a Lorem Ipsum passage, and going through the cites of the word in classical literature, discovered the undoubtable source. Lorem Ipsum es from sections 1.10.32 and 1.10.33 of "de Finibus Bonorum et Malorum" (The Extremes of Good and Evil) by Cicero, written in 45 BC. This book is a treatise on the theory of ethics, very popular during the Renaissance. The first line of Lorem Ipsum, "Lorem ipsumRenaissance. The first line of Lorem Ipsum, "Lorem ipsum dolor sit ameContrary to popular belief, Lorem Ipsum is not simply random text. It has roots in a piece of classical Latin literature from 45 BC, making it over 2000 years old. Richard McClintock, a Latin professor at Hampden-Sydney College in Virginia, looked up one of the more obscure Latin words, consectetur, from a Lorem Ipsum passage, and going through the cites of the word in classical literature, discovered the undoubtable source. Lorem Ipsum es from sections 1.10.32 and 1.10.33 of "de Finibus Bonorum et Malorum" (The Extremes of Good and Evil) by Cicero, written in 45 BC. This book is a treatise on the theory of ethics, very popular during the Renaissance. The first line of Lorem Ipsum, "Lorem ipsum dolor sit ame<span id="test3">assasdasdasd</span>Contrary to popular belief, Lorem Ipsum is not simply random text. It has roots in a piece of classical Latin literature from 45 BC, making it over 2000 years old. Richard McClintock, a Latin professor at Hampden-Sydney College in Virginia, looked up one of the more obscure Latin words, consectetur, from a Lorem Ipsum passage, and going through the cites of the word in classical literature, discovered the undoubtable source. Lorem Ipsum es from sections 1.10.32 and 1.10.33 of "de Finibus Bonorum et Malorum" (The Extremes of Good and Evil) by Cicero, written in 45 BC. This book is a treatise on the theory of ethics, very popular during the Renaissance. The first line of Lorem Ipsum, "Lorem ipsum dolor sit ameContrary to popular belief, Lorem Ipsum is not simply random text. It has roots in a piece of classical Latin literature from 45 BC, making it over 2000 years old. Richard McClintock, a Latin professor at Hampden-Sydney College in Virginia, looked up one of the more obscure Latin words, consectetur, from a Lorem Ipsum passage, and going through the cites of the word in classical literature, discovered the undoubtable source. Lorem Ipsum es from sections 1.10.32 and 1.10.33 of "de Finibus Bonorum et Malorum" (The Extremes of Good and Evil) by Cicero, written in 45 BC. This book is a treatise on the theory of ethics, very popular during the Renaissance. The first line of Lorem Ipsum, "Lorem</div>

You should try like this:

document.getElementById("YOUR ID").scrollIntoView({
   behavior: "smooth",
   block: "start",
   inline: "start"
});

you should not give the same id twice on a page. give each span in the right for instance:

<span id="1to"></span>

and call the animate function for the element with # + id + to

var element = $('#'+id+'to');
$('.right').animate({ scrollTop: element.offset().top }, 500);

also you could position your .left "menu" at a fixed position and animate the whole html, body to the certain position.

try this fiddle: https://jsfiddle/xchqw7uz/

works as you intend it to. and is easier to use, since you dont need so many ids

I had trouble scrolling to element inside scrollable div (or other scrollable element) witch may be inside other scrollable element witch may be inside scrollable page or other scrollable element and so on.

I have spent some time and made the following decision:

utils.scrollVerticallyToElement(jqElement, true);

where jqElement is an element (wrapped in jQuery object) to scroll to, the second argument is a flag that indicates whether to animate scrolling process (true to animate) and scrollVerticallyToElement is a method of the following object:

var utils = {
    clearAllSelections: function() {
        //clearing selected text if any
        if (document.selection && document.selection.empty) {
            document.selection.empty();
        } else if (window.getSelection) {
            var sel = window.getSelection();
            sel.removeAllRanges();
        }
    },

    getWindowClientVisibleRect: function () {
        var html = document.documentElement;
        var body = document.body;
        var doc = (html && html.clientWidth) ? html : body;

        var scrollTop = window.pageYOffset || html.scrollTop || body.scrollTop;
        var scrollLeft = window.pageXOffset || html.scrollLeft || body.scrollLeft;

        var clientTop = html.clientTop || body.clientTop || 0;
        var clientLeft = html.clientLeft || body.clientLeft || 0;

        var windowLeft = scrollLeft - clientLeft;
        var windowRight = doc.clientWidth + windowLeft;
        var windowTop = scrollTop - clientTop;
        var windowBottom = doc.clientHeight + windowTop;

        return { left: windowLeft, top: windowTop, right: windowRight, bottom: windowBottom };
    },

    getScrollableElementVisibleRect: function (element) {
        var left = element.scrollLeft - element.clientLeft;
        var top = element.scrollTop - element.clientTop;

        return { left: left, top: top, right: element.clientWidth + left, bottom: element.clientHeight + top };
    },

    getCoordinates: function (element) {
        var top = 0, left = 0;

        if (element.getBoundingClientRect) {
            var windowRect = this.getWindowClientVisibleRect();
            var elementRect = element.getBoundingClientRect();

            top = Math.round(elementRect.top + windowRect.top);
            left = Math.round(elementRect.left + windowRect.left);
        }
        else {
            while (element) {
                top = top + parseInt(element.offsetTop);
                left = left + parseInt(element.offsetLeft);
                element = element.offsetParent;
            }
        }
        return { top: top, left: left, right: left + element.offsetHeight, bottom: top + element.offsetHeight };
    },

    scrollWindowVerticallyToElement: function (element) {
        var elemCoord = this.getCoordinates(element);
        var wndRect = this.getWindowClientVisibleRect();

        if (elemCoord.top < wndRect.top) {
            window.scrollTo(wndRect.left, elemCoord.top);
        }
        else if (elemCoord.bottom > wndRect.bottom) {
            window.scrollBy(0, elemCoord.bottom - wndRect.bottom);
        }
    },

    scrollVerticallyToElement: function (jqElement, useAnimation) {
        if (!jqElement || !jqElement.parent) {
            return;
        }

        var scrollToElement;
        if (!useAnimation) {
            scrollToElement = function(jq, scrollValue) {
                jq.scrollTop(scrollValue);
            };
        }
        else {
            scrollToElement = function (jq, scrollValue) {
                jq.animate({
                    scrollTop: scrollValue
                }, 'fast');
            };
        }

        jqElement.parents().each(function () {
            var jqThis = $(this);

            var top = Math.round(jqElement.position().top);
            var bottom = top + jqElement.innerHeight();

            var parentTop = Math.round(jqThis.position().top);
            var parentBottom = parentTop + jqThis.innerHeight();

            if (top < parentTop && jqThis.scrollTop() > 0) {
                scrollToElement(jqThis, jqThis.scrollTop() - parentTop + top);
            } else if (bottom > parentBottom) {
                scrollToElement(jqThis, jqThis.scrollTop() - parentBottom + bottom);
            }
        });

        this.scrollWindowVerticallyToElement(jqElement.get(0));
    }
};

This code was tested in Opera, Firefox and IE. And it really works!

Please, fill free to use utils object in your project if you need (you may even rename it if you need).

发布评论

评论列表(0)

  1. 暂无评论