I'm fairly new to programming and I'm working on a project,
HTML
<div class="textAnimation">
<span><h2 class="animatedHeader">Text1</h2></span>
<span
><h2 class="animatedHeader twoH">Text2</h2></span
>
<span
><h2 class="animatedHeader">Text3</h2></span
>
<span
><h2 class="animatedHeader">text4</h2></span
>
<span><h2 class="animatedHeader">text5</h2></span>
<span><h2 class="animatedHeader">text6</h2></span>
<span><h2 class="animatedHeader">text7</h2></span>
<span><h2 class="animatedHeader">text8</h2></span>
<span><h2 class="animatedHeader">text9</h2></span>
</div>
JavaScript
// Check if is in viewport & animate
const headers2 = document.querySelector(".twoH");
function elementInViewportTWO() {
let bounding = headers2.getBoundingClientRect();
if (
bounding.top >= 0 &&
bounding.left >= 0 &&
bounding.right <=
(window.innerWidth || document.documentElement.clientWidth) &&
bounding.bottom <=
(window.innerHeight || document.documentElement.clientHeight)
) {
headers2.style.opacity = 1;
} else {
headers2.style.opacity = 0.6;
}
}
setInterval(elementInViewportTWO, 10);
My questions is, how to apply this effect, given an array of 9 headings without reusing so much code, how do I make my function work with an array of elements?
(My code highlights text when a certain element is in a viewport)
Select them all with document.querySelectorAll and loop through them each time.
// Check if is in viewport & animate
const headers = document.querySelectorAll(".animatedHeader");
function elementsInViewport() {
headers.forEach(header=>{
let bounding = header.getBoundingClientRect();
if (
bounding.top >= 0 &&
bounding.left >= 0 &&
bounding.right <=
(window.innerWidth || document.documentElement.clientWidth) &&
bounding.bottom <=
(window.innerHeight || document.documentElement.clientHeight)
) {
header.style.opacity = 1;
} else {
header.style.opacity = 0.6;
}
})
}
setInterval(elementsInViewport, 10);
<div class="textAnimation">
<span><h2 class="animatedHeader">Text1</h2></span>
<span
><h2 class="animatedHeader twoH">Text2</h2></span
>
<span
><h2 class="animatedHeader">Text3</h2></span
>
<span
><h2 class="animatedHeader">text4</h2></span
>
<span><h2 class="animatedHeader">text5</h2></span>
<span><h2 class="animatedHeader">text6</h2></span>
<span><h2 class="animatedHeader">text7</h2></span>
<span><h2 class="animatedHeader">text8</h2></span>
<span><h2 class="animatedHeader">text9</h2></span>
</div>
The function you've provided evaluates the dimensions of each .animatedHeader element every 10 milliseconds. This will make your CPU work very hard and has a high chance of hurting your site's peformance. And because of setInterval it will keep on running even if you're not interacting with the site and nothing changes.
Instead, consider using the Intersection Observer API which is specifically designed to detect if elements are within a viewport whilst keeping the performance high.
const headers = document.querySelectorAll('.animatedHeader');
const intersectionCallback = entries => {
for (const { isIntersecting, target } of entries) {
if (isIntersecting) {
target.style.opacity = 1;
} else {
target.style.opacity = 0.6;
}
}
};
const observer = new IntersectionObserver(intersectionCallback);
for (const header of headers) {
observer.observe(header);
}
Related
I'm trying to add a bottom border to appear under the tabs on a navigation bar depending on where you are on the webpage, but when I test to see if my code works, the CSS doesn't get applied. When I check in chrome's dev tools, the class gets added to the elements properly, the border just doesn't appear visually. I've just starting to learn JavaScript so I can't figure out why exactly this isn't working.
I did this following this YouTube tutorial https://www.youtube.com/watch?v=3-2Pj5hxwrw, my code matches his exactly except for a couple notes.
I've played with the required scroll position since my screen is bigger than the one he was using, but it still has the same issue of it adding the class correctly, but the CSS not being applied at all. All related code is under here and any insight would be appreciated!
HTML:
</div>
<ul class="navbar_menu">
<li class="navbar_item">
Home
</li>
<li class="navbar_item">
About
</li>
<li class="navbar_item">
<a href="#services" class="navbar_links" id="services-page"
>Services</a
>
</li>
<li class="navbar_btn">
Sign Up
</li>
</ul>
</div>
CSS:
.highlight {
border-bottom: 4px solid rgb(132,0,255);
}
JavaScript:
const highlightMenu = () => {
const elem = document.querySelector('.highlight');
const homeMenu = document.querySelector('#home-page');
const aboutMenu = document.querySelector('#about-page');
const servicesMenu = document.querySelector('#services-page');
let scrollPos = window.scrollY;
if(window.innerWidth > 960 && scrollPos < 600) {
homeMenu.classList.add('highLight');
aboutMenu.classList.remove('highLight');
return;
} else if (window.innerWidth > 960 && scrollPos < 1400) {
aboutMenu.classList.add('highLight');
homeMenu.classList.remove('highLight');
servicesMenu.classList.remove('highLight');
return;
} else if (window.innerWidth > 960 && scrollPos < 2345) {
servicesMenu.classList.add('highLight');
aboutMenu.classList.remove('highLight');
return;
}
if((elem && window.innerWidth < 960 && scrollPos < 600) || elem) {
elem.classList.remove('highLight');
}
}
window.addEventListener('scroll', highlightMenu);
window.addEventListener('click', highlightMenu);
Just needed to close your anonymous function, in this cases I advice you to use JS validator, so you won't waste time for these kind of mistakes.
const highlightMenu = () => {
const elem = document.querySelector('.highlight');
const homeMenu = document.querySelector('#home-page');
const aboutMenu = document.querySelector('#about-page');
const servicesMenu = document.querySelector('#services-page');
let scrollPos = window.scrollY;
if(window.innerWidth > 960 && scrollPos < 600) {
homeMenu.classList.add('highLight');
aboutMenu.classList.remove('highLight');
return;
} else if (window.innerWidth > 960 && scrollPos < 1400) {
aboutMenu.classList.add('highLight');
homeMenu.classList.remove('highLight');
servicesMenu.classList.remove('highLight');
return;
} else if (window.innerWidth > 960 && scrollPos < 2345) {
servicesMenu.classList.add('highLight');
aboutMenu.classList.remove('highLight');
return;
}
if((elem && window.innerWidth < 960 && scrollPos < 600) || elem) {
elem.classList.remove('highLight');
}
}
I mix different sources (thank's to them) to achieve what we need.
We have a div following the mouse ... it's ok ... but we need to toggle/add a class when this div overlapsing an other fixed div in the dom.
function detection(){
const animalEl = document.getElementById("animal");
const targetEl = document.getElementById("target");
const a = animalEl.getBoundingClientRect();
const b = targetEl.getBoundingClientRect();
var overlap = (
a.right == b.left || // right to left touching
a.left == b.right || // left to right touching
a.bottom == b.top || // bottom to top touching
a.top == b.bottom) // top to bottom touching
if(overlap){
console.log("overlaps");
targetEl.classList.toggle("touched");
}else{
//console.log("non");
}
}
Here is a pen
https://codepen.io/vinchoz/pen/QWdmVza
I tried with "getBoundingClientRect()" but not sure to use it the right way...
Could a javascript guru have a look at it?
Thank's
YES... I did find a solution
function detection(){
const animalEl = document.getElementById("bee");
const targetEl = document.getElementById("target");
const a = animalEl.getBoundingClientRect();
const b = targetEl.getBoundingClientRect();
/* FOR COVER
var inside = (
((b.top <= a.top) && (a.top <= b.bottom)) &&
((b.top <= a.bottom) && (a.bottom <= b.bottom)) &&
((b.left <= a.left) && (a.left <= b.right)) &&
((b.left <= a.right) && (a.right <= b.right))
)
if(inside){
targetEl.classList.toggle("inside");
}else{
}
*/
/* FOR TOUCHING */
var touched = !(
b.top > b.bottom ||
a.right < b.left ||
a.bottom < b.top ||
a.left > b.right
)
if(touched){
targetEl.classList.add("touched");
}else{
targetEl.classList.remove("touched");
}
}
https://codepen.io/vinchoz/pen/QWdmVza
I am working on a university project which requires me to design a website including dynamic Javascript content. This unit is exclusively about Javascript; no Jquery or anything else is allowed until next unit.
What I am trying to accomplish is for the images in the gallery to scroll in when they are scrolled into the viewport. If any part of the image is visible, the script should begin increasing the opacity proportionally to how much of the image has been scrolled in. I've tried a few different things from different tutorial and answers in the stack, but nothing works. The code might work, but it doesn't activate on scroll. Here's the code if anyone can help:
var elementPosition = window.pageYOffset;
function isInViewport(img) {
var relct = img.getBoundingClientRect();
return rect.bottom > 0 &&
rect.right > 0 &&
rect.left < (window.innerWidth || document.documentElement.clientWidth) &&
rect.top < (window.innerHeight || document.documentElement.clientHeight);
}
function fadeIn() {
var imgList = document.getElementsByTagName("IMG");
var i;
for (i = 0; i < imgList.length; i++) {
var img = imgList[i];
if (isInViewport(img)) {
if (elementPosition < 200) {
opacity = 1 - (elementPosition / 200));
}
else {
opacity = 1;
}
}
else {
opacity = 0;
}
}
}
window.addEventListener('scroll', fadeIn());
Lots of typos were fouling your code -- I'd recommend using an application that will either tidy your code and/or flag errors as you write (personally, I use codepen.io). Also, opacity is set by: element.style.opacity.
var imgList = document.getElementsByTagName("IMG");
function isInViewport(img) {
var rect = img.getBoundingClientRect();
return (
rect.bottom > 0 &&
rect.right > 0 &&
rect.left < (window.innerWidth || document.documentElement.clientWidth) &&
rect.top < (window.innerHeight || document.documentElement.clientHeight)
);
}
function fadeIn() {
for (i = 0; i < imgList.length; i++) {
if (isInViewport(imgList[i])) {
imgList[i].style.opacity = 1;
}
}
}
window.addEventListener("scroll", fadeIn);
img {display: block; transition: all 1s; opacity: 0;}
<img src="http://www.fillmurray.com/300/600">
<img src="http://www.fillmurray.com/300/600">
<img src="http://www.fillmurray.com/300/600">
<img src="http://www.fillmurray.com/300/600">
I have an index on the left side of my page. I wanted to glow a particular index according to the div element, which is showing on the screen. And the index will change with scroll.
My code is working only for the element1, not working for other elements.
Can anyone help me to show the javascript code?
My Demo HTML Code:-
<div id="index1">
<a>index1</a>
</div>
<div id="index2">
<a>index2</a>
</div>
<div id="index3">
<a>index3</a>
</div>
<div id="element1">
<!-- code... -->
</div>
<div id="element2">
<!-- code... -->
</div>
<div id="element3">
<!-- code... -->
</div>
My Actual Js Code:-
function isInViewport(el) {
const rect = el.getBoundingClientRect();
return (
rect.top >= 0 &&
rect.left >= 0 &&
rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) &&
rect.right <= (window.innerWidth || document.documentElement.clientWidth)
);
}
const e1= document.querySelector('#element1');
const e2= document.querySelector('#element2');
const e3= document.querySelector('#element3');
document.addEventListener("scroll", function () {
if(isInViewport(e1)){
document.querySelector('#index1').style.color = "white";
document.querySelector('#index1').style.fontWeight = "bold";
}else if(isInViewport(e2)){
document.querySelector('#index2).style.color = "white";
document.querySelector('#index2').style.fontWeight = "bold";
}else if(isInViewport(e3)){
document.querySelector('#index3').style.color = "white";
document.querySelector('#index3').style.fontWeight = "bold";
}
}, {
passive: true
});
I know getBoundingClientRect() gets the bounds in view but I found out this won't work if the view got transform scale. Any solution on your part.
var bounding = elem.getBoundingClientRect();
// Check if it's out of the viewport on each side
var out = {};
out.top = bounding.top >= 0;
out.left = bounding.left >= 0;
out.bottom = (bounding.bottom) > ((window.innerHeight) || (document.documentElement.clientHeight));
out.right = (bounding.right) > ((window.innerWidth) || (document.documentElement.clientWidth));
Please drag the square, it got transform scale and rotate on.
$.fn.isOnScreen = function(partial){
//let's be sure we're checking only one element (in case function is called on set)
var t = $(this).first();
//we're using getBoundingClientRect to get position of element relative to viewport
//so we dont need to care about scroll position
var box = t[0].getBoundingClientRect();
//let's save window size
var win = {
h : $(window).height(),
w : $(window).width()
};
//now we check against edges of element
//firstly we check one axis
//for example we check if left edge of element is between left and right edge of scree (still might be above/below)
var topEdgeInRange = box.top >= 0 && box.top <= win.h;
var bottomEdgeInRange = box.bottom >= 0 && box.bottom <= win.h;
var leftEdgeInRange = box.left >= 0 && box.left <= win.w;
var rightEdgeInRange = box.right >= 0 && box.right <= win.w;
//here we check if element is bigger then window and 'covers' the screen in given axis
var coverScreenHorizontally = box.left <= 0 && box.right >= win.w;
var coverScreenVertically = box.top <= 0 && box.bottom >= win.h;
//now we check 2nd axis
var topEdgeInScreen = topEdgeInRange && ( leftEdgeInRange || rightEdgeInRange || coverScreenHorizontally );
var bottomEdgeInScreen = bottomEdgeInRange && ( leftEdgeInRange || rightEdgeInRange || coverScreenHorizontally );
var leftEdgeInScreen = leftEdgeInRange && ( topEdgeInRange || bottomEdgeInRange || coverScreenVertically );
var rightEdgeInScreen = rightEdgeInRange && ( topEdgeInRange || bottomEdgeInRange || coverScreenVertically );
//now knowing presence of each edge on screen, we check if element is partially or entirely present on screen
var isPartiallyOnScreen = topEdgeInScreen || bottomEdgeInScreen || leftEdgeInScreen || rightEdgeInScreen;
var isEntirelyOnScreen = topEdgeInScreen && bottomEdgeInScreen && leftEdgeInScreen && rightEdgeInScreen;
return partial ? isPartiallyOnScreen : isEntirelyOnScreen;
};
$.expr.filters.onscreen = function(elem) {
return $(elem).isOnScreen(true);
};
$.expr.filters.entireonscreen = function(elem) {
return $(elem).isOnScreen(true);
};
$(function(){
$('#circle1').draggable({ drag: function() {
if ($("#circle1").isOnScreen()) $('.indicator').html('yes its on screen');
else $('.indicator').html('its off screen');
},});
});
.circle{
width: 50px;
height: 50px;
background-color: red;
top: 50%;
left: 50%;
}
.circle.big{
transform: scale(2,2) rotate(20deg);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.1/jquery.min.js"></script>
<script
src="https://code.jquery.com/ui/1.12.1/jquery-ui.min.js"
integrity="sha256-VazP97ZCwtekAsvgPBSUwPFKdrwD3unUfSGVYrahUqU="
crossorigin="anonymous"></script>
<div class="circle big" id="circle1">drag me</div>
<div class="indicator"></div>
Press to enlarge