Still a noob but I am slowly getting there.
I have a series of divs, all the same class and I have previous and next buttons that scroll to the top of the next or previous div when clicked. I would like to set an offset so that my header won't hide the div that scrolls underneath of it and I am unsure how to go about this. Code below.
<button class="prev link js-prev js-scroll-to">Previous</button>
<button class="next link js-next">Next</button>
<script>
$('.js-scroll-to').click(function(e) {
target = $($(this).attr('href'));
if (target.offset()) {
$('html, body').animate({scrollTop: target.offset().top + 'px'}, 1000);
}
e.preventDefault();
});
$('.js-next').click(function(e) {
var selected = $(".js-list-item.js-current-panel");
var anchors = $(".js-list-item");
var pos = anchors.index(selected);
var next = anchors.get(pos+1);
var prev = anchors.get(pos-1);
target = $(next);
$(selected).removeClass("js-current-panel");
$(next).addClass("js-current-panel");
if (target.offset()) {
$('html, body').animate({scrollTop: target.offset().top + 'px'}, 1000);
}
e.preventDefault();
});
$('.js-prev').click(function(e) {
var selected = $(".js-list-item.js-current-panel");
var anchors = $(".js-list-item");
var pos = anchors.index(selected);
var next = anchors.get(pos+1);
var prev = anchors.get(pos-1);
target = $(prev);
$(selected).removeClass("js-current-panel");
$(prev).addClass("js-current-panel");
if (target.offset()) {
$('html, body').animate({scrollTop: target.offset().top + 'px'}, 1000);
}
e.preventDefault();
});
</script>
For your case, I think you could just add the offset right into your animated scroll code (subtracting the height of the nav bar plus a little margin):
$('html, body').animate({scrollTop: target.offset().top - 54 + 'px'}, 1000);
I usually do this without a JS scroll by adding a span class to use as the anchor instead of anchoring on the div itself. This will work if someone links directly to the anchor point as well.
That way I can use position relative on the anchor to set an offset for the height of the nav bar.
In this case, I think you probably have some divs like this:
<div class="js-list-item js-current-panel">
content
</div>
<div class="js-list-item">
content
</div>
<div class="js-list-item">
content
</div>
I'd change it to:
<span class="anchor js-list-item js-current-panel"></span>
<div class="content">
content
</div>
<span class="anchor js-list-item"></span>
<div class="content">
content
</div>
<span class="anchor js-list-item"></span>
<div class="content">
content
</div>
With some CSS to position those new anchors (top depends on nav bar height):
.anchor {
position: relative;
top: -54px;
}
Example with some extra CSS to show how the anchors are positioned:
<style type="text/css">
.nav {
position: fixed;
top: 0;
left: 0;
right: 0;
width: 100%;
height: 44px;
background: black;
}
.main {
margin-top: 54px;
}
.js-list-item {
display: inline-block;
width: 5px;
height: 5px;
background: blue;
position: relative;
top: -54px;
}
.content {
background: red;
width: 100%;
height: 500px;
margin-bottom: 25px;
}
</style>
<div class="nav">
<button class="prev link js-prev js-scroll-to">Previous</button>
<button class="next link js-next">Next</button>
</div>
<div class="main">
<span class="js-list-item js-current-panel"></span>
<div id="one" class="content">content</div>
<span class="js-list-item"></span>
<div id="two" class="content">content</div>
<span class="js-list-item"></span>
<div id="three" class="content">content</div>
<span class="js-list-item"></span>
<div id="four" class="content">content</div>
<span class="js-list-item"></span>
<div id="five" class="content">content</div>
<span class="js-list-item"></span>
<div id="six" class="content">content</div>
<span class="js-list-item"></span>
<div id="seven" class="content">content</div>
</div>
<script src="https://code.jquery.com/jquery-3.5.1.min.js" integrity="sha256-9/aliU8dGd2tb6OSsuzixeV4y/faTqgFtohetphbbj0=" crossorigin="anonymous"></script>
<script>
$('.js-scroll-to').click(function(e) {
target = $($(this).attr('href'));
if (target.offset()) {
$('html, body').animate({scrollTop: target.offset().top + 'px'}, 1000);
}
e.preventDefault();
});
$('.js-next').click(function(e) {
var selected = $(".js-list-item.js-current-panel");
var anchors = $(".js-list-item");
var pos = anchors.index(selected);
var next = anchors.get(pos+1);
var prev = anchors.get(pos-1);
target = $(next);
$(selected).removeClass("js-current-panel");
$(next).addClass("js-current-panel");
if (target.offset()) {
$('html, body').animate({scrollTop: target.offset().top + 'px'}, 1000);
}
e.preventDefault();
});
$('.js-prev').click(function(e) {
var selected = $(".js-list-item.js-current-panel");
var anchors = $(".js-list-item");
var pos = anchors.index(selected);
var next = anchors.get(pos+1);
var prev = anchors.get(pos-1);
target = $(prev);
$(selected).removeClass("js-current-panel");
$(prev).addClass("js-current-panel");
if (target.offset()) {
$('html, body').animate({scrollTop: target.offset().top + 'px'}, 1000);
}
e.preventDefault();
});
</script>
Related
I have a fixed div on the page which contains a logo and as the user scrolls and this logo passes over other divs I wnat to the change the colour of the logo.
I have this working over a single div but need to it work across multiple so any help appreciated.
The WIP site can be seen here... dd.mintfresh.co.uk - if you scroll down you'll (hopefully) see the logo change from black to white as it crosses an illustrated egg. I need the same to happen when it crosses other divs further down the page.
The script so far...
jQuery(window).scroll(function(){
var fixed = jQuery("logo");
var fixed_position = jQuery("#logo").offset().top;
var fixed_height = jQuery("#logo").height();
var toCross_position = jQuery("#egg").offset().top;
var toCross_height = jQuery("#egg").height();
if (fixed_position + fixed_height < toCross_position) {
jQuery("#logo img").css({filter : "invert(100%)"});
} else if (fixed_position > toCross_position + toCross_height) {
jQuery("#logo img").css({filter : "invert(100%)"});
} else {
jQuery("#logo img").css({filter : "invert(0%)"});
}
}
);
Any help appreciated. Thanks!
you need to fire a div scroll event. you can assign
$("div1").scroll(function(){
//change the color of the div1
}
});
$("div2").scroll(function(){
//change the color of the div2
}
});
or you can assign a class to divs which you want to change the color
$(".div").scroll(function(){
//change the color of the div which you are scrolling now
}
});
You can use like this :-
$(window).scroll(function() {
var that = $(this);
$('.section').each(function() {
var s = $(this);
if (that.scrollTop() >= s.position().top) {
if(s.hasClass('active')) {
$('.logo').addClass('invert');
} else {
$('.logo').removeClass('invert');
}
}
});
});
body {
padding: 0;
margin: 0;
}
div {
background: #f00;
height: 400px;
}
.logo {
position: fixed;
top: 0;
left: 0;
width: 100px;
}
.logo.invert {
filter: invert(100%);
}
div:nth-child(even) {
background: #ff0;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<img src="https://dd.mintfresh.co.uk/wp-content/uploads/2018/06/DD_logo.svg" class="logo" />
<div id="page1" class="section"></div>
<div id="page2" class="section active"></div>
<div id="page3" class="section"></div>
<div id="page4" class="section active"></div>
<div id="page5" class="section"></div>
As your site code you can do like this :
$(window).scroll(function() {
var that = $(this);
$('#content > section').each(function() {
var s = $(this);
if (that.scrollTop() >= s.position().top) {
if(s.hasClass('black')) {
$('#logo img').css({filter: 'invert(0%)'});
} else {
$('#logo img').css({filter: 'invert(100%)'});
}
}
});
});
I'm trying to make the side bar stop following the user's scroll once it hits the footer. Right now I set the z-index to -2 so that it goes behind the footer, but it sticks out a tiny bit.
JavaScript
$(document).ready(function () {
var floatingDiv = $('#side_bar');
var floatingDivPosition = floatingDiv.position();
$(window).scroll(function (){
var scrollBarPosition = $(window).scrollTop();
if(scrollBarPosition >= floatingDivPosition.top) {
floatingDiv.css({
'position': 'fixed',
'top': 55,
'width': '18.6676%',
'z-index': -2
});
}
else{
floatingDiv.css({
'position': 'relative',
'top': 0,
'width': '79.4392%'
});
}
});
});
HTML
<div id="content">
<div id="col_1">
<div id="side_bar">
<h4 id="cater_to">We cater to</h4>
<button class="side_bar_btns">Contractor</button>
<button class="side_bar_btns">Wood/Sport Floors</button>
<button class="side_bar_btns">Grocery/Commercial</button>
<button class="side_bar_btns">Education</button>
<h4 id="simplicity">Simplicity</h4>
<div id="all_systems_side_bar">
<img src="images/all_systems_logo.png" alt="All Systems Maintenance logo. Links to more about All Systems Maintenance." width="100%">
</div><!-- all systems side bar -->
</div><!-- side_bar -->
</div><!-- col_1 -->
<div id="col_2">
//// bunch of stuff here
</div><!-- col_2 -->
<div class="clear"></div>
</div><!-- content -->
<footer>
/// bunch of stuff here
</footer>
CSS
#col_1 {
float:left;
margin-top:44px;
width:23.4994%;
margin-left:3.9531%;
}
#side_bar {
background:#003768;
min-height:665px;
width:79.4392%;
border-radius:20px;
box-shadow: 10px 10px 5px #888;
}
#col_2 {
float:right;
margin-top:44px;
width:68.5944%;
margin-right:3.9531%;
}
footer {
background-image:url(../images/foot_background.gif);
background-repeat:no-repeat;
background-size:cover;
}
The footer background is almost the same height as the screen (about 824px when I inspect it with Chrome).
Found this gem on Youtube at https://www.youtube.com/watch?v=5s0L6dCVevk and changed it slightly to come up with the following, which works.
$(function() {
if ($('#side_bar').length) {
var el = $('#side_bar');
var stickyTop = $('#side_bar').offset().top;
var stickyHeight = $('#side_bar').height();
$(window).scroll(function(){
var limit = $('footer').offset().top - stickyHeight - 20;
var windowTop = $(window).scrollTop();
if (stickyTop < windowTop) {
el.css({
position: 'fixed',
top: 55,
width: '18.6676%'
});
} else {
el.css({
position: 'static',
width: '79.4392%'
});
}
if (limit < windowTop) {
var diff = limit - windowTop;
el.css({
top: diff
});
}
});
}
});
I have a slide left/right and right/left transition between two divs that occurs simultaneously.
Fiddle : https://jsfiddle.net/n8jyzys2/
However the current transition looks somewhat like this
(The divs are at different rows during the transition):
Slide Transition 1
The transition I would like to achieve is similar to this (Have both divs at the same row simultaneously during transition) :
Slide Transition 2
Any ideas?
JS Credit
jQuery.fn.extend({
slideRightShow: function() {
return this.each(function() {
$(this).show('slide', {direction: 'right'}, 1000);
});
},
slideLeftHide: function() {
return this.each(function() {
$(this).hide('slide', {direction: 'left'}, 1000);
});
},
slideRightHide: function() {
return this.each(function() {
$(this).hide('slide', {direction: 'right'}, 1000);
});
},
slideLeftShow: function() {
return this.each(function() {
$(this).show('slide', {direction: 'left'}, 1000);
});
}
});
$("#slide_two_show").click(function () {
$("#slide_one_div").slideLeftHide();
$("#slide_two_div").slideRightShow();
});
$("#slide_one_show").click(function () {
$("#slide_one_div").slideLeftShow();
$("#slide_two_div").slideRightHide();
});
HTML Code
<div>
<div id="slide_one_div">
<br>
<div class="mydiv">
<h1>Slide 1 (Left Slide)</h1>
<p>...</p>
<button id="slide_two_show">Show Slide 2</button>
</div>
</div>
<div id="slide_two_div" style = "display:none">
<br>
<div class="mydiv">
<h1>Slide 2 (Right Slide)</h1>
<p>...</p>
<button id="slide_one_show">Show Slide 1</button>
</div>
</div>
</div>
Style
.mydiv {
background: green;
width: 100%;
height: 100px;
outline: 1px solid #f93;
}
Add this CSS to your page:
#slide_one_div {
position: absolute;
width: 100%;
}
Hope I helped ;)
My code looks like this:
<div id="arrow">
<a class="next"></a>
<a class="previous"></a>
</div>
<section id="first">
...
</section>
<section id="second">
...
</section>
<section id="third">
...
</section>
The element #arrow has position: fixed, and I'm trying to make the window scroll to the next section when a.next is clicked.
Ex: The first time a.next is clicked, the window scrolls to section#first, the second time, the window scrolls to section#second, etc. The same thing happens to a.previous.
Does someone know how to solve this problem?
Thanks a lot!
EDIT
My JS code:
$('#arrows a.previous').click(function() {
$.scrollTo($(this).closest('section').prev(),800);
});
$('#arrows a.next').click(function() {
$.scrollTo($(this).closest('section').next(),800);
});
You will need to handle to 3 events in this case:
Current page position - updated each time.
User scrolls manualy the page.
User clicks the prev or next button.
2, 3 need to use the current page position and update him according to the direction that the page is scrolling.
My quick demos : Vertical Version jsFiddle --- Horizontal Version jsFiddle
Vertical Version snippet :
$(function(){
var pagePositon = 0,
sectionsSeclector = 'section',
$scrollItems = $(sectionsSeclector),
offsetTolorence = 30,
pageMaxPosition = $scrollItems.length - 1;
//Map the sections:
$scrollItems.each(function(index,ele) { $(ele).attr("debog",index).data("pos",index); });
// Bind to scroll
$(window).bind('scroll',upPos);
//Move on click:
$('#arrow a').click(function(e){
if ($(this).hasClass('next') && pagePositon+1 <= pageMaxPosition) {
pagePositon++;
$('html, body').stop().animate({
scrollTop: $scrollItems.eq(pagePositon).offset().top
}, 300);
}
if ($(this).hasClass('previous') && pagePositon-1 >= 0) {
pagePositon--;
$('html, body').stop().animate({
scrollTop: $scrollItems.eq(pagePositon).offset().top
}, 300);
return false;
}
});
//Update position func:
function upPos(){
var fromTop = $(this).scrollTop();
var $cur = null;
$scrollItems.each(function(index,ele){
if ($(ele).offset().top < fromTop + offsetTolorence) $cur = $(ele);
});
if ($cur != null && pagePositon != $cur.data('pos')) {
pagePositon = $cur.data('pos');
}
}
});
section { min-height:800px; }
#arrow {
position:fixed;
right:0;
top:0;
background-color:black;
color:white;
}
#arrow a{
display:inline-block;
padding:10px 20px;
cursor:pointer;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<div id="arrow">
<a class="next">next</a>
<a class="previous">prev</a>
</div>
<section style="background-color:green">...</section>
<section style="background-color:blue">...</section>
<section style="background-color:red">...</section>
All you need, to allow the user to use both arrows and scrollbar:
var $sec = $("section");
$(".prev, .next").click(function(){
var y = $sec.filter(function(i, el) {
return el.getBoundingClientRect().bottom > 0;
})[$(this).hasClass("next")?"next":"prev"]("section").offset().top;
$("html, body").stop().animate({scrollTop: y});
});
*{margin:0;padding:0;}
#arrow{
position:fixed;
width:100%;
text-align:center;
}
#arrow a{
display:inline-block;
background: tomato;
padding:6px 15px;
border-radius:3px;
cursor:pointer;
}
section{
height:1200px;
border:3px solid #444;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="arrow"><a class="prev">↑</a><a class="next">↓</a></div>
<section>1</section>
<section style="height:500px;">2</section>
<section>3</section>
<section style="height:600px;">4</section>
<section>5</section>
To explain the jQuery a bit:
// Cache your selectors
var $sec = $("section");
// On any of both arrows click
$(".prev, .next").click(function(){
// We need to get current element
// before defining the `.next()` or `.prev()` element to target
// and get it's `offset().top` into an `y` variable we'll animate to.
// A current element is always the one which bottom position
// (relative to the browser top) is higher than 0.
var y = $sec.filter(function(i, el) {
return el.getBoundingClientRect().bottom > 0;
})[$(this).hasClass("next")?"next":"prev"]("section").offset().top;
// (Line above:) if the clicked button className was `"next"`,
// target the the `.next("section")`, else target the `.prev("section")`
// and retrieve it's `.offset().top`
$("html, body").stop().animate({scrollTop: y});
});
i have tried to do with .closest("section") but it only works when the section is a parent of the element you clicked so this is the best way i got
sections=$("section");
s=0;
$(".next").click(function() {
if(s<sections.length-1){
s++;
$('html, body').animate({
scrollTop: sections.eq(s).offset().top
}, 500);
}});
$(".previous").click(function() {
if(s>0){
s--;
$('html, body').animate({
scrollTop: sections.eq(s).offset().top
}, 500);
}});
section{
background-color:#bbb;
width:100%;
height:700px;
border-bottom:2px solid #eee;
}
#arrow{
position:fixed;
}
#first{
background-color: red;
}
#second{
background-color:green;
}
#third{
background-color: blue;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="arrow">
<a class="next">next</a>
<a class="previous">prev</a>
</div>
<section id="first">
...
</section>
<section id="second">
...
</section>
<section id="third">
...
</section>
Basically I am just trying to do random jQuery stuff for educational purpose, and here is my very simple slider. I want it to work automatically and also with controls (little arrows to scroll to next/previous slider). The only problem that I have right now is that when you press the arrow, the function that automatically switches slides every 5 seconds is still counting these 5000 ms, so the next slide appears faster then desired. What I want is to make those arrows reset the timer, so you press the arrow -> next slide appears -> only after 5 seconds later the slide switches again.
Sorry for sloppy explanation, hope I made it clear enough.
Here's the jsfiddle: http://jsfiddle.net/cA9aW/
and here is the code
HTML
<body>
<div id="wrapper">
<header>
<h1>Simplest Sliding Image Slider</h1>
</header>
<div id="content">
<div id="slider_container">
<div id="slider">
<div class="slides" id="slide1">
<img src="http://s2.postimg.org/5uxqi0mgl/cats1.jpg" alt="" />
</div>
<div class="slides" id="slide2">
<img src="http://s2.postimg.org/66f6us2wl/cats2.jpg" alt="" />
</div>
<div class="slides" id="slide3">
<img src="http://s2.postimg.org/ai3sjs9th/cats3.jpg" alt="" />
</div>
</div>
</div>
</div>
<footer></footer>
</div>
</body>
JS
jQuery(document).ready(function($) {
// start slider function
startSlider();
// set width and step variables and add active class to first slider
var slideWidth = $('.slides').width();
$('#slide1').addClass('slides active');
// actual function
function startSlider() {
looper = setInterval(function() {
// remove and add class active
$('.active').removeClass('active').next().addClass('active');
// animation expression
$('.active').animate({'left': '-=' + (slideWidth) + 'px'}, 500);
$('.active').siblings().animate({'left': '-=' + (slideWidth) + 'px'}, 500);
// return to first slide after the last one
if($('.active').length == 0) {
$('#slide1').addClass('active');
$('.slides').animate({'left': 0}, 500);
}
}, 5000); // interval
// adding controls
$('.slides').append("<div class='controls'><a class='control_left' href='#'></a><a class='control_right' href='#'></a></div>");
// remove unnecessary controlls on first and last slides
$('.slides:nth-child(1) a.control_left').remove();
$(".slides:nth-child(" + $('.slides').length + ") a.control_right").remove();
// add functionality to controls
$('.control_left').on('click', function() {
$('.active').removeClass('active').prev().addClass('active');
$('.active').animate({'left': '+=' + (slideWidth) + 'px'}, 500);
$('.active').siblings().animate({'left': '+=' + (slideWidth) + 'px'}, 500);
});
$('.control_right').on('click', function() {
$('.active').removeClass('active').next().addClass('active');
$('.active').animate({'left': '-=' + (slideWidth) + 'px'}, 500);
$('.active').siblings().animate({'left': '-=' + (slideWidth) + 'px'}, 500);
});
}
});
Thx a lot in advance
Slideshow with prev/next buttons, autoslide, pause on hover
Instead of jQuery's .animate() and animating the left CSS property, use the GPU accelerated CSS transform: translateX for the animation on a common slides wrapper element
$(".SlideShow").each((i, EL) => {
const
$parent = $(EL),
$slides = $(".SlideShow-slides", EL),
$item = $(".SlideShow-item", EL),
$prevNext = $(".SlideShow-btn", EL),
tot = $item.length,
mod = (n, m) => ((n % m) + m) % m;
let
c = 0,
itv;
const prev = () => {c = mod(--c, tot); anim();};
const next = () => {c = mod(++c, tot); anim();};
const anim = () => $slides.css({transform: `translateX(-${c * 100}%)`});
const stop = () => clearInterval(itv);
const play = () => itv = setInterval(next, 4000);
$prevNext.on("click", (ev) => $(ev.currentTarget).is(".next") ? next() : prev());
$parent.hover(stop, play);
play(); // start
});
.SlideShow {
position: relative;
overflow: hidden;
width: 100%;
height: 180px;
}
.SlideShow-slides {
display: flex;
flex-flow: row-nowrap;
height: 100%;
width: 100%;
transition: transform 0.7s; /* Animation duration here */
}
.SlideShow-item {
min-width: 100%;
}
.SlideShow-item>img {
display: block;
width: 100%;
height: 100%;
object-fit: cover;
}
.SlideShow-btn {
position: absolute;
top: 0;
z-index: 1;
width: 50px;
height: 100%;
background: rgba(255, 255, 255, 0.5);
opacity: 0.5;
border: 0;
cursor: pointer;
}
.SlideShow-btn:hover {
opacity: 1;
}
.SlideShow-btn.next {
right: 0px;
}
<div class="SlideShow">
<div class="SlideShow-slides">
<div class="SlideShow-item"><img src="http://placehold.it/600x400/0bf?text=A" alt=""></div>
<div class="SlideShow-item"><img src="http://placehold.it/600x400/fb0?text=B" alt=""></div>
<div class="SlideShow-item"><img src="http://placehold.it/600x400/0fb?text=C" alt=""></div>
</div>
<button type="button" class="SlideShow-btn prev"></button>
<button type="button" class="SlideShow-btn next"></button>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
What you need to do it to clear the interval in the button clicks and start interval again.
function resetInterval(){ //add this method which wil reset the timer
window.clearInterval(looper); //clear current interval
looper = setInterval(autoSlide, 5000); //start auto slide again.
}
function autoSlide(){ //move this to a function from being anonymous
// remove and add class active
$('.active').removeClass('active').next().addClass('active');
// animation expression
$('.active').animate({
'left': '-=' + (slideWidth) + 'px'
}, 500);
$('.active').siblings().animate({
'left': '-=' + (slideWidth) + 'px'
}, 500);
// return to first slide after the last one
if ($('.active').length === 0) {
$('#slide1').addClass('active');
$('.slides').animate({
'left': 0
}, 500);
}
}
and
$('.control_left').on('click', function () {
resetInterval(); //reset it
....
$('.control_right').on('click', function () {
resetInterval(); //reset it
....
Demo