12

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

example

The two black borders are the sides of a screen. As you can see, the green box (div2) is the most visible on the screen - I would like to know how I can get that element. The most visible element should not have to be fully visible.

I have done a quick (it wasn't THAT quick) seach but to no avail, if I have missed it - my apologies.

J. Titus
  • 9,535
  • 1
  • 32
  • 45
Yates
  • 532
  • 7
  • 23
  • 1
    You can get them clientheight , after subtract their difference,and take that picture whose height is greater than – Vanya Avchyan Jul 13 '16 at 20:17
  • 1
    This is not trivial and without any code of yours makes it too broad a question. This site works by you providing some code that isn't doing what is expected and others help fix that code....not write code from scratch or provide tutorial on what to do – charlietfl Jul 13 '16 at 20:17
  • have you tried anything. post your code. SO is not a code writing service. – bhspencer Jul 13 '16 at 20:27
  • @VanyaAvchyan I'm not entirely sure what you mean. Care providing more information on a step-to-step basis? – Yates Jul 13 '16 at 20:29
  • @charlietfl I have no code because I cannot think of a way to try and get the result I want. There are many questions by many people who have not provided code because they don't know a possible way to solve their problem or come close to and those questions are still there. – Yates Jul 13 '16 at 20:29
  • http://stackoverflow.com/a/1076255/1675954 – Rachel Gallen Jul 13 '16 at 20:30
  • @bhspencer Indeed SO is not. But there is nothing holding anyone back by providing a step-to-step basis on how to solve the problem. I am fully capable of writing the code but I don't know where to begin. My post also states that I want to know how, I never intentionally asked for a full set of code. – Yates Jul 13 '16 at 20:30
  • @RachelGallen the code provided in the link is a way to get the highest element within a div. The problem is that I could have a huge div which is not seen on the screen so it is not the most visible. – Yates Jul 13 '16 at 20:32
  • @ThomasYates start by figuring out how to get position of viewport with regard to document along with it's dimensions which are the window size. then you need to loop over dom and start comparing based on element offsets, heights and widths to determine area that is visible – charlietfl Jul 13 '16 at 20:35
  • @ThomasYates the code iterates through all elements and can easily be adapted for your purposes. As previously stated, SO is a guide, not a service. You have to start to learn sometime! – Rachel Gallen Jul 13 '16 at 20:35
  • 1
    I'm interested to see what answer you end up getting. I'm not sure about how to go about this either. To those wanting this question closed: I don't understand "you need code to post a question to SO". A broad question maybe just needs a broad answer? – KidBilly Jul 13 '16 at 20:36
  • 2
    You might find [jQuery.fracs](https://larsjung.de/jquery-fracs/latest/demo/) useful. – showdev Jul 13 '16 at 21:14
  • @showdev this may actually be a more practical use of what I eventually want to accomplish. I have marked the answer by exabyssus as correct seeing as it fully answers my question but will also dive into the code of fracs right away! Thank you. – Yates Jul 13 '16 at 21:26

3 Answers3

14

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
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div class="the-divs">
  <div class="top"></div>
  <div class="middle"></div>
  <div class="bottom"></div>
</div>
Community
  • 1
  • 1
Andy
  • 4,901
  • 5
  • 35
  • 57
2

Yes, this question is too broad. But I was interested on solving it. Here is crude example on how to accomplish it.

I tried to explain what's going on with comments. It surely can be done better, but I hope it helps.

// init on page ready
$(function() {
    // check on each scroll event
    $(window).scroll(function(){
        // elements to be tested
        var _elements = $('.ele');

        // get most visible element (result)
        var ele = findMostVisible(_elements);
    });
});


function findMostVisible(_elements) {

    // find window top and bottom position.
    var wtop = $(window).scrollTop();
    var wbottom = wtop + $(window).height();


    var max = 0; // use to store value for testing
    var maxEle = false; // use to store most visible element

    // find percentage visible of each element
    _elements.each(function(){

        // get top and bottom position of the current element
        var top = $(this).offset().top;
        var bottom = top + $(this).height();

        // get percentage of the current element
        var cur = eleVisible(top, bottom, wtop, wbottom);

        // if current element is more visible than previous, change maxEle and test value, max 
        if(cur > max) {
            max = cur;
            maxEle = $(this);
        }
    });

    return maxEle;
}

// find visible percentage
function eleVisible(top, bottom, wtop, wbottom) {

    var wheight = wbottom - wtop;

    // both bottom and top is vissible, so 100%
    if(top > wtop && top < wbottom && bottom > wtop && bottom < wbottom)
    {
        return 100;
    }

    // only top is visible
    if(top > wtop && top < wbottom)
    {
        return  100 + (wtop - top) / wheight * 100;
    }

    // only bottom is visible
    if(bottom > wtop && bottom < wbottom)
    {
        return  100 + (bottom - wbottom) / wheight * 100;
    }

    // element is not visible
    return 0;
}

Working example - https://jsfiddle.net/exabyssus/6o30sL24/

exabyssus
  • 451
  • 2
  • 9
  • Sometimes maxEle is a boolean and sometimes it is an element. Is that what you intended? – bhspencer Jul 13 '16 at 21:07
  • @bhspencer that a bug, maxEle is false if no elements are visibe and _element_ if there is – exabyssus Jul 13 '16 at 21:12
  • 1
    I added a working example, hope that helps. https://jsfiddle.net/exabyssus/6o30sL24/ – exabyssus Jul 13 '16 at 21:20
  • It is perfect and absolutely what I was going for. Thank you very much! – Yates Jul 13 '16 at 21:25
  • I know this answer is old, but for anybody stumbling across it from Google like me: The `eleVisible` function incorrectly returns `0` for any elements where neither the top or bottom is visible (i.e elements with a height greater than the window height) – Andy Sep 19 '16 at 14:44
0
<style>
    .block{
        padding: 20px;
        border:2px solid #000;
        height: 200px;
        overflow:hidden;
    }
    .green{
        border: 1px solid green;
        height: 150px;
        margin:20px 0px;
    }
    .red{
        border: 1px solid red;
        height: 100px;
    }
</style>
<div class="block">
    <div class="example green"></div>
    <div class="example red"></div>
</div>


var divs = $('.example');
var obj = {};
var heights = [];

$.each(divs,function (key, val)
{
    heights.push($(val).outerHeight());
    obj[$(val).outerHeight()] = $(val);
});
var max = Math.max.apply(null, heights);

console.log(obj[max]);
Vanya Avchyan
  • 880
  • 7
  • 24