I'm trying out locomotive-scroll for the first time and it's been good so far until I had to try to toggle the header style onscroll because the eventlistener isn't working. I've looked into gsap scrolltrigger and intersection observer but I'm having a difficult time figuring things out because I have little knowledge on the area.
How can I make this work / do something like this on locomotive scroll?
let header = document.querySelector("header");
function toggleHeader(ev) {
if (window.pageYOffset > 300) {
header.classList.add("header--active");
} else {
header.classList.remove("header--active");
}
}
window.addEventListener('scroll', function() {
toggleHeader();
});
HTML/CSS/JS
<div data-scroll-container=''>
<div class='header'>
Header
</div>
<section data-scroll-section=''></section>
<section data-scroll-section=''></section>
</div>
.header {
height: 80px;
background: #f00;
text-align: center;
display: flex;
align-items: center;
justify-content: center;
color: #fff;
position: fixed;
width: 100%;
left: 0;
top: 0;
transition: ease 0.4s;
}
.header--active {
height: 40px;
background-color: #000;
}
section {
height: 500px;
border-bottom: 1px solid #f00;
}
const scroller = new LocomotiveScroll({
el: document.querySelector('[data-scroll-container]'),
smooth: true
})
a functional sample:
var el = document.getElementById("test");
var wheel = "nothing";
var scroll = new LocomotiveScroll({
el: el,
smooth: true,
repeat: true,
getDirection: true
});
scroll.on("call", (fun, dir, obj) => {
console.log("call", fun, dir);
});
scroll.on("scroll", (obj) => {
if (obj.direction == wheel) return;
wheel = obj.direction;
console.log("scroll--", obj.direction);
console.log(obj.currentElements['0'],obj.currentElements['1'], Object.keys(obj.currentElements));
});
<script src="https://cdn.jsdelivr.net/npm/locomotive-scroll#4.1.0/dist/locomotive-scroll.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/locomotive-scroll#4.1.0/dist/locomotive-scroll.min.css">
<div id="test" data-scroll-container=''>
<div class='header'>
Header
</div>
<section data-scroll-section=''>
<div data-toggle data-toggle-call="text1">
<h2 class="intro__title" data-scroll data-scroll-call="text0">If I scroll to the second intro section (AND the first intro is in the viewport) it will change to a black background. But if I scroll up it will not change to a white background as the section did not get out from the viewport and the last call
was with a black background.</h2>
<p>You have to completely pass through a section to be able to reverse back the colors.<br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br></p>
</div>
<div data-toggle data-toggle-call="text2">
<h2 class="intro__title" data-scroll data-scroll-call="text1">If I scroll to the second intro section (AND the first intro is in the viewport) it will change to a black background. But if I scroll up it will not change to a white background as the section did not get out from the viewport and the last call
was with a black background.</h2>
<p>You have to completely pass through a section to be able to reverse back the colors.<br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br></p>
</div>
</section>
</div>
Related
I am working on a website with a custom SVG map on the home page.
I already created a map with interactive points (usual link tags), which works pretty well. But the problem here is that map is big and needs to be larger then a screen size, especially on small devices.
I want map to be zoomable (without zooming all the page) and scrollable by dragging mouse (on desktop), also it needs to be centered by default.
I tried to use JqueryUI draggable method to achieve scrolling, and it works, but have some kind of conflict with the method I use to center it. And also absolutely stucks when I try to limit the draggable area.
Here is the latest example I have: https://codepen.io/khomutovspace/pen/jOVzbMe
Code:
$(document).ready(function () {
var outerContent = $(".map");
var innerContent = $(".map > svg");
outerContent.scrollTop((innerContent.height() - outerContent.height()) / 2);
});
$(function () {
$(".map").draggable();
});
body {
margin: 0;
}
.content {
position: fixed;
top: 0;
left: 0;
z-index: 1;
padding: 15px;
}
.navigation {
display: grid;
grid-template-columns: repeat(2, 1fr);
}
.map {
min-width: 100vw;
min-height: 100vh;
overflow: hidden;
}
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="content">
<div class="navigation">
<div>
<a>Title</a>
</div>
<div>
<a>Item 1</a>
<a>Item 2</a>
<a>Item 3</a>
</div>
</div>
</div>
<div class="map">
<svg>…
</div>
If you can use another lib than jQuery UI, you can try PanZoom.
const mapElement = $(".map .svg")[0];
const panzoom = Panzoom(mapElement, { contain: 'outside', startScale: 1.5 });
mapElement.parentElement.addEventListener('wheel', panzoom.zoomWithWheel);
mapElement.parentElement.addEventListener('wheel', function (event) {
if (!event.shiftKey) return;
panzoom.zoomWithWheel(event);
})
For example : https://codepen.io/adrienlamotte/pen/bGgPgqj
Following guys, I used the code:
window.scrollBy (0, window.innerHeight)
And yes, it scrolls down the instagram home page.
However, when I go to my story, and see who viewed it, I want him to scroll the story's NOT scroll bar on the home page.
When I open the console and use the code I mentioned above, it returns me undefined and does not do what I want.
How do I scroll the bar of people who have viewed my story? Not from the home page (complete)?
EDIT
enter image description here
var button = document.querySelector('#scroll-child')
button.addEventListener('click', function() {
var childBlock = document.querySelector('.child')
childBlock.scroll(0, 50)
})
.parent {
height: 300px;
background-color: yellow;
text-align: center;
overflow: scroll;
}
.child {
width: 300px;
height: 200px;
background-color: crimson;
text-align: center;
overflow: scroll;
}
.child-content {
margin: 20px;
height: 1000px;
}
<div class="parent">
<button id="scroll-child">
scroll child content!
</button>
<div class="child">
<div class="child-content">
something1
something2
something3
something4
something5
something6
something7
something8
</div>
</div>
</div>
find your story block with its css selector:
var storyBlock = document.querySelector('#my-story-block-id')
scroll inside block
storyBlock.scroll(0, storyBlock.innerHeight)
I have a webpage where there is a full height intro image. Underneath this image is the main body of the site with a regular site header at the top, I'm trying to create an effect where once the user scrolls down to the site header, they cannot scroll back up to view the intro image.
CSS Classes:
Main Intro Image: .cq-fullscreen-intro
Site Header: .nav-down
I had a poke around on StackOverflow but I can't find anything that addresses this circumstance, can anyone point me in the right direction to achieve this using jQuery?
you can use JQuery scrollTop function like this
$(function() {
$(window).scroll(function() {
var scroll = $(window).scrollTop();
// set the height in pixels
if (scroll >= 200) {
// after the scroll is greater than height then you can remove it or hide it
$(".intro-image").hide();
}
});
});
So instead of scrolling, I personally think it would be better to have it be actionable. Forcing the user to manually do the transition (and all in between states) is a bad idea. If the user scrolls half way, and see's something actionable (menu, button, input field) is it usable? If it is, what happens if they submit... very awkward. If it isn't usable, how do they know when it is? How do they know it's because they haven't scrolled all the way. It's very poor user experience.
In the following example, I've created a pseudo-screenport for you to see what's actually going on. The .body container in your real site would be the body element.
Code Pen Example
$(document).ready(function(){
$('.splash-screen').on('click', function(){
$('.splash-screen').addClass("is-hidden");
});
})
html, body{
background: #eee;
margin: 0;
padding: 0;
}
.flex-root {
display: flex;
align-items: center;
justify-content: center;
height: 100vh;
width: 100vw;
}
.web-container {
width: 640px;
height: 480px;
background: #fff;
}
.body {
font-size: 0; // this is only to prevent spacing between img placholders
position: relative;
}
.splash-screen{
position: absolute;
transition: transform 1s ease-in-out;
}
.splash-screen .fa {
position: absolute;
z-index: 1;
font-size: 24px;
color: #fff;
left: 50%;
bottom: 15px;
}
.splash-screen.is-hidden {
transform: translateY(-110%);
transition: transform 1s ease-in-out;
}
<link href="https://stackpath.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="flex-root">
<div class="web-container">
<div class="body">
<div class="splash-screen">
<img src="https://via.placeholder.com/640x480?text=Splash+Screen"/>
<i class="fa fa-chevron-circle-up"></i>
</div>
<img src="https://via.placeholder.com/640x60/cbcbcb?text=Menu"/>
<img src="https://via.placeholder.com/640x420/dddddd?text=Site Body"/>
<div>
</div>
</div>
While its not direclty preventing you from scrolling up and its not jQuery, I would suggest to remove/hide the element once its out of view.
You could get the current scroll position, relative to the top of the page, and check if its greater than the elements height:
const target = document.getElementById('my-target')
const targetHeight = target.getBoundingClientRect().height
const scrollEventListener = () => {
if (
document.body.scrollTop > targetHeight ||
document.documentElement.scrollTop > targetHeight
) {
target.remove()
window.removeEventListener('scroll', scrollEventListener)
document.documentElement.scrollTop = 0
}
}
window.addEventListener('scroll', scrollEventListener)
Here is a codepen https://codepen.io/bluebrown/full/aboagov
I have a simple chat JS application, with a div.chat-holder holding all chat messages within a pane on the overall window. I set height of '.chat-holder so it remains fixed in size, and allows for scrolling of all the messages.
<style>
.chat-holder {
height: 30px;
overflow-y: scroll;
}
</style>
<div class="pane">
<div class="chat-holder">
<div class="chat-item">
first msg
</div>
<div class="chat-item">
second msg
</div>
....
<div class="chat-item">
last msg
</div>
</div>
</div>
On page load, I scroll to the bottom by setting the scrollTop of the holder:
var $holder = $('.chat-holder');
$holder.scrollTop($holder[0].scrollHeight);
and this works fine.
Problem occurs when I start with div.pane set to display:none. Ideally, I look to have a separate event to "show/hide" the chat pane, and start with the pane hidden.
When the parent pane is hidden, the .chat-holder scrollHeight is 0, so on load, the hidden pane won't be scrolled to the bottom. Which means when the pane is displayed, the chats are not scrolled to the most recent chats. You can see this in the following snippet: with .pane initially not displayed, scroll isn't set. If you set .pane to start displayed, then scroll works fine.
Is there anyway to "scroll to the bottom" while parent is hidden? (Yes, I know I could do this by detecting when the chat-holder is exposed & then scroll to the bottom, but I'm looking to do it on load.)
$(function() {
var $holder = $('.chat-holder');
$holder.scrollTop($holder[0].scrollHeight);
$('button').click(function() {
$('.pane').toggleClass('active');
});
});
.chat-holder {
height: 30px;
overflow-y: scroll;
border: thin solid black;
}
.chat-item {
font-size: 20px;
}
.pane {
display: none;
}
.pane.active {
display: block;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="pane">
<div class="chat-holder">
<div class="chat-item">first msg</div>
<div class="chat-item">second msg</div>
<div class="chat-item">last msg</div>
</div>
</div>
<button>Toggle pane</button>
You can get creative and use opacity or visibility rules instead of display: none:
$(function() {
var $holder = $('.chat-holder');
$holder.scrollTop($holder[0].scrollHeight);
$('button').click(function() {
$('.pane').toggleClass('active');
});
});
.chat-holder {
height: 30px;
overflow-y: scroll;
border: thin solid black;
}
.chat-item {
font-size: 20px;
}
.pane {
opacity: 0;
position: absolute;
z-index: 1;
}
.pane.active {
opacity: 1;
position: relative;
}
button {
z-index: 2;
position: relative;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="pane">
<div class="chat-holder">
<div class="chat-item">first msg</div>
<div class="chat-item">second msg</div>
<div class="chat-item">last msg</div>
</div>
</div>
<button>Toggle pane</button>
I've been stuck trying to figure out how to code a menu much like what you see on the Playstation website: http://us.playstation.com/
EDIT: Fiddle: http://jsfiddle.net/jjcarlson/7q64A/
So far I have a number of issues. The first is that I have been unable to create the 100% width, because, I am assuming, of the parent/child relationship.
The second issue I have is that my Timeout works on all class elements rather than only the currently hovered element. In other words, if all elements have slid down and one is hovered over, they all will remain open until none of them have been hovered for 1.5 seconds. I admit that my inability to come up with a solution may be due to my limited experience with the language. Below is the CSS:
.accordion-container {
width: 90%;
padding-bottom: 5px;
margin: 20px 0 0 20px;
}
.accordion {
width: 40%;
padding: 20px;
margin: 0 15px 35px;
position: relative;
float: left;
display: inline-block;
}
.accordion-question {
margin: 0;
padding: 0 0 5px 20px;
display: inline-block;
color: #06F;
background-color: #9F0;
cursor: pointer;
}
.accordion-answer-container {
padding: 0 20px;
overflow: hidden;
color: #999;
background: #F00;
}
.accordion-answer {
margin: 0;
padding: 0;
color: #0C0;
}
Then, the JQuery:
$(document).ready(function () {
var menu = $('.accordion-answer')
var timeout = 0;
var hovering = false;
menu.hide();
$('.accordion-question').hover(function () {
hovering = true;
// Open the menu
$(this).closest('.accordion').find('.accordion-answer')
.stop(true, true)
.delay(400).slideDown(600);
if (timeout > 0) {
clearTimeout(timeout);
}
})
.on("mouseleave", function () {
resetHover();
});
$('.accordion-answer').hover(function () {
hovering = true;
startTimeout();
})
.on("mouseleave", function () {
resetHover();
});
function startTimeout() {
timeout = setTimeout(function () {
closeMenu();
}, 1500);
};
function closeMenu() {
if (!hovering) {
$('.accordion-answer').stop(true, true).slideUp(400);
}
};
function resetHover() {
hovering = false;
startTimeout();
};
});
And finally, the HTML:
<div class="accordion-container">
<div class="accordion">
<div class="accordion-question">
<h2>Is this a question?</h2>
</div>
<div class="accordion-answer-container">
<div class="accordion-answer">
<p>To be honest, I am not sure</p>
<ul>
<li>List item one</li>
<li>List item two</li>
</ul>
<p>That is all.</p>
</div>
</div>
</div><!-- /accordion -->
<div class="accordion" id="testanchor">
<div class="accordion-question">
<h2>What would be a good second question?</h2>
</div>
<div class="accordion-answer-container">
<div class="accordion-answer">
<p>I don’t know, man!</p>
<p>That is all.</p>
</div>
</div>
</div><!-- /accordion -->
</div>
Styling is minimal right now (sorry) as I'm just trying to get this figured out. Thank you for any help you can provide.
To get a width of 100% you should not display them as inline-block and set the width of .accordion to 100%.
In the hover-event you set hovering to true. If the next hover-event occurs prior to the call of closeMenu, then the if clause will already be false.
You should be able to accomplish the 100% width of your dropdown by altering the css of your .according-answer-container to a fixed position along with setting left and right to 0:
.accordion-answer-container {
padding: 0 20px;
overflow: hidden;
color: #999;
background: #F00;
position: fixed;
left: 0;
right: 0;
}
An update to your fiddle shows this working