Changing background-image onscroll - javascript

I'm trying to change the background image of an element after a certain position has been scrolled past. Here's a snippet of my code:
<body>
<script>
window.onscroll = function() {scrollBG()};
function scrollBG() {
if (document.body.scrollTop > document.getElementById("one").getBoundingClientRect().top ||
document.documentElement.scrollTop > document.getElementById("one").getBoundingClientRect().top) {
document.getElementById("outer").style.backgroundImage = "url('imgs/pic1.jng')";
} else {
document.getElementById("outer").style.backgroundImage = "url('imgs/pic2.jpg')";
}
}
</script>
<table id="outer">
I'm using a similar coding style to show/hide a "back to top" button after a certain scroll position that functions just fine. I don't think there's a conflict between the two (though inline scripting isn't my preferred style) because even when I remove everything related to the "back to top" button, my code still fails to function.
Is this a stupid syntactical error, or is there a more fundamental error to my approach?

I've tweaked your code a little and it's working:
jsFiddle 1
var divOuter = document.getElementById("outer"),
divOne = document.getElementById("one");
window.onscroll = function() {scrollBG()};
function scrollBG() {
var oneTop = divOne.getBoundingClientRect().top;
if(document.body.scrollTop > oneTop ||
document.documentElement.scrollTop > oneTop){
divOuter.style.backgroundImage = "url('//www.planwallpaper.com/static/images/518071-background-hd_xO1TwRc.jpg')";
} else {
divOuter.style.backgroundImage = "url('//www.planwallpaper.com/static/images/maxresdefault_YodSsVN.jpg')";
}
}
body { margin: 0; padding: 0; height: 1500px; }
#outer {
position: fixed;
background: url('//www.planwallpaper.com/static/images/maxresdefault_YodSsVN.jpg') no-repeat;
top: 0;
left: 0;
right: 0;
bottom: 0;
}
#one {
width: 100%;
height: 150px;
background-color: orange;
color: white;
position: relative;
top: 400px;
}
<div id="outer"></div>
<div id="one"><h1>This is One</h1></div>
However, following the above method will be inefficient as IMHO it makes an extra HTTP request for the images every time the scroll goes up and down the threshold and thus you'll see flickering every time the background images get changed.
So it'd be better if we make use of an external CSS class, i.e #outer.bg2, and just add/remove it depending on the position of the scroll and this will fetch a cached version of the image which makes it smooth [except for the first time when the image is being requested for the first time]. Like below:
jsFiddle 2
var divOuter = document.getElementById("outer"),
divOne = document.getElementById("one");
window.onscroll = function() { scrollBG() };
function scrollBG() {
var oneTop = divOne.offsetTop;
if (document.body.scrollTop > oneTop ||
document.documentElement.scrollTop > oneTop) {
divOuter.classList.add('bg2');
} else {
divOuter.classList.remove('bg2');
}
}
body{ margin:0; padding:0; height: 1500px; }
#outer{
position:fixed;
background: url('//www.planwallpaper.com/static/images/maxresdefault_YodSsVN.jpg') no-repeat;
top:0;
left:0;
right:0;
bottom:0;
}
#outer.bg2{
background: url('//www.planwallpaper.com/static/images/518071-background-hd_xO1TwRc.jpg');
}
#one{
width:100%;
height:150px;
background-color:orange;
color:white;
position:relative;
top:400px;
}
<div id="outer"></div>
<div id="one"><h1>This is One</h1></div>
In the above code the triggering will happen when the scroll meets the bottom of the element #one, if you want the triggering to happen according to the top edge then replace this:
var oneTop = divOne.offsetTop;
With this:
var oneTop = divOne.offsetTop - divOne.offsetHeight;
jsFiddle 3

Related

rotate element on scroll within a div container

Ok so here's a challenge: I'm looking to rotate a fixed element when you scroll up and down inside a < div > - and not when you scroll on the entire page. So how do i target the scroll within a specific < div> (my div has classname="elementor")?
My code so far looks like this:
HTML
/* The image i'm trying to rotate */
<img class="portfolio" id="rotatelogo" src="http://jakobnatorp.com/wp-content/uploads/2021/10/cropped-JAKOB-LERCHE-DAA-NATORP.png"/>
/* And a div container with class="elementor" */
CSS
.portfolio {
position: fixed;
width:150px;
height:150px;
margin-top:50px;
margin-bottom:-300px;
margin-left:50px;
}
.elementor {
width: 100vh;
height: 100vw;
overflow-x: scroll;
overflow-y: scroll;
transform: rotate(-90deg) translateX(-100vh);
transform-origin: top left;
-ms-overflow-style: none;
}
JS
var element = document.getElementsByClassName("elementor")[0]
var elem = document.getElementById("rotatelogo");
element.addEventListener('scroll', function() {
var value = element.scrollY * 0.25;
elem.style.transform = `translatex(-50%) translatey(-50%) rotate(${value}deg)`;
});
Edit: I changed the code and it works now. I replaced the "scrollY" with "scrollTop". My new JS looks like this:
var element = document.getElementsByClassName("elementor")[0]
var elem = document.getElementById("rotatelogo");
element.addEventListener('scroll', function() {
var value = element.scrollTop * 0.25;
elem.style.transform = `translatex(-50%) translatey(-50%) rotate(${value}deg)`;
});
If I understand it right, you could select the element you'r adding an event to.
Something like :
const scrollDiv = document.querySelector(".scrollOnMe");
scrollDiv.addEventListener("wheel", () => {
console.log("Scrolling !");
})
div {
height: 30px;
}
.scrollOnMe {
background-color: green;
}
.foo {
background-color: red;
}
<div class="scrollOnMe">Scroll on me !</div>
<div class="foo">Don't :(<div>

how to change the color of the navbar after scrolling

I want my navbar to be transparent, but when the user scrolls a bit I want it to change to a solid color and I am using bootstrap for the navbar, I have done the code that is needed with javascript.
I had this javascript in my HTML file, but it doesn't seems to work and I don't really know why
<script>
var myNav = document.getElementById("mynav");
window.onscroll = function() {
use strict";
if (document.body.scrollTop >= 100) {
myNav.classList.add("scroll");
} else {
myNav.classList.remove("scroll");
}
};
</script>
and I have also added the CSS code.
.scroll {
background-color: transparent !important;
transition: all 0.5s ease-in;
}
I don't know why it doesn't work, it is not displaying any errors, I have also manually put the class and it worked so the problem is from the js code and not the CSS.
Use scrollY property of Window object.
See the Snippet below:
var myNav = document.getElementById("mynav");
window.onscroll = function() {
if (window.scrollY >= 100) {
myNav.classList.add("scroll");
} else {
myNav.classList.remove("scroll");
}
};
.scroll {
background-color: transparent !important;
transition: all 0.5s ease-in;
}
.main-container{
height: 1000px;
}
#mynav{
position: fixed;
background-color: gray;
height: 50px;
margin:0 auto;
top: 0;
bottom:0;
line-height: 50px;
padding:5px;
width: 100%;
}
<div class="main-container">
<div class="mynav" id="mynav">
Hello World! this is mynav
</div>
</div>
Try using window.scrollY instead of document.body.scrollTop.
if (window.scrollY >= 100)
You can also use document.documentElement.scrollTop. It's the html element that actually scrolls, not the body. Typically document.body.scrollTop will always be 0.

Detect Distance Between Elements on Scroll

I am using jQuery to change a fixed div at the top of the screen top:0.
When the scroll gets to a certain point the class is changed and CSS is changed. Great.
However, I was looking for a better way. Since I am changing it when it reaches 30px away from the content block, doing what I did below doesn't work well since it is using a fixed height:
$(function(){
$(document).scroll(function() {
var x = $(this).scrollTop();
if(x > 2025) {
if($(window).width() > 950) {
$('.topFullWidthWhite').addClass('nonStick');
}
} else {
$('.topFullWidthWhite').removeClass('nonStick');
}
});
});
SO...
Is there a way of doing something more along the lines of...
if(x <= 20 from /* HTML ELEMENT */){
//DO WHATEVER HERE
}
If there is a way of doing this relative to other elements rather than document height that would be grand.
Thanks!
Try to make use of offset().top for that particular element after which you want to change the css
$(window).on("scroll", function() {
var two = $(".two").offset().top;
if ($(this).scrollTop() > two - 20) {
$(".two").addClass("reached");
} else {
$(".two").removeClass("reached");
}
})
body {
margin-bottom: 400px;
}
.one {
height: 150px;
background: green;
margin-bottom: 20px;
}
.two {
height: 100px;
background: blue;
}
.two.reached {
background: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="one"></div>
<div class="two"></div>

Fix an element when it reaches the top of the screen using javascript and css

I have an element, that I wish to stick on top after it reaches the top of the screen.
<div id="HeaderWrapper">
...
<div id="Navigation">
Navigation
</div>
...
</div>
I am adding an event listener on scroll, which would call a function to check the posting of the element by using getBoundingClientRect() method. If the top or the y of the element is less then 0 relative to the viewport, then I would like to fix/stick the header. Again if its more than 0 then I would like to remove the fix position. In both the cases, I am adding and removing a class name of fixed_navbar which has the property of fix position.
document.addEventListener("scroll", function() {
const el = document.getElementById("Navigation");
let rect = el.getBoundingClientRect();
if (rect.top <= 0) {
el.classList.add("fixed_navbar");
} else {
el.classList.remove("fixed_navbar");
}
});
You can also the check the codepen demo.
When the position top of the element is more than zero it works fine. Also when scrolling down to the position where the element's top position is less than 0 it sticks to the page and has the fixed propery. But again when scrolling back to the position when the element's top is more than 0, the element still has the fixed propery and stick's to the top of the screen. How can I make the element stick to the top when it reaches the top of the screen and again when the element is below the top of the screen remove the fixed postion?
You can achieve this with CSS alone, by using:
position: sticky
When declaring position: sticky; you will also need to declare a top style (eg. top: 0;) to indicate at which point you want the element to become "stuck".
Working Example:
header {
height: 600px;
}
.navigation {
position: sticky;
top: 0;
margin-top: 150px;
}
<header>
<div class="navigation">Navigation</div>
</header>
Further Information:
position: sticky works in the following browsers:
https://caniuse.com/#feat=css-sticky
Try This
if (rect.top <= 0) {
In if condition you write rect.top < 0 that is wrong for your requirement
#Rounin provide an awesome solution. Although I fix your issue in JavaScript. you can check this
document.addEventListener("scroll", function() {
const el = document.getElementById("Navigation");
let rect = el.getBoundingClientRect();
if (rect.top <= 0) {
el.classList.add("fixed_navbar");
} else {
window.onscroll = function() {myFunction()};
function myFunction() {
if ( document.body.scrollTop < 100 ) {
el.classList.remove("fixed_navbar");
}
}
}
});
* {
margin: 0;
padding: 0;
}
#HeaderWrapper {
background: lightgrey;
height: 1500px;
}
.box {
background: skyblue;
width: 100%;
height: 100px;
}
#Navigation {
background: green;
}
.fixed_navbar {
position: fixed;
z-index: 1000;
width: 100%;
left: 0;
top: 0;
}
<div id="HeaderWrapper">
<div class="box"></div>
<div id="Navigation">
Navigation
</div>
</div>

Mouseover events of two DIVs, positioned one over the other

I need to trigger the mouseover event of two DIVs positioned one on top of other.
http://jsfiddle.net/hvh8k/
For the DIV in front, if I have given pointer-events:none; I will get the mouseover event of the DIV underneath. But this stops triggering the mouseover event of the DIV in front.
Javascript
$(function () {
var stopAnimation = false;
var loop1 = setInterval(function () {
if(stopAnimation)return;
var L = parseInt($("#back").css("left"), 10) + 10;
if(L > $(window).width())L=-300;
$("#back").css("left", L);
}, 100);
$("#back").mouseover(function () {
stopAnimation = true;
});
$("#back").mouseout(function () {
stopAnimation = false;
});
$("#front").mouseover(function () {
$("#front").animate({width:200}, 100);
});
$("#front").mouseout(function () {
$("#front").animate({width:100}, 100);
});
});
CSS
#back {
width: 300px;
height: 200px;
background-color: #aaa;
position: absolute;
left:0;
cursor: pointer;
}
#front {
width: 100px;
height: 100px;
background-color: #caa;
position: absolute;
left:0;
top:100px;
border-radius:50%;
overflow:hidden;
}
body {
margin:0;
}
HTML
<div id="main">
<div id="back"></div>
<div id="front"></div>
</div>
Don't know if this would be suited for what you are trying to achieve, but what about toggling the z-index as you click the divs?
First div.front will show. When div.front is clicked, it calls your function AND move div.front to the back, and div.back to the front, which would allow you to click and trigger the div.back function and toggle the divs again.
So to be clear... front visible > click > back visible > click > front visible etc.

Categories

Resources