JSFiddle - React, Tailwind, and code Playground

by Andris Gangis

HTML

<script src="https://code.jquery.com/jquery-3.0.0.min.js"></script>
<div class="ele"></div>
<div class="ele"></div>
<div class="ele"></div>
<div class="ele"></div>
<div class="ele"></div>
<div class="ele"></div>
<div class="ele"></div>

CSS

body {
    padding: 200px 0;
}

.ele {
    background-color: red;
    height: 300px;
    width: 300px;
    margin: 40px auto;
}

.ele.act {
  background: green;
}

JavaScript

// init on page ready
$(function() {
    // check on each scroll event
    $(window).scroll(function(){
        // elements to be tested
        var _elements = $('.ele');
				_elements.removeClass('act');
        // get most visible element (result)
        var ele = findMostVisible(_elements);
        if(ele)
           ele.addClass('act')
    });
});


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;
}