I am trying to change the color of elements when they are between 30% and 60% of the viewport.
So I have this grid of elements stacking side
Create a div width width:100%
and height:100%
that represent the viewport. Inside this div you place your grid system.
Than you need to use jquery .position()
jquery position
var grid = $( "griddiv's" );
var position = grid.position();
var height = $('parentdiv').height();
lower = 0.3 * height;
upper = 0.6 * height;
if(grid.top >= lower && grid.top <= upper){
$('gridcell').css('background','red');
}
I didn't test it but I hope it works
I was free to create a plugin for this. Within options you can set percents, css class, trigger event and execution delay (css changed to responsive for presentation only):
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();
ul {
margin: 0 auto;
padding: 0;
}
ul li {
width: 32.73%;
height: 0;
padding-bottom: 3.5%; /* responsive height */
background: #f5f5f5;
float: left;
margin: .3%;
list-style:none;
}
ul li.middleviewport {
background:red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<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><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li>
</ul>
</body>
Fiddle here
scroll
event handler on window
li
elements to check if the element is in the interested viewportli
position from top
and check if it is in the interested viewport section.Demo:
Changed the height of li
for demo purpose.
See the comments inline in the code.
$(document).ready(function() {
// Get viewport height, gridTop and gridBottom
var windowHeight = $(window).height(),
gridTop = windowHeight * .3,
gridBottom = windowHeight * .6;
$(window).on('scroll', function() {
// On each scroll check if `li` is in interested viewport
$('ul li').each(function() {
var thisTop = $(this).offset().top - $(window).scrollTop(); // Get the `top` of this `li`
// Check if this element is in the interested viewport
if (thisTop >= gridTop && (thisTop + $(this).height()) <= gridBottom) {
$(this).css('background', 'red');
} else {
$(this).css('background', 'gray');
}
});
});
});
ul {
margin: 0;
list-style-type: none;
padding: 0;
}
ul li {
width: 50px;
height: 30px;
background: #f5f5f5;
float: left;
margin: 10px;
text-align: center;
padding-top: 10px
}
ul li.middleviewport {
background: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.10.0/jquery.min.js"></script>
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
<li>6</li>
<li>7</li>
<li>8</li>
<li>9</li>
<li>10</li>
<li>11</li>
<li>12</li>
<li>13</li>
<li>14</li>
<li>15</li>
<li>16</li>
<li>17</li>
<li>18</li>
<li>19</li>
<li>20</li>
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
<li>6</li>
<li>7</li>
<li>8</li>
<li>9</li>
<li>10</li>
<li>11</li>
<li>12</li>
<li>13</li>
<li>14</li>
<li>15</li>
<li>16</li>
<li>17</li>
<li>18</li>
<li>19</li>
<li>20</li>
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
<li>6</li>
<li>7</li>
<li>8</li>
<li>9</li>
<li>10</li>
<li>11</li>
<li>12</li>
<li>13</li>
<li>14</li>
<li>15</li>
<li>16</li>
<li>17</li>
<li>18</li>
<li>19</li>
<li>20</li>
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
<li>6</li>
<li>7</li>
<li>8</li>
<li>9</li>
<li>10</li>
<li>11</li>
<li>12</li>
<li>13</li>
<li>14</li>
<li>15</li>
<li>16</li>
<li>17</li>
<li>18</li>
<li>19</li>
<li>20</li>
</ul>
[[ This example checks if ANY part of the element is inside the specified region ]]
When you have the top and bottom coordinates of two boxes, you can check if the two boxes overlap by checking:
box1.top < box2.bottom && box1.bottom > box2.top
In the following example, box1 is the 30%-60% portion of window while box2 is each list item. Add debounce function and we have:
var timeout;
$(window).on("load scroll resize", function() {
if (timeout) {
clearTimeout(timeout);
}
timeout = setTimeout(function() {
var $window = $(window),
hitbox_top = $window.scrollTop() + $window.height() * .3,
hitbox_bottom = $window.scrollTop() + $window.height() * .6;
$("li").each(function() {
var $element = $(this),
element_top = $element.offset().top,
element_bottom = $element.offset().top + $element.height();
$element.toggleClass("middle-viewport", hitbox_top < element_bottom && hitbox_bottom > element_top);
});
}, 200);
});
#overlay {
position: fixed;
left: 0;
top: 30%;
width: 100%;
height: 30%;
background-color: rgba(0, 192, 255, .5);
}
ul {
padding: 0;
text-align: center;
}
li {
display: inline-block;
margin: 10px;
width: 200px;
height: 200px;
background-color: #F5F5F5;
}
li.middle-viewport {
background-color: #FF0000;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<div id="overlay"></div>
<ul>
<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>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
</ul>
Improved @Tushar's solution to make it work even after a resize of the window (a recalculation of the viewport is necessary each time, not only at the beginning), and to make it start already highlighted, without the need to scroll.
Also improved a bit the graphic of the example to highlight the interested area.
Running demo
$(document).ready(function() {
$(window).on('scroll', function() {
var windowHeight = $(window).height(),
gridTop = windowHeight * .3,
gridBottom = windowHeight * .6;
$('ul li').each(function() {
var thisTop = $(this).offset().top - $(window).scrollTop();
if (thisTop > gridTop && (thisTop + $(this).height()) < gridBottom) {
$(this).css('background', 'red');
} else {
$(this).css('background', 'silver');
}
});
});
$(window).trigger('scroll');
});
ul {
margin: auto;
}
ul li {
width: 300px;
height: 10px;
background: silver;
float: left;
margin: 10px;
list-style: none;
}
ul li.middleviewport {
background: red;
}
#viewportMask {
position: fixed;
top: 30%;
bottom: 40%;
left: 0;
right: 0;
background: red;
opacity: 0.2;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<div id="viewportMask"></div>
<ul>
<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>