Get the element which is the most visible on the screen

后端 未结 4 692
我寻月下人不归
我寻月下人不归 2020-12-16 03:47

I would like to get the one element which is the most visible on the screen (takes up the most space). I have added an example picture below to understand my question a bit

4条回答
  •  粉色の甜心
    2020-12-16 03:59

    TLDR:

    Inspired by this question and the necessity for similar functionality in my own projects, I've written a module/jQuery plugin based on the code below. If you're not interested in the 'how', just download that or install with your favourite package manager.

    Original Answer:

    The answer provided by exabyssus works well in most cases, apart from when neither of an element's top or bottom is visible e.g when the element height is greater than the window height.

    Here's an updated version which takes that scenario into account and uses getBoundingClientRect which is supported right the way down to IE8:

    // Usage: var $element = getMostVisible($('.elements' ));
    function getMostVisible($elements) {
        var element,
            viewportHeight = $(window).height(),
            max = 0;
    
        $elements.each(function() {
            var visiblePx = getVisibleHeightPx($(this), viewportHeight);
    
            if (visiblePx > max) {
                max = visiblePx;
                element = this;
            }
        });
    
        return $elements.filter(element);
    }
    
    function getVisibleHeightPx($element, viewportHeight) {
        var rect = $element.get(0).getBoundingClientRect(),
            height = rect.bottom - rect.top,
            visible = {
                top: rect.top >= 0 && rect.top < viewportHeight,
                bottom: rect.bottom > 0 && rect.bottom < viewportHeight
            },
            visiblePx = 0;
    
        if (visible.top && visible.bottom) {
            // Whole element is visible
            visiblePx = height;
        } else if (visible.top) {
            visiblePx = viewportHeight - rect.top;
        } else if (visible.bottom) {
            visiblePx = rect.bottom;
        } else if (height > viewportHeight && rect.top < 0) {
            var absTop = Math.abs(rect.top);
    
            if (absTop < height) {
                // Part of the element is visible
                visiblePx = height - absTop;
            }
        }
    
        return visiblePx;
    }
    

    This returns the most visible element based on pixels rather than as a percentage of the height of the element, which was ideal for my use-case. It could easily be modified to return a percentage if desired.

    You could also use this as a jQuery plugin so you can get the most visible element with $('.elements').mostVisible() rather than passing the elements to the function. To do that, you'd just need to include this with the two functions above:

    $.fn.mostVisible = function() {
        return getMostVisible(this);
    };
    

    With that in place you can chain your method calls rather than having to save the element into a variable:

    $('.elements').mostVisible().addClass('most-visible').html('I am most visible!');
    

    Here's all of that wrapped up in a little demo you can try out right here on SO:

    (function($) {
      'use strict';
    
      $(function() {
        $(window).on('scroll', function() {
          $('.the-divs div').html('').removeClass('most-visible').mostVisible().addClass('most-visible').html('I am most visible!');
        });
      });
    
      function getMostVisible($elements) {
        var element,
          viewportHeight = $(window).height(),
          max = 0;
    
        $elements.each(function() {
          var visiblePx = getVisibleHeightPx($(this), viewportHeight);
    
          if (visiblePx > max) {
            max = visiblePx;
            element = this;
          }
        });
    
        return $elements.filter(element);
      }
    
      function getVisibleHeightPx($element, viewportHeight) {
        var rect = $element.get(0).getBoundingClientRect(),
          height = rect.bottom - rect.top,
          visible = {
            top: rect.top >= 0 && rect.top < viewportHeight,
            bottom: rect.bottom > 0 && rect.bottom < viewportHeight
          },
          visiblePx = 0;
    
        if (visible.top && visible.bottom) {
          // Whole element is visible
          visiblePx = height;
        } else if (visible.top) {
          visiblePx = viewportHeight - rect.top;
        } else if (visible.bottom) {
          visiblePx = rect.bottom;
        } else if (height > viewportHeight && rect.top < 0) {
          var absTop = Math.abs(rect.top);
    
          if (absTop < height) {
            // Part of the element is visible
            visiblePx = height - absTop;
          }
        }
    
        return visiblePx;
      }
    
    
    
      $.fn.mostVisible = function() {
        return getMostVisible(this);
      }
    
    })(jQuery);
    .top {
      height: 900px;
      background-color: #999
    }
    
    .middle {
      height: 200px;
      background-color: #eee
    }
    
    .bottom {
      height: 600px;
      background-color: #666
    }
    
    

提交回复
热议问题