I am trying to create a simple Read More example. It consists of a paragraph and a button with half of the paragraph enclosed in a span tag which is initially set to hidden. When user clicks on Read More button the hidden span shows up. I have got the working code but just want to do a fade in effect like JQuery but with pure Javascript. Anyone please help.
var span = document.getElementsByTagName('span')[0];
var hideshow = document.getElementById('hideshow');
span.style.display = 'none';
hideshow.onclick = function() {
span.style.display = 'block';
};
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ipsa maiores dolore earum ducimus molestiae, aut. <span>Quisquam consequuntur, maiores et, doloremque atque provident similique consequatur totam voluptas vitae veniam, molestiae laborum.</span></p>
<button id="hideshow">Read More</button>
One approach is to use a CSS3 transition in order to transition the element's opacity.
In the example below, the class fade-in is added to the child span element when clicking the button.
var button = document.querySelector('.read-more');
button.addEventListener('click', function(event) {
var span = event.target.previousElementSibling.querySelector('span');
span.classList.add('fade-in');
});
.show-more span {
display: inline-block;
height: 0;
overflow: hidden;
transition: opacity 2s;
opacity: 0;
}
.show-more span.fade-in {
height: auto;
opacity: 1;
}
<p class="show-more">Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ipsa maiores dolore earum ducimus molestiae, aut. <span>Quisquam consequuntur, maiores et, doloremque atque provident similique consequatur totam voluptas vitae veniam, molestiae laborum.</span></p>
<button class="read-more">Read More</button>
If you want an approach that works for multiple elements, you could also use the following:
var buttons = document.querySelectorAll('.read-more');
for (var i = 0; i < buttons.length; i++) {
buttons[i].addEventListener('click', function(event) {
var span = event.target.previousElementSibling.querySelector('span');
span.classList.add('fade-in');
});
}
.show-more span {
display: inline-block;
height: 0;
overflow: hidden;
transition: opacity 2s;
opacity: 0;
}
.show-more span.fade-in {
height: auto;
opacity: 1;
}
<p class="show-more">Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ipsa maiores dolore earum ducimus molestiae, aut. <span>Quisquam consequuntur, maiores et, doloremque atque provident similique consequatur totam voluptas vitae veniam, molestiae laborum.</span></p>
<button class="read-more">Read More</button>
<p class="show-more">Another shorter paragraph. <span>Quisquam consequuntur, maiores et, doloremque atque provident similique consequatur totam voluptas vitae veniam, molestiae laborum.</span></p>
<button class="read-more">Read More</button>
Starting here
span.style.opacity = 0;
You'll need to gradually transition the opacity to here.
span.style.opacity = 1;
You'll need to use an asynchronous construct (setTimeout/setInterval/requestAnimationFrame) for iterating, because a synchronous one (while/for/for-in/forEach) will block the main thread, preventing the browser from actually rendering the element with the updated opacity.
function fadeIn(element) {
function transition() {
if(element.style.opacity < 1) {
requestAnimationFrame(transition);
element.style.opacity = Number(element.style.opacity) + 0.05;
}
}
transition();
}
Alternatively, if you're happy to use CSS (rather than pure JS) you can do this with classes and transitions.
.out {
opacity: 0;
transition-duration: 0.5s;
}
.in {
opacity: 1;
transition-duration: 0.5s;
}
Make sure that the element has the out class when it arrives in the DOM, then when you're ready to fade it in, swap it for the in class and the browser will handle the animation for you.
var duration = 2000; // msecs
document.getElementById('hideshow').onclick = () => {
requestAnimationFrame((start_time) => {
var anim = (time) => {
var p = (time - start_time) / duration;
(p < 1) && requestAnimationFrame(anim);
span.style.opacity = 1 - p;
}
anim(start_time);
})
}
Related
This question already has answers here:
How do I detect a click outside an element?
(91 answers)
Closed 2 years ago.
I'm trying to find multiple ways to close a sidebar menu that pops out from the left side. The idea of this is to have a page with an "Open/Close Menu" button. As expected this button should be able to open and close the menu with clicked, but I also want to include an option of closing it when simply clicking outside the menu bar.
My thought process behind this is to add a div that surrounds all of the content on the page, and gives it a class name of "notMenu". I would define the dimensions of this to be the entire page and give it a z-index of 1. When the menu pops up, it would be on top of .notMenu with a z-index of 2, yet I can't seem to get it to work.
var menuBtn = document.querySelector('.menuBtn');
var sidebar = document.querySelector('.sidebar');
var closeMenuBtn = document.querySelector('.closeMenuBtn');
var notMenu = document.querySelector('.notMenu');
var nav = 'closed'
menuBtn.addEventListener('click', function() {
if (nav === 'closed') {
sidebar.style.display = 'block'
nav = 'open'
} else {
sidebar.style.display = 'none'
nav = 'closed'
}
});
// closeMenuBtn.addEventListener('click',function(){
// sidebar.style.display = 'none'
// });
closeMenuBtn.addEventListener('click', function() {
sidebar.style.display = 'none';
nav = 'closed';
});
/*
notMenu.addEventListener('click',function(){
sidebar.style.display = 'none'
nav = 'closed';
})
*/
h1 {
text-align: center;
}
.menuBtn {
position: relative;
left: 50%;
transform: translateX(-50%);
}
.closeMenu {
font-size: 30px;
z-index: 2;
}
.sidebar {
position: absolute;
top: 0;
height: 100vh;
width: 300px;
background: grey;
display: none;
z-index: 2;
}
.notMenu {
position: absolute;
top: 0;
height: 100%;
width: 100%;
z-index: 1;
}
<body>
<div class="notMenu">
<h1> Header </h1>
<div class="sidebar">
<ul>
<li><a href=''>Link1</a></li>
<li><a href=''>Link2</a></li>
<li><a href=''>Link3</a></li>
</ul>
<button class="closeMenuBtn">Close Menu</button>
</div>
<button class="menuBtn">Open/Close Menu</button>
<div class="content1">
<br><br> Lorem ipsum dolor sit amet consectetur, adipisicing elit. Aspernatur quia ipsam optio, veritatis corrupti exercitationem quae itaque accusamus voluptas ipsa consequuntur nostrum, culpa, cum dolore incidunt ducimus harum minus doloremque?
</div>
<div class="content2">
<br><br> Lorem ipsum dolor sit amet consectetur adipisicing elit. Eum quia laboriosam ut accusantium itaque adipisci vitae error provident voluptate, dolorem veniam dignissimos atque accusamus aut rem quos esse fugit voluptas soluta laudantium.
Nam voluptates maxime sapiente, pariatur voluptatibus mollitia quia.
</div>
</div>
<!--closes .notMenu-->
</body>
CodePen Link
Alternatively, is there a way to do this without designated a new class as .notMenu? I assume there is a possibility to do this with e.target in JS with if statements.
function(e){
if (e.target !== 'sidebar'){
sidebar.style.display = 'none'
}
}
The issue I ran into with this is that e.target returns an object. I'm unable to define which objects represent the sidebar and which ones do not, therefore I can't determine if the area outside the sidebar is being clicked.
try this
window.addEventListener('mouseup', function(e) {
var x = document.querySelector('.sidebar');
if (event.target != document.querySelector(".icon")) {
x.style.display = "none";
}
});
var menuBtn = document.querySelector('.menuBtn');
var sidebar = document.querySelector('.sidebar');
var closeMenuBtn = document.querySelector('.closeMenuBtn');
var notMenu = document.querySelector('.notMenu');
var nav = 'closed'
menuBtn.addEventListener('click',function(){
if (nav === 'closed'){
sidebar.style.display='block'
nav = 'open'
}
else{
sidebar.style.display = 'none'
nav = 'closed'
}
});
closeMenuBtn.addEventListener('click',function(){
sidebar.style.display = 'none';
nav = 'closed';
});
// fire event if click is outside of sidebar and menubtn
window.onclick = function(event) {
if (event.target !== sidebar && event.target !== menuBtn) {
sidebar.style.display = "none";
console.log('clicked');
}
}
h1{
text-align:center;
}
.menuBtn{
position:relative;
left:50%;
transform:translateX(-50%);
}
.closeMenu{
font-size:30px;
z-index:2;
}
.sidebar{
position:absolute;
top:0;
height:100vh;
width:300px;
background:grey;
display:none;
z-index:2;
}
.notMenu{
position:absolute;
top:0;
height:100%;
width:100%;
z-index:1;
}
<div class="notMenu">
<h1> Header </h1>
<div class="sidebar">
<ul>
<li><a href =''>Link1</a></li>
<li><a href =''>Link2</a></li>
<li><a href =''>Link3</a></li>
</ul>
<button class="closeMenuBtn">Close Menu</button>
</div>
<button class="menuBtn">Open/Close Menu</button>
<div class="content1">
<br><br>
Lorem ipsum dolor sit amet consectetur, adipisicing elit. Aspernatur quia ipsam optio, veritatis corrupti exercitationem quae itaque accusamus voluptas ipsa consequuntur nostrum, culpa, cum dolore incidunt ducimus harum minus doloremque?
</div>
<div class="content2">
<br><br>
Lorem ipsum dolor sit amet consectetur adipisicing elit. Eum quia laboriosam ut accusantium itaque adipisci vitae error provident voluptate, dolorem veniam dignissimos atque accusamus aut rem quos esse fugit voluptas soluta laudantium. Nam voluptates maxime sapiente, pariatur voluptatibus mollitia quia.
</div>
</div>
try this
My requirement is that I need to ON/Enable JavaScript on some site Okay, But when I keep JavaScript Enable in Chrome site my another JS (this PopUp on selection) is not working, But when I disable/Block all JS for the same site the Popup script is working, Why? Rather I want to on JS.
Now I want to use this Popup script on a webpage, when all other JS is enabled, How to do it?
But here my problem is when all other JS is enabled, This Popup is not working
So Plz Any Body can solve my issue, many many advance thanks to them.
My Popup Function Code is:
const container2 = document.querySelector('#article_body');
const popupContainer = document.querySelector('.popupContainer');
// this method is added
// It gives the text of HTML of selected text :)
function getHTMLOfSelection () {
var range;
if (document.selection && document.selection.createRange) {
range = document.selection.createRange();
return range.htmlText;
}
else if (window.getSelection) {
var selection = window.getSelection();
if (selection.rangeCount > 0) {
range = selection.getRangeAt(0);
var clonedSelection = range.cloneContents();
var div = document.createElement('div');
div.appendChild(clonedSelection);
return div.innerHTML;
}
else {
return '';
}
}
else {
return '';
}
}
container2.addEventListener('mouseup', (e) => {
const selectedText = getHTMLOfSelection(); // First get the raw HTML text
if (selectedText) {
//selectedText.split("<").join("<"); // Now replacing the < so that browser don't render it
//selectedText.split(">").join(">"); // Also replacing the > so that browser don't render it
//console.log(selectedText);
showPopup(selectedText); // using the 'xmp' tags around the text, to show2 the html as it is
}
});
popupContainer.addEventListener('click', (event) => {
if (event.target.matches('.popupContainer')) {
popupContainer.classList.remove('show2');
}
});
function showPopup(selectedText) {
// set the selected text as html inside popup2 element
document.querySelector('.popup2').innerHTML = selectedText;
popupContainer.classList.add('show2');
}
.popupContainer {
position: fixed;
width: 100vw;
height: 100vh;
background: rgba(0, 0, 0, 0.7);
top: 0;
display: flex;
opacity: 0;
transition: opacity 0.2s ease;
pointer-events: none;
align-items: center;
justify-content: center;
color: red;
z-index: 1;
overflow: scroll;
font-family: Kohinoor Devanagari;
box-shadow: inset -17px -6px 20px 20px #0c3f41, 0 0 25px blue, 0 0 5px darkblue;
}
.show2 {
opacity: 1;
pointer-events: all;
}
.popup2 {
background: #fff;
padding: 10px;
border-radius: 3px;
box-shadow: 0 0 5px rgba(0, 0, 0, 0.3);
width: 80%;
transition: transform 0.4s cubic-bezier(.39,.575,.565,1.000);
-webkit-transform: scale(.5);transform:scale(.5)
}
.show2 .popup2 {
-webkit-transform: scale(1);transform:scale(1)
}
<div class="popupContainer"><div class="popup2"></div></div>
<div id="article_body">
Lorem ipsum dolor, sit amet consectetur adipisicing elit. Recusandae pariatur eos aperiam saepe, beatae necessitatibus exercitationem, nemo, sit provident possimus debitis modi eligendi repellat iure vitae perferendis? Recusandae accusamus placeat velit itaque quis fuga laudantium debitis, ab eaque voluptatum illo esse incidunt! Quia tempore explicabo sint laboriosam rerum nihil voluptates voluptatibus voluptate iure. Earum magnam blanditiis voluptates quod ex exercitationem reiciendis, iure qui ducimus similique impedit nemo est, quisquam facere id adipisci harum tenetur consequuntur illum saepe laudantium. Suscipit facilis corporis natus aperiam! Reprehenderit hic quia natus nisi similique quod fugiat, architecto autem deleniti unde commodi accusamus modi voluptate?
</div>
Any Body can solve my issue, many many advance thanks to them.
I have a div at the top of the page, middle, and bottom. When I refresh the page each time I would like the top and bottom divs to switch without affecting the middle div at all. Thanks in advance for any answers.
My jsfiddle
Code:
.top {
background: lightpink;
padding: 40px;
}
.content {
background: white;
}
.bottom {
background: lightblue;
padding: 40px;
}
<div class="top">
1
</div>
<div class="content">
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ullam fuga impedit, obcaecati, commodi dolores quasi odit numquam esse aliquid, alias natus doloribus nihil eius dicta eaque, nobis veritatis! Praesentium, laboriosam.
</div>
<div class="bottom">
2
</div>
It can be done using sessionStorage and cloning divs.
What this is doing is taking a copy of each div in the clone variables and then using a sessionStorage value to toggle between the states. If the sessionStorage value is 0 then it will do nothing but change the value, if it's 1 then it'll remove the divs and then add them in the new order from the cloned content.
var divOne = document.querySelector('.top');
var divTwo = document.querySelector('.bottom');
var divOneClone = document.querySelector('.top').outerHTML;
var divTwoClone = document.querySelector('.bottom').outerHTML;
var divContent = document.querySelector('.content');
if (sessionStorage.getItem('refreshState')) {
if (sessionStorage.getItem('refreshState') == 1) {
divOne.parentNode.removeChild(divOne);
divTwo.parentNode.removeChild(divTwo);
divContent.insertAdjacentHTML('beforebegin', divTwoClone);
divContent.insertAdjacentHTML('afterend', divOneClone);
sessionStorage.setItem('refreshState', 0);
} else {
sessionStorage.setItem('refreshState', 1);
}
} else {
sessionStorage.setItem('refreshState', 0);
}
Here's a working JS Fiddle example.
I've got a responsive site I'm building Where I have two elements that overlap each other. THe size of the elements will change depending on the browser width as will the overlap and consequently I need to set left-padding on the right element dynamically.
I'm unsure of how to proceed with this. Have set up a Fiddle here.
html:
<div class="container">
<div class="row copy intro">
<section class="red">
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Dolor illum nobis ullam neque, harum, magni. Reprehenderit veritatis in deleniti incidunt dolore dolores ex id expedita.</p>
<p>Corporis soluta ducimus ut quasi libero nesciunt, eligendi autem, consequatur error sapiente labore, officia tempora in voluptas non deleniti veniam officiis, quis vero consequuntur quia!</p>
</section>
<section class="white">
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Dolor illum nobis ullam neque, harum, magni. Reprehenderit veritatis in deleniti incidunt dolore dolores ex id expedita.</p>
<p>Corporis soluta ducimus ut quasi libero nesciunt, eligendi autem, consequatur error sapiente labore, officia tempora in voluptas non deleniti veniam officiis, quis vero consequuntur quia!</p>
</section>
</div>
</div><!--container-->
css:
/* line 3, ../build/sass/_intro.scss */
.intro {
background: #0079c2;
position: relative;
padding: 15px;
padding-bottom: 150px;
}
/* line 9, ../build/sass/_intro.scss */
.intro section {
position: relative;
padding: 100px;
width: 60%;
-moz-border-radius: 500px;
-webkit-border-radius: 500px;
border-radius: 500px;
}
/* line 26, ../build/sass/_intro.scss */
.intro section.red {
background: rgba(238, 45, 36, 0.85);
color: #fff;
z-index: 200;
}
/* line 31, ../build/sass/_intro.scss */
.intro section.red h1 {
font-size: 24px;
}
/* line 45, ../build/sass/_intro.scss */
.intro section.white {
background: #fff;
color: #0079c2;
position: absolute;
top: 150px;
right: 15px;
}
js:
// set intro sections width = height
$(document).ready(function() {
var circleWidth= $('.intro section.red').outerWidth();
$('.intro section').css('min-height', circleWidth + 'px');
$('.intro section.white').css('width', circleWidth + 'px');
});
Thank you for your time.
Use % for padding and adjust accordingly. See this revised Fiddle for an example.
The revised Fiddle comments out:
$('.intro section.white').css('width', circleWidth + 'px');
Fixing the width of the white circle means that it is not responsive any more. If you need to do that for some reason, you would have to make adjustments.
Here's a JSFiddle doing what I think you want: http://jsfiddle.net/6yro5vhx/2/
Basically I user offset() & outerWidth() on the two elements to work out the overlap, and then call calculatePadding() function on documentready & resize events.
function calculatePadding() {
var white = $('.intro section.white');
var red = $('.intro section.red');
var extraPadding = 20;
var distanceLeft = white.offset().left;
var redDistanceRight = red.offset().left + red.outerWidth();
var paddingLeft = (redDistanceRight - distanceLeft) + extraPadding;
$('.intro section.white').css('padding-left', paddingLeft + 'px');
}
Update the answer below mine is a far better way to achieve what you're looking for. CSS is a much better responsive approach than excess JQuery.
Is there a solution for adding a class to the element in view when scrolling, and removing when out of view? This needs to work for a scrollable div. I have found a few solutions so far but they only seem to work for body... not a scrollable div.
I am happy to use a plugin if you know one exists. Something like this...
if ($('.journal-slider .each-slide img').inViewport() ) {
$(this).addClass('in-view');
} else {
$('.journal-slider .each-slide img').removeClass('in-view');
}
Thanks,
R
You could make your own jQuery plugin to do this. Something like this which takes two functions (whenInView, whenNotInView):
$('.journal-slider .each-slide img').inViewport(
function(){$(this).addClass("am-in-view");},
function(){$(this).removeClass("am-in-view");}
);
It tests on scroll (or resize) wether the target elements are currently within the viewport and calls the related function.
Here's the whole thing as a demo Snippet. In this example I have added an animation to the .am-in-view class so that you can see it working as the elements enter the viewport. This has not been tested on anything other than Chrome so far. Feel free to use and improve.
/*! inViewport 0.0.1
* jQuery plugin by Moob
* ========================
* (requires jQuery)
*/
(function ($) {
var vph=0;
function getViewportDimensions(){
vph = Math.max(document.documentElement.clientHeight, window.innerHeight || 0);
}
getViewportDimensions();
//on resize/scroll
$(window).on('resize orientationChanged', function(){
getViewportDimensions();
});
$.fn.inViewport = function (whenInView, whenNotInView) {
return this.each(function () {
var el = $(this),
inviewalreadycalled = false,
notinviewalreadycalled = false;
//on resize/scroll
$(window).on('resize orientationChanged scroll', function(){
checkInView();
});
function checkInView(){
var rect = el[0].getBoundingClientRect(),
t = rect.top,
b = rect.bottom;
if(t<vph && b>0){
if(!inviewalreadycalled){
whenInView.call(el);
inviewalreadycalled = true;
notinviewalreadycalled = false;
}
} else {
if(!notinviewalreadycalled){
whenNotInView.call(el);
notinviewalreadycalled = true;
inviewalreadycalled = false;
}
}
}
//initial check
checkInView();
});
}
}(jQuery));
html, body {
margin:0;
}
.me, .not-me {
padding:20px;
border:1px solid #aaa;
margin:20px;
}
.am-in-view {
background-color:pink;
-webkit-transition: all 1500ms;
-moz-transition: all 1500ms;
-o-transition: all 1500ms;
transition: all 1500ms;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div class="me">
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Eveniet, pariatur.</p>
<p>Saepe, eligendi nihil totam dolorum reprehenderit! Repellat omnis neque quasi.</p>
<p>Eos cumque voluptatum placeat eius nisi facere neque nesciunt praesentium.</p>
<p>Eos qui consectetur voluptatem eum, labore accusamus tempora distinctio sunt?</p>
</div>
<div class="me">
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Excepturi, sit.</p>
<p>A veritatis quis quae totam accusamus repellendus adipisci corporis soluta.</p>
<p>Debitis animi dolor distinctio ratione dolorum ex aperiam maiores fugit?</p>
<p>Incidunt non consequatur porro provident recusandae sunt architecto repellat enim.</p>
</div>
<div class="me">
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Blanditiis, reprehenderit?</p>
<p>Neque tempora perferendis dolor, mollitia debitis sunt voluptas ea ut!</p>
<p>Maiores earum officia corporis, sint voluptatem, in laboriosam perferendis asperiores?</p>
<p>Odit dolor voluptate laboriosam voluptatem accusamus aperiam explicabo at provident.</p>
</div>
<div class="not-me">
<p>I'm totally normal</p>
</div>
<div class="me">
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ullam, accusamus.</p>
<p>Quisquam architecto repellat facere amet sapiente dolore obcaecati harum fuga.</p>
<p>Tempora labore, unde necessitatibus ipsam repellat architecto, aliquam autem at.</p>
<p>Sapiente quis doloremque a illum, repellat, eius corporis ab placeat.</p>
</div>
<div class="me">
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Voluptate, assumenda!</p>
<p>Nesciunt corrupti, eaque dolores ut libero ipsam dolorem laudantium saepe.</p>
<p>Similique quisquam quod esse expedita, voluptate quia nobis? Cum, tempore.</p>
<p>Amet voluptatem eaque non, praesentium tenetur molestias minima architecto laboriosam?</p>
</div>
<div class="me">
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Tempore, ex?</p>
<p>Perferendis hic, sint maxime similique quia autem cum quasi? Sed.</p>
<p>Nemo ratione aliquid itaque est blanditiis aliquam maiores veniam ab!</p>
<p>Reiciendis cumque fugit earum ea animi et aut molestiae dolores!</p>
</div>
<!-- how to call it -->
<script>
$(function(){
$('.me').inViewport(
function(){$(this).addClass("am-in-view");},
function(){$(this).removeClass("am-in-view");}
);
});
</script>
The plugin you are looking for is called waypoints
Quote from the "Get Started" :
"Let's say you have a div with overflow:scroll, and you want a waypoint inside of this scrollable element. The context option lets you do this. Scroll the box below."
$('#example-context').waypoint(function() {
notify('Hit top of context');
}, { context: '.example-scroll-div' });
EDIT: Not using waypoints
Based on what you already did, I came to this :
function checkInView(elem,partial)
{
var container = $(".scrollable");
var contHeight = container.height();
var contTop = container.scrollTop();
var contBottom = contTop + contHeight ;
var elemTop = $(elem).offset().top - container.offset().top;
var elemBottom = elemTop + $(elem).height();
var isTotal = (elemTop >= 0 && elemBottom <=contHeight);
var isPart = ((elemTop < 0 && elemBottom > 0 ) || (elemTop > 0 && elemTop <= container.height())) && partial ;
return isTotal || isPart ;
}
$(document).ready(function(){
$(".scrollable").scroll(function(){
var result="",result2="";
$.each( $(".scrollable p"),function(i,e){
if (checkInView($(e),false)) {
$( this ).addClass( "red" );
} else {
$( this ).removeClass( "red" );
}
result += " " + checkInView($(e),false);
result2 += " " + checkInView($(e),true);
});
$("#tt").text(result);
$("#kk").text(result2);
});
});
.scrollable{
margin:10px;
height:100px;
overflow-y:scroll;
}
p
{
border-width:1px;
border-color:black;
border-style:solid;
}
.red {
background-color: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
full: <div id="tt"></div>
part: <div id="kk"></div>
<div class="scrollable">
<p>item1<span></span></p>
<p>item2<span></span></p>
<p>item3<span></span></p>
<p>item4<span></span></p>
<p>item5<span></span></p>
<p>item6<span></span></p>
<p>item7<span></span></p>
<p>item8<span></span></p>
</div>
where offset is an element's offset from screen. you should call this (throttles) using the scroll event, the repeatedly check if an element is in view.
function isElementInViewport(el, offset){
var rect = el.getBoundingClientRect();
offset = offset || 0;
return (
rect.top - offset >= 0 &&
rect.left >= 0 &&
rect.bottom + offset <= (window.innerHeight || document.documentElement.clientHeight) && /*or $(window).height() */
rect.right <= (window.innerWidth || document.documentElement.clientWidth) /*or $(window).width() */
);
}
using with onscroll event:
// utilizing underscore's `debounce` method
$(window).on('scroll.checkVisibility', _.debounce(check, 200));
function check(){
var visibility = isElementInViewport(element, -100);
if( visibility )
// do something if visisble
}
Using the Intersection Observer API
(native on modern browsers)
As jQuery is becoming obsolete, here is a simple solution using the Intersection Observer API:
/* Javascript */
// define an observer instance
var observer = new IntersectionObserver(onIntersection, {
root: null, // default is the viewport
threshold: 0.5, // percentage of taregt's visible area. Triggers "onIntersection"
});
// callback is called on intersection change
function onIntersection(entries, opts) {
entries.forEach((entry) => {
if (entry.isIntersecting) {
// Adding a class name if element is in view
entry.target.classList.add("class-name");
} else {
// Removing the class name if element is NOT in view
entry.target.classList.remove("class-name");
}
});
}
// Use the bserver to observe an element
observer.observe(document.getElementById("hello"));
// To stop observing:
// observer.unobserve(entry.target)
/* CSS */
#big-div {
height: 600px;
}
.class-name {
background-color: blue;
transition: 2s background-color;
}
<!--HTML-->
<div id="big-div">Scroll down to see the result!</div>
<div id="hello">Hello world</div>