JSFiddle - React, Tailwind, and code Playground

HTML

<body>
    <ul class="check_viewport">
        <li></li>
        <li></li>
        <li></li>
        <li></li>
        <li></li>
        <li></li>
        <li></li>
        <li></li>
        <li></li>
        <li></li>
        <li></li>
        <li></li>
        <li></li>
        <li></li>
        <li></li>
        <li></li>
        <li></li>
        <li></li>
        <li></li>
        <li></li>
        <li></li>
        <li></li>
        <li></li>
    </ul>
</body>

CSS

ul {
    margin: auto;
}
ul li {
    width: 300px;
    height: 50px;
    background: #f5f5f5;
    float: left;
    margin: 5px;
    list-style:none;
}
ul li.middleviewport {
    background:red;
}

JavaScript

jQuery.fn.extend({
    markInViewport: function (options) {
        var that = this;
        this.defaults = {
            percentTop: 30,
            percentBottom: 40,
            cssClass: 'middleviewport',
            event: 'scroll resize',
            delay: 10
        };
        this.options = $.extend(that.defaults, options);
        this.win = $(window);
        this.delayChecking = null;
        this.items = [];
        this.checkItems = function (items) {
            clearTimeout(that.delayChecking);
            that.delayChecking = setTimeout(function () {
                var thisWindowHeight = that.win.height();
                var thisWindowScrollTop = that.win.scrollTop();
                that.items.each(function (j) {
                    var thisItem = $(this);
                    var thisItemHeight = thisItem.outerHeight();
                    var thisItemPositionTop = thisItem.offset().top;
                    var currentPercentTop = (thisItemPositionTop - thisWindowScrollTop) / thisWindowHeight * 100;
                    var currentPercentBottom = (thisWindowScrollTop + thisWindowHeight - thisItemPositionTop - thisItemHeight) / thisWindowHeight * 100;
                    thisItem.toggleClass(that.options.cssClass, currentPercentTop >= that.options.percentTop && currentPercentBottom >= that.options.percentBottom);
                });
            }, that.options.delay);
        };
        return this.each(function () {
            that.items = that.children();
            $(window).on(that.options.event, that.checkItems);
            that.checkItems();
        });
    }
});



$('.check_viewport').markInViewport();