web-dev-qa-db-ja.com

要素がスクロール可能かどうかを正確に判断する

特定の要素がスクロールされているかどうかを判断し、ビューポートを基準にして要素の上部で監視可能なバインドを更新するカスタムノックアウトバインディングに取り組んでいます。今のところ、製本はうまくいくようですが、うまくいかない状況があるのではないかと心配です。

HTML:

Scroll position: <span data-bind="text: scrollPosition"></span>

<div class="longdiv">    
    <p data-bind="scroll: scrollPosition">This is some text.</p>
    <div class="shim"></div>
</div>

CSS:

.longdiv {
    width: 200px;
    height: 200px;
    overflow: scroll;
    border: 1px solid black;
}

JS:

ko.bindingHandlers.scroll = {
    init: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
        var firstScrollableContainer = null;

        var binding = allBindings.get('scroll');

        $(element).parents().each(function (i, parent) {
            if ($(parent).css('overflow')=='scroll') {
                firstScrollableContainer = parent;
                return false;
            }
        });

        firstScrollableContainer = firstScrollableContainer || window;                

        binding(element.getBoundingClientRect().top);

        $(firstScrollableContainer).scroll(function() {            
            binding(element.getBoundingClientRect().top);
        });
    }
};

var ViewModel = function() {
    var self = this;

    self.scrollPosition = ko.observable(0);
};

ko.applyBindings(new ViewModel());

JSFiddle

バインディングは要素を受け取り、jQueryを使用して親チェーンを上に移動し、親要素にオーバーフローがあるかどうかを確認します:スクロールセット。オーバーフロー:scrollのあるdivが見つかった場合、イベントハンドラーをその要素のscrollイベントにバインドします。オーバーフロー:scrollを持つ親が見つからない場合は、ウィンドウのscrollイベントにバインドします。

したがって、次のように構造化されたドキュメントを前提として、私が探しているものは次のとおりです。

body > div > div > div > p

は、スクロール可能なpに最も近い要素を含むため、イベントハンドラーをアタッチできます。

私の質問は:オーバーフローを見ている:親要素がスクロールできるかどうかを確認するのに十分なテストをスクロールしますか?そうでない場合、私は何を見るべきですか?

編集:あなたの有益なコメントと回答に基づいて、ここに私が思いついた解決策があります:

function scrollable(element) {
    var vertically_scrollable, horizontally_scrollable;

    var e = $(element);

     if (   e.css('overflow') == 'scroll' 
         || e.css('overflow') == 'auto'
         || e.css('overflowY') == 'scroll'
         || e.css('overflowY') == 'auto'
         || e.css('height') != 'none'
         || e.css('max-height') != 'none'                          
         ) {
         return true;
    } else {
        return false;
    }
}
13
McCroskey

要素がスクロールできるかどうか、または現在スクロールできるかどうかを知りたいですか?

要素はスクロールできますか?

要素に固定のheight(またはmax-height)があり、overflow-yscrollまたはautoの場合、要素はスクロールできます。ただし、 要素の高さが固定されているかどうかを通知する は簡単ではないため、overflow-yを確認するだけで十分です。

e.css('overflow-y') == 'scroll' || e.css('overflow-y') == 'auto'

要素は今スクロールできますか?

要素のscrollHeightclientHeightより大きい場合、およびclientWidthoffsetWidthを比較することで判別できるスクロールバーがある場合、要素は今すぐスクロールできます。 (余白と境界線を考慮に入れて)またはoverflow-yscrollまたはautoであるかどうかを確認します。

10
Michael Best

これはおそらく最も安全な解決策です(jQueryが必要です。プレーンJavaScriptについては以下を参照してください)。

$.fn.isHScrollable = function () {
    return this[0].scrollWidth > this[0].clientWidth;
};

$.fn.isVScrollable = function () {
    return this[0].scrollHeight > this[0].clientHeight;
};

$.fn.isScrollable = function () {
    return this[0].scrollWidth > this[0].clientWidth || this[0].scrollHeight > this[0].clientHeight;
};

次に、要素が次のようにスクロール可能かどうかを確認できます。

$(parent).isScrollable();

JQueryなしで使用する場合は、次のような関数を実装できます。

function isScrollable(element) {
    return element.scrollWidth > element.clientWidth || element.scrollHeight > element.clientHeight;
};

var myParent = document.getElementById('myParent')
isScrollable(myParent)

10
RafaelKr

2つの答えをマージし、自分の ちょっとしたもの を追加すると、これは私が垂直スクロールをチェックするために使用するものです。他の場合に簡単に変換できます。 (H&VH)

function isScrollable(e){
    if( e.scrollTopMax !== undefined )
        return e.scrollTopMax > 0; //All Hail Firefox and it's superior technology!

    if( e == document.scrollingElement ) //If what you're checking is BODY (or HTML depending on your css styles)
        return e.scrollHeight > e.clientHeight; //This is a special case.

    return e.scrollHeight > e.clientHeight && ["scroll", "auto"].indexOf(getComputedStyle(e).overflowY) >= 0



}

これをFirefoxとChromiumでテストしました。両方のLinux。あなたはまだあなた自身のためにそれらをチェックしたいかもしれません。

0
aliqandil