I have a js file to update the index based on the cursor's position on the items of a menu This is the code i used:
const menu = document.getElementById("menu");
Array.from(document.getElementsByClassName("menu-item"))
.forEach((item, index) => {
item.onmouseover = () => {
menu.dataset.activeIndex = index;
}
});
The index updating is supposed to move a background image using css
#menu[data-active-index="0"] > #menu-background-pattern {
background-position: 0% -25%;
}
#menu[data-active-index="1"] > #menu-background-pattern {
background-position: 0% -50%;
}
#menu[data-active-index="2"] > #menu-background-pattern {
background-position: 0% -75%;
}
#menu[data-active-index="3"] > #menu-background-pattern {
background-position: 0% -100%;
}
The Background image is not moving While The background image should have moved
Here is the html
<div id="menu">
<div id="menu-items">
<div class="menu-item">Home</div>
<div class="menu-item">Shop</div>
<div class="menu-item">About</div>
<div class="menu-item">Contact Us</div>
</div>
<div id="menu-background-pattern"></div>
<div id="menu-background-image"></div>
</div>
<script></script>
<link rel="stylesheet" href="main.css">
Related
HTML that is needed to know
<section class="home" id="home">
<div class="max-width">
<div class="home-content">
<div class="text-1">Hello, my name is</div>
<div class="text-2">Hadi Zouhbi</div>
<div class="text-3">And I'm a <span id="headSpan">Developer</span></div>
</div>
</div>
</section>
Here is the needed CSS
.sticky {
padding: 30px 0;
background-color: crimson;
}
.stickyHeadSpan {
color: #fff;
}
Here is the javascript code that is needed
window.addEventListener('scroll' , function(){
if(window.scrollY > 20){
const navbar = document.querySelector('.navbar')
const headSpan = document.querySelector('span')
navbar.classList.add('sticky')
headSpan.classList.add('stickyHeadSpan')
}
})
window.addEventListener('scroll' , () => {
if(window.scrollY === 0) {
const navbar = document.querySelector('.navbar')
navbar.classList.remove('sticky')
}
})
I tried getting the span by the id and still did not work , whenever I scroll down the span is not changing color to white , did I make a mistake somewhere ? I also tried using just span so no id or class and it still did not work , it is really strange . Is there any rule that makes this not work ? I am a beginner at Javascript so I hope you can help me fix this.
window.addEventListener('scroll', function() {
if (window.scrollY > 20) {
const navbar = document.querySelector('.home');
const headSpan = document.querySelector('span');
navbar.classList.add('sticky');
headSpan.classList.add('stickyHeadSpan');
}
})
window.addEventListener('scroll', () => {
if (window.scrollY === 0) {
const navbar = document.querySelector('.home')
navbar.classList.remove('sticky')
}
})
.wrapper{
height: 200vh;
}
.sticky {
padding: 30px 0;
background-color: crimson;
position: sticky;
top: 0;
left: 0;
}
.stickyHeadSpan {
color: #fff;
}
<div class="wrapper">
<section class="home" id="home">
<div class="max-width">
<div class="home-content">
<div class="text-1">Hello, my name is</div>
<div class="text-2">Hadi Zouhbi</div>
<div class="text-3">And I'm a <span id="headSpan">Developer</span></div>
</div>
</div>
</section>
</div>
I'm wondering if anyone has discovered a beautiful way to rotate out logo's based on 'sections' of the page.
In more detail I have a logo on a transparent navbar, let's say a white logo.
My page is broken into sections, some gray/light background some darker/black backgrounds. As I scroll, I hope that the sticky logo will be swapped out to an opposing color. I attempted to do this by naming each section with an id such as id='white and id=black.
Then once I scrolled down and hit that I'd trigger the function and swap out the picture, although, I realized that it only detects the first id of white or the second of black.
Not sure how to approach this other then make a unique id for each section, which, seems barbaric.
window.onscroll = function() {
myFunction()
};
function myFunction() {
if ($(this).scrollTop() >= $('#white').position().top) {
logoSwap(0);
} else if (($(this).scrollTop() >= $('#black').position().top)) {
logoSwap(1);
}
}
function logoSwap(which) {
if (which) {
$('#logo').css("background-color", "black");
} else {
$('#logo').css("background-color", "white");
}
}
#logo {
position: fixed;
top: 0;
left: 0;
height: 50px;
width: 50px;
background-color: black;
}
.h500 {
height: 500px;
}
.white {
background-color: white;
}
.black {
background-color: black;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="logo">
</div>
<section id="white" class='h500 white'>
</section>
<section id="black" class='h500 black'>
</section>
<section id="white" class='h500 white'>
</section>
<section id="black" class='h500 black'>
</section>
You have to use classes and not id's because there must be only one item in the document having a same id, contrary to class.
About the script: the idea is to iterate over all the sections .white or .black and get the top and bottom for each one, which will allow you while handling scrolling event to verify if your logo is inside a given section (between the section's top and bottom positions)
Edit: I add this code (with pure javascript) to my comment.
const whites = [...document.querySelectorAll('.white')].map(e => ({
top: e.getBoundingClientRect().top,
bottom: e.getBoundingClientRect().bottom
}));
//If you have a logic of only white and black sections, you can omit blacks, else you can use them
// const blacks = [...document.querySelectorAll('.black')].map(e => ({top: e.top, bottom: e.bottom}));
const logo = document.querySelector('#logo');
document.addEventListener('scroll', () => {
let position = (logo.getBoundingClientRect().bottom + logo.getBoundingClientRect().top) / 2 + window.scrollY;
for (let i = 0; i < whites.length; i++) {
if (position >= whites[i].top && position <= whites[i].bottom) {
logo.classList.remove('whiteLogo');
logo.classList.add('blackLogo');
return;
}
}
logo.classList.remove('blackLogo');
logo.classList.add('whiteLogo');
});
*,
html,
body {
margin: 0;
padding: 0;
}
section {
height: 200px;
}
.black,
.blackLogo {
background: black;
}
.white,
.whiteLogo {
background: white;
}
#logo {
position: fixed;
top: 0;
left: 0;
height: 50px;
width: 50px;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<div id="logo" class="whiteLogo"></div>
<section class="black"></section>
<section class="white"></section>
<section class="black"></section>
<section class="black"></section>
<section class="white"></section>
<section class="black"></section>
</body>
</html>
DOM id's need to be unique, so your code will only recognize the first instance of each. You should find the last section you scrolled over, and find what class that has:
function myFunction() {
var position = $(this).scrollTop()
var class_pos = $('.white, .black').filter(function(){ return position >= $(this).position().top})
// console.log(class_pos)
if ($(class_pos[class_pos.length - 1]).hasClass('white')){
logoSwap(0);
} else {
logoSwap(1);
}
}
I have two divs, top and bottom. Both divs have dynamic height, the top div will show or hide depending on a variable.
I would like to add in a sliding animation to the top div when showing or hiding, but the bottom div should stick with the top div and slide with it too.
var hide = true;
var trigger = document.getElementById("trigger");
var topdiv = document.getElementById("topdiv");
trigger.addEventListener('click', function() {
if (hide) {
topdiv.classList.add('hide');
} else {
topdiv.classList.remove('hide');
}
hide = !hide;
});
div {
position: relative;
display: block;
width: 100%;
padding: 10px;
}
.top {
background: #999;
}
.body {
background: #555;
}
.hide {
display: none !important;
}
<div id="topdiv" class="top hide">
<p>Top</p>
</div>
<div class="body">
<p>Body</p>
<button id="trigger">
Trigger
</button>
</div>
I tried adding transform animations, but the effect is only applied to the top div while the bottom div remains unanimated.
#keyframes topDivAnimate {
from {
transform: translateY(-100%);
}
to {
transform:translateY(0%);
}
}
Help is much appreciated.
I would use CSS transition rather than animation. I've found it easiest to do by animating the lower div rather than the upper one, and changing its position so that it covers the top one (or, of course, not). See demonstration below, I've made as minimal changes as I could to the CSS and JS:
var cover = true;
var trigger = document.getElementById("trigger");
var bottomdiv = document.getElementsByClassName("body")[0];
trigger.addEventListener('click', function() {
if (cover) {
bottomdiv.classList.add('cover');
} else {
bottomdiv.classList.remove('cover');
}
cover = !cover;
});
div {
position: relative;
display: block;
width: 100%;
padding: 10px;
}
.top {
background: #999;
}
.body {
background: #555;
transform: translateY(0%);
transition: transform 0.5s;
}
.cover {
transform: translateY(-100%);
}
<div id="topdiv" class="top hide">
<p>Top</p>
</div>
<div class="body">
<p>Body</p>
<button id="trigger">
Trigger
</button>
</div>
Are you looking something like this? Then please try this:
var trigger = document.getElementById("trigger");
var topdiv = document.getElementById("topdiv");
trigger.addEventListener('click', function() {
if ($('#topdiv').css('display') == 'none') {
$(topdiv).slideDown();
} else {
$(topdiv).slideUp();
}
});
div {
position: relative;
display: block;
width: 100%;
padding: 10px;
}
.top {
display: none;
background: #999;
}
.body {
background: #555;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="topdiv" class="top hide">
<p>Top</p>
</div>
<div class="body">
<p>Body</p>
<button id="trigger">
Trigger
</button>
</div>
Try this code and see if that's the effect you wanted. It uses the Animate.css library so you'll need to link that in your <head></head>
function animateCSS(element, animationName, callback) {
const node = document.querySelector(element)
node.classList.add('animated', animationName)
function handleAnimationEnd() {
node.classList.remove('animated', animationName)
node.removeEventListener('animationend', handleAnimationEnd)
if (typeof callback === 'function') callback()
}
node.addEventListener('animationend', handleAnimationEnd)
}
var hide = false;
var trigger = document.getElementById("trigger");
var topdiv = document.getElementById("topdiv");
trigger.addEventListener('click', function() {
if (!hide) {
topdiv.classList.remove('hide');
animateCSS('.body', 'slideInDown');
animateCSS('#topdiv', 'slideInDown');
} else {
animateCSS('#topdiv', 'slideOutUp', function() {
topdiv.classList.add('hide');
})
animateCSS('.body', 'slideOutUp');
}
hide = !hide;
});
Working Codepen demo of my solution
Here's some more explanation on how to use the Animate.css library.
I want to make an image larger when the mouse is moved over it, and return it to normal after. The image loads at normal size fine using the getPhoto function in my JavaScript, but when I mouse over it, nothing happens.
What am I doing wrong?
document.getElementById("photo").onmouseover = function() {
mouseOver()
};
document.getElementById("photo").onmouseout = function() {
mouseOut()
};
function getPhoto(handle) {
var img = new Image();
var div = document.getElementById("photo");
while (div.firstChild) {
div.removeChild(div.firstChild);
}
img.src = "https://res.cloudinary.com/harmhxmnk/image/upload/" + handle;
img.height = 32;
img.onload = function() {
div.appendChild(img);
};
}
function mouseOver() {
var img = document.getElementById("photo");
img.height = 100;
}
function mouseOut() {
// TODO
}
.photo {
position: absolute;
top: 86px;
right: 92px;
}
<div class="photo" id="photo"></div>
No need for JS IMHO :-)
.photo {
position: absolute;
top: 86px;
right: 92px;
transform: scale(1);
transition: transform .5s;
}
.photo:hover {
transform: scale(1.2);
}
<div class="photo" id="photo"><img src="https://wallpaperbrowse.com/media/images/3848765-wallpaper-images-download.jpg" /></div>
None of the answers so far explain why it does not work. The reason it does not work is you are setting the height of 32 on the image. But when you are setting the height, you are setting it on the div, not the image. So if you want to do it your way, you would need to select the image. querySelector will let you reference the image in the element.
function mouseOver() {
var img = document.querySelector("#photo img");
img.height = 100;
}
I think it would be easier and cleaner to just use css for this
#photo:hover{
height: 100:
}
Very simple with CSS using flexbox (demo)
.col {
display: flex;
}
.col img {
margin: 5px 5px; /* more margin makes the image smaller */
flex-grow: 1;
}
.col img:hover {
margin: 0 0; /* less margin on hover makes the image bigger */
}
<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" rel="stylesheet"/>
<div class="container">
<div class="row">
<div class="col">
<img src="https://placekitten.com/g/200/200">
</div>
<div class="col">
<img src="https://placekitten.com/g/200/200">
</div>
</div>
<div class="row">
<div class="col">
<img src="https://placekitten.com/g/200/200">
</div>
<div class="col">
<img src="https://placekitten.com/g/200/200">
</div>
<div class="col">
<img src="https://placekitten.com/g/200/200">
</div>
</div>
</div>
so I am trying to create the effect seen on this website (for the photos on the left side of the column):
https://www.franshalsmuseum.nl/en/
I want to be able to change the image on scroll inside of a div.
And preferably, it won't scroll down past the page until all of the images have been scrolled through!
I'm trying to get the hang of javascript before adding things like jQuery, so can someone help with this using pureJS?`
window.onscroll = function() {
console.log(window.pageYOffset);
var img1 = document.getElementById('img1');
var img2 = document.getElemebtById('img2')
if ( window.pageYOffset > 1000 ) {
img1.classList.add("hidden");
img2.classList.remove("hidden");
} else {
img2.classList.add("hidden");
img1.classList.remove("hidden");
}
}
.rightPhotos {
max-width: 50%;
height: 50%;
overflow: auto;
}
.aPhoto {
max-height: 100%;
}
.hidden {
visibility: hidden;
}
.images {
width: 100%;
height: 100%;
}
<div class="other">
<div class="rightPhotos" onscroll="myFunction()">
<div class="aPhoto">
<img class ="images" id="img1" src="IMAGES/sunglasses.jpeg" alt="Woman with Sunglasses">
</div>
<div class="aPhoto hidden">
<img class="images" src="IMAGES/dancer1.jpg" alt="A Dancer">
</div>
</div>
</div>
`
The page you linked actually looks very nice, so I took a while to make something looking a bit closer to it than what other answers do.
I added a properly working transition, similar to one on franshalsmuseum.nl.
I styled the page to deal relatively well with being resized:
The sizing of panes and images is all ralative,
Scroll steps are relative to page height,
Images are shown using <div> with background-image instead of <img> tag. Depending on the size of the window, they are slightly cropped to adjust to changing aspect ratio of viewport.
I made the number of image sets very simple to change. It could be improved by creating the html elements in Javascript, but that doesn't look necessary. At least, it wouldn't be for the original page.
How it works
HTML
Images are put into special envelop elements (.img-wrapper), that provide proper sizing and positioning position: relative is important there). Each image element gets url (as background image url) and image set number to be used by javascript:
<div class="img visible" data-imageset="1"
style="background-image: url('http://placeimg.com/640/480/people');">
</div>
Class visible is set to show imageset 1 at the beginning.
CSS
The key points are these definitions (and similar for #bottom-image). As the element enveloping the image has overflow: hidden, we can hide the image by moving it outside of visible area. When we set coordinates back to normal, the image will slide back, using the smooth transition.
/* hiding images in #top-image */
#left-pane #top-image .img {
top: 100%;
}
#left-pane #top-image .img.visible {
top: 0;
}
JS
The Javascript code is very minimal, the interaction with DOM is really one line. However, it uses some tricks that may not be obvious, so there is this line with some links to documentation:
document.querySelectorAll('#left-pane .img').forEach((img) => {
img.classList.toggle('visible', img.dataset.imageset <= currentSet);
}
It just finds all images and adds or removes class visible depending on the data-imageset attribute of the image.
Full snippet with demo
See snippet below. Demo looks much better if you use "Full page" link after running the snippet.
let currentSet = 1;
function updateSelectedImgSet() {
const currentScroll = document.scrollingElement.scrollTop;
const scrollMax = document.scrollingElement.scrollHeight - document.scrollingElement.clientHeight;
const setsCount = 3;
const scrollPerSet = scrollMax / setsCount;
const scrolledSet = Math.floor(currentScroll / scrollPerSet) + 1;
if (scrolledSet == currentSet) {
return;
}
currentSet = scrolledSet;
document.querySelectorAll('#left-pane .img').forEach((img) => {
img.classList.toggle('visible', img.dataset.imageset <= currentSet);
});
}
window.onscroll = updateSelectedImgSet;
window.onresize = updateSelectedImgSet;
/* Left pane, fixed */
#left-pane {
position: fixed;
height: 100%;
width: 40vw;
}
#left-pane .img-wrapper {
position: relative;
height: 50%;
width: 100%;
overflow: hidden;
}
#left-pane .img-wrapper .img {
position: absolute;
width: 100%;
height: 100%;
/* Sizing and cropping of image */
background-position: center;
background-size: cover;
/* Transition - the slow sliding of images */
transition: 0.5s all ease-in-out;
}
/* hiding images in #top-image */
#left-pane #top-image .img {
top: 100%;
}
#left-pane #top-image .img.visible {
top: 0;
}
/* hiding images in #bottom-image */
#left-pane #bottom-image .img {
bottom: 100%;
}
#left-pane #bottom-image .img.visible {
bottom: 0;
}
/* Right pane, scrolling with the page */
#right-pane {
margin-left: 40vw;
}
.scrollable-content {
font-size: 40vw;
writing-mode: vertical-rl;
white-space: nowrap;
}
<div id="left-pane">
<div id="top-image" class="img-wrapper">
<div class="img visible" data-imageset="1"
style="background-image: url('http://placeimg.com/640/480/people');">
</div>
<div class="img" data-imageset="2"
style="background-image: url('http://placeimg.com/640/480/animals');">
</div>
<div class="img" data-imageset="3"
style="background-image: url('http://placeimg.com/640/480/any');">
</div>
</div>
<div id="bottom-image" class="img-wrapper">
<div class="img visible" data-imageset="1"
style="background-image: url('http://placeimg.com/640/480/nature');">
</div>
<div class="img" data-imageset="2"
style="background-image: url('http://placeimg.com/640/480/tech');">
</div>
<div class="img" data-imageset="3"
style="background-image: url('http://placeimg.com/640/480/arch');">
</div>
</div>
</div>
<div id="right-pane">
<div class="scrollable-content">Scrollable content!</div>
</div>
see code bellow:(I set 60 insteed 1000 (in function)for see changes)
I use one image and onscroll change the src of image
window.onscroll = function() {
var img1 = document.getElementById('img1');
var img2 = document.getElementById('img2')
if ( window.pageYOffset > 60 ) {
document.getElementById("img1").src = "https://material.angular.io/assets/img/examples/shiba2.jpg";
} else {
document.getElementById("img1").src = "https://material.angular.io/assets/img/examples/shiba1.jpg";
}
}
.rightPhotos
{
max-width: 50%;
height:50%;
overflow: auto;
}
.aPhoto
{
max-height: 100%;
}
.images
{
width: 100%;
height: 500px;
}
<div class="other">
<div class="rightPhotos" onscroll="myFunction()">
<div class="aPhoto">
<img class ="images" id="img1" src="https://material.angular.io/assets/img/examples/shiba1.jpg" alt="Woman with Sunglasses"/>
</div>
</div>
</div>
You can use the CSS properties to show/ hide the elements; instead of having custom CSS with hidden class.
if ( window.pageYOffset > 1000 ) {
img1.style.visibility = 'hidden';
img2.style.visibility = 'visible';
} else {
img2.style.visibility = 'hidden';
img1.style.visibility = 'visible';
}
The above would hide the element, but the DOM element would still occupy space.
For it now to have space occupied (like to remove it)
if ( window.pageYOffset > 1000 ) {
img1.style.display = 'none';
img2.style.display = 'block';
} else {
img1.style.display = 'block';
img2.style.display = 'none';
}
//window.pageYOffset
var scrollingDiv = document.getElementById('scrollContainer');
var img1 = document.getElementById('img1');
var img2 = document.getElementById('img2');
scrollingDiv.onscroll = function(event) {
if (scrollingDiv.scrollTop < 500) {
img1.src = "https://placeimg.com/250/100/arch";
img2.src = "https://placeimg.com/250/100/animals";
}
if (scrollingDiv.scrollTop > 500) {
img1.src = "https://placeimg.com/250/100/nature";
img2.src = "https://placeimg.com/250/100/people";
}
if (scrollingDiv.scrollTop > 1000) {
img1.src = "https://placeimg.com/250/100/tech";
img2.src = "https://placeimg.com/250/100/any";
}
}
.container{
display: table;
width: 100%;
height: 100%;
}
body{
margin: 0;
}
.container > div {
vertical-align:top;
}
.left, .middle, .right {
display: table-cell;
height: 100vh;
box-sizing: border-box;
}
.left, .right{
width:40%;
background: gray;
}
.middle{
overflow: auto;
position: relative;
}
.in-middle{
background: tomato;
position: absolute;
width: 100%;
height: 100%;
box-sizing: border-box;
margin: 0;
}
.in-in-middle{
height: 500px;
background: tomato;
}
.in-in-middle:nth-child(2){
background: pink;
}
.in-in-middle:nth-child(3){
background: skyblue;
}
.left img{
width: 100%;
transition: all 0.5s;
}
<div class="container">
<div class="left">
<img id="img1" src="https://placeimg.com/250/100/arch">
<img id="img2" src="https://placeimg.com/250/100/animals">
</div>
<div class="middle" id="scrollContainer">
<div class="in-middle">
<div class="in-in-middle" id="1"></div>
<div class="in-in-middle" id="2"></div>
<div class="in-in-middle" id="3"></div>
</div>
</div>
</div>