How to animate transitions triggered by links - javascript

I found this useful jQuery for a navigation that highlights as linked content scrolls. I think I understand how this works, however I'm having trouble including transitions / animations for clicked items. I want the sections to smoothly transition when triggered by the navigation.
I have tried adding this to the CSS
.section {
transition: transform .5s ease-in-out;
}
and also to jQuery
$('#navigation').click(function(){
$('.section').animate('slow');
});
I'd really appreciate an explanation of what I am doing wrong in this particular example.
Here is the code and https://jsfiddle.net/r040p7oa/
<div id="navigation">
<ul>
<li>Section 1</li>
<li>Section 2</li>
</ul>
</div>
<div id="sections">
<div id ="section1" class="section">I'm section 1</div>
<div id ="section2" class="section">I'm section 2
</div>
#sections {
position: absolute;
top: 0;
left: 120px;
}
#navigation {
position: fixed;
top: 0;
left: 0;
}
.active {
background: red;
}
.section {
padding-bottom: 400px;
}
-
$(window).scroll(function() {
var position = $(this).scrollTop();
$('.section').each(function() {
var target = $(this).offset().top;
var id = $(this).attr('id');
if (position >= target) {
$('#navigation > ul > li > a').removeClass('active');
$('#navigation > ul > li > a[href=#' + id + ']').addClass('active');
}
});
});
https://jsfiddle.net/r040p7oa/

$('a').click(function(){
$('html, body').animate({
scrollTop: $( $.attr(this, 'href') ).offset().top
}, 500);
return false;
});
Working fiddle :) Code from here

This should do it:
$('a').click(function(e) {
e.preventDefault();
$('body, html').animate({scrollTop:$($(this).attr("href")).offset().top});
});
Here is the JSFiddle demo

Related

My Sticky Header Cover Content with the Smooth Scrolling Effect

I added a sticky header and a smooth scrolling effect, and I cannot figure out how to fix the position so it counts with the header size. The things I have tried disable the sticky header completely.
I have tried to use several different techniques, although I am a newbie and it might be too hard for me to do by myself.
<div id="container">
<section id="sectionHome">
<!--Header and Logo-->
<header id="myHeader">
<logo>
<img src="Pictures/Marvel-logo-880x660.crop.png">
</logo>
</header>
<!--The Top Navigation Menu-->
<div id="mainNav">
<ul>
<li class="current">Home</li>
<li>Characters</li>
<li>Movies</li>
<li>More Info</li>
</ul>
</div>
</section>
//Smooth Scrolling in Main Nav
$(document).ready(function() {
$('#mainNav li a').click(function(e) {
var targetHref = $(this).attr('href');
$('html, body').animate({
scrollTop: $(targetHref).offset().top
}, 1000);
e.preventDefault();
});
});
// Sticky Header
window.onscroll = function() {
myFunction()
}; // When the user scrolls the page
var header = document.getElementById("sectionHome"); // Get the header and top nav
var sticky = header.offsetTop; // Get the offset position of the navbar
function myFunction() { // Add the sticky class to the header when you reach its scroll position. Remove "sticky" when you leave the scroll position
if (window.pageYOffset > sticky) {
header.classList.add("sticky");
} else {
header.classList.remove("sticky");
}
}
This was one thing I tried, but it disabled my sticky header:
$(document).ready(function() {
var headerHeight = $('header').outerHeight(); // Target your header navigation here
$('#main-nav li a').click(function(e) {
var targetHref = $(this).attr('href');
$('html, body').animate({
scrollTop: $(targetHref).offset().top - headerHeight // Add it to the calculation here
}, 1000);
e.preventDefault();
});
});
I thought I could set a value for the total header size and position it that way, although it disables the sticky header. How do I do this properly?
This is my webpage:
http://www.student.city.ac.uk/~aczc972
Best regards,
Danielle
I have added a sandbox how to do it using jQuery, generally speaking only one addition from my site is that I am checking what is the target e.g. scroll to top page, and if yes, I am running specified code for it:
if (targetHref === "#") {
$("html, body").animate(
{ scrollTop: 0 },
"1000"
);
} else {
$("html, body").animate({scrollTop: $(targetHref).offset().top},1000);
}
codesandbox.io/s/81l87w26w0
Subtract header height scroll to prevent covering content by header
scrollTop: $(targetHref).offset().top - 180"
You can also scroll to top of the page like:
Add id="home" to body and change href in:
<li class="current">Home</li>
to home i.e.
<li class="current">Home</li>
Should work with your code
This is not necessarily the best way to do this, but it's an example which is designed to illustrate how it can be done. You don't need jQuery to achieve this effect so it's worth trying it without.
The code below fixes the header, and adjusts the padding of the main wrapper to account for the size of the header. It then sets up listeners on elements with the class section-link. For those elements, the click event will scroll to the element with the id which corresponds to the data-section attribute for the element which was clicked.
You can ignore the css for this which was only added to illustrate how this might work.
const padForHeader = () => {
// find out how high the header element is
const headerHeight = document.getElementById('top-header').clientHeight;
// how much extra padding would we like?
const headerPadding = 20;
// add the two together to see how much padding we need to add
const headerBufferSize = headerHeight + headerPadding;
// set the marginTop property so that the header doesn't overlay content
document.querySelector('.wrapper').style.marginTop = `${headerBufferSize}px`;
};
padForHeader();
// when the window resizes, re-pad for the header
window.addEventListener('resize', padForHeader);
document
.querySelectorAll('.section-link')
.forEach(element => {
// we want to scroll 'smoothly' to the element
const scrollOptions = {
behavior: "smooth"
};
// we can read the data attribute to find the matching element's id
const elementIdToScrollTo = element.dataset.section;
// we can use the id we found to get the corresponding element
const elementToScrollTo = document.getElementById(elementIdToScrollTo);
// we can set the onclick property to scroll to the element we found
element.onclick = () => elementToScrollTo.scrollIntoView(scrollOptions);
});
.header {
background-color: red;
border: solid 2px grey;
border-radius: 5px;
font-family: arial;
margin: 0 auto;
position: fixed;
top: 0;
left: 0;
right: 0;
width: 97%;
}
.header>ul {
list-style: none;
color: rgba(250, 250, 240, 0.8);
}
.header>ul>li {
cursor: pointer;
display: inline-block;
position: relative;
top: 0px;
transition: all 0.3s ease;
width: 200px;
}
.header>ul>li:hover {
color: rgba(250, 250, 240, 1);
top: -1px;
}
.section {
background-color: rgba(20, 20, 30, 0.2);
height: 80vh;
border-bottom: solid 2px black;
padding-top: 50px;
}
<div class="wrapper">
<div id="top-header" class="header sticky">
<ul>
<li class="section-link" data-section="1">Item 1</li>
<li class="section-link" data-section="2">Item 2</li>
<li class="section-link" data-section="hello-world">Item hello world</li>
</ul>
</div>
<div id="1" class="section">
Test 1
</div>
<div id="2" class="section">
Test 2
</div>
<div id="hello-world" class="section">
Test 3
</div>
</div>

Keep div at top of window while content expands above it?

var divPos;
$('div').click(function() {
$(this).addClass('open');
$('div').not(this).addClass('close');
divPos = $(this).offset().top;
});
$('button').click(function(){
$('div').removeClass('open close');
$('html, body').animate({
scrollTop: divPos
}, 1000);
})
html, body {height:100%; padding:0; margin:0;}
div {height:25%; transition:height 1s;}
div.open {height:400px;}
div.close {height:0;}
div:nth-of-type(1) {background:red;}
div:nth-of-type(2) {background:blue;}
div:nth-of-type(3) {background:green;}
div:nth-of-type(4) {background:yellow;}
button { margin-bottom:100%;}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<div></div>
<div></div>
<div></div>
<div></div>
<button>close</button>
I have a stack of divs and when the user clicks one it expands it's height, while the ones that weren't clicked get zero height. All heights are transitioned by css.
When a close button is clicked, all divs go back to the original size.
How can I have the window scroll position keep the previously opened div at the top of the screen while the divs above it are expanding?
I have tried getting the position of the clicked div at it's original state and using:
$('html, body').animate({
scrollTop: divPos
}, 500);
Which basically works but it doesn't keep time with the css transition so it moves down before scrolling back up into position.
Here is a mockup of the problem: https://jsfiddle.net/0n6mxdt4/1/
The bounce back gets worse the lower the div it is.
If I correctly understand your problem, I think this is your answer. You need to add this line before animating to position:
$("html, body").scrollTop(divPos);
It is the working answer
var divPos;
$("div").click(function() {
$(this).addClass("open");
$("div")
.not(this)
.addClass("close");
divPos = $(this).offset().top;
clickedPos = $(this);
});
$("button").click(function() {
$("div").removeClass("open close");
$("html, body").scrollTop(divPos);
$("html, body").animate({
scrollTop: divPos
},
1000
);
});
html,
body {
height: 100%;
padding: 0;
margin: 0;
}
div {
height: 25%;
transition: height 1s;
}
div.open {
height: 400px;
}
div.close {
height: 0;
}
div:nth-of-type(1) {
background: red;
}
div:nth-of-type(2) {
background: blue;
}
div:nth-of-type(3) {
background: green;
}
div:nth-of-type(4) {
background: yellow;
}
button {
margin-bottom: 100%;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<div></div>
<div></div>
<div></div>
<div></div>
<button>close</button>

Menu only "clickable" once

I have a menu div that is opacity 0, visibility hidden initially. I essentaially want this div to be made available on a click of another div ( its a menu that sticks to the top of my page, discoverable/hide-able via click).
This works great.... ONE TIME...
I can click the "#menuIcon" and my menu is availble. I can click and it is hidden. Then my menu is forever hidden and will not become available again. Help me fix this??
jQuery code
/* Discovers menu on clicks */
$('#menuIcon').click(function () {
if ($('#menu ul').css('visibility') == 'hidden') {
$('#menu ul').css('visibility', 'visible');
$('#menu ul').animate({
opacity: 1
}, 500);
} else {
$('#menu ul').animate({
opacity: 0
}, 500,
function () {
$('#menu ul').css('visibility', 'hidden');
});
}
});
In your animate script, you forget to close the parentheses in the proper location this should fix it:
$('#menuIcon').click(function () {
if ($('#menu ul').css('visibility') == 'hidden') {
$('#menu ul').css('visibility', 'visible');
$('#menu ul').animate({
opacity: 1
}, 500);
} else {
$('#menu ul').animate({
opacity: 0
}, 500,
function () {
$('#menu ul').css('visibility', 'hidden');
});
}
});
Also, note that JSFiddle is your friend. Use it to help tidy up your script and check for errors in your script
Typo:
$('#menu ul').animate({opacity : 0 }, 500, function() {
$('#menu ul').css('visibility','hidden');
});
jsfiddle: http://jsfiddle.net/9geoh4vz/1/
If you want you can try this totally different approach and it's simple too.
Used : fadeToggle() plugin JQuery
JSFiddle : DEMO
CSS
html, body {
margin:0%;
width:100%;
height:100%;
}
.header {
display:block;
width:100%;
height:50px;
margin:0%;
background:#2b2937;
padding:5px 0px;
}
.menu {
display:block;
float:right;
width:80px;
height:auto;
background:lightgreen;
text-align:center;
color:white;
padding:5px 0px;
margin-top:10px;
cursor:pointer;
}
.menu-list
{
display:none;
padding:0px;
background:lightgreen;
float:right;
position:fixed;
top:60px; /* Header height=50px + top/bottom-padding=5px so, 50+5+5 = 60px*/
right:0px;
}
li
{
padding:5px 0px;
}
HTML
<div class="header"> <span class="menu">
MENU
</span>
</div>
<span class="menu-list">
<ul>
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
</ul>
</span>
JS
$(".menu").click(function()
{
$(".menu-list").fadeToggle();
});
Try this : You can use a variable to know if menu has been shown for once and use it in your if condition.
Note : - you can use is(':visible') instead of .css('visibility') and user show() / hide() for making menu visible and hidden as shown in code below
var isVisibleOnce = false;
/* Discovers menu on clicks */
$('#menuIcon').click( function() {
//check if isVisibleOnce is false and menu not visible
//then show menu
if(!isVisibleOnce && !$('#menu ul').is(':visible')) {
//set isVisibleOnce to true
isVisibleOnce = true;
$('#menu ul').animate({opacity : 1 }, 500,function(){
$('#menu ul').show();
});
}
else {
$('#menu ul').animate({opacity : 0 }, 500), function() {
$('#menu ul').hide();
});
}
});

jQuery scrollTop - Issue with wrong hash

I am trying to do scrollTop animation to an anchor that resides inside of a fullscreen <section>, but does not scroll to right anchor at first click. Here's my code.
<nav id="scroller"> Scroll me to sub 1
Scroll me to sub 2
Scroll me to sub 3
</nav>
<section id="boxTop"></section>
<section id="boxMaster">
<section id="subBox1">
<p>Hello. I am the Sub 1!</p>
</section>
<section id="subBox2">
<p>Hello. I am the Sub 2!</p>
</section>
<section id="subBox3">
<p>Hello. I am the Sub 3!</p>
</section>
</section>
$("#scroller a").click(function () {
$('#boxMaster').animate({
scrollTop: $(this.hash).offset().top
}, 700);
$("#scroller a").removeClass("active");
$(this).addClass("active");
});
fiddle
$("#scroller a").click(function() {
$('#boxMaster').animate({
scrollTop: $(this.hash).offset().top
}, 700);
$("#scroller a").removeClass("active");
$(this).addClass("active");
});
html,
body {
margin: 0;
padding: 0;
width: 100%;
height: 100%;
overflow: hidden;
}
#scroller {
position: fixed;
top: 0;
height: 30px;
text-align: center;
}
#scroller a {
color: #fff;
margin: 0 20px;
text-decoration: none;
}
#scroller a.active {
font-weight: bold;
text-decoration: underline;
}
#boxTop {
width: 100%;
height: 100%;
background: red;
}
#boxMaster {
width: 100%;
height: 100%;
background: blue;
overflow: hidden;
}
#boxMaster #subBox1,
#boxMaster #subBox2,
#boxMaster #subBox3 {
width: 100%;
height: 100%;
display: table;
}
p {
color: #fff;
text-align: center;
display: table-cell;
vertical-align: middle;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<nav id="scroller"> Scroll me to sub 1
Scroll me to sub 2
Scroll me to sub 3
</nav>
<section id="boxTop"></section>
<section id="boxMaster">
<section id="subBox1">
<p>Hello. I am the Sub 1!</p>
</section>
<section id="subBox2">
<p>Hello. I am the Sub 2!</p>
</section>
<section id="subBox3">
<p>Hello. I am the Sub 3!</p>
</section>
</section>
Add the current scroller value to the offset().top(), the latter beeing relative to the top of frame, and get rid of this.hash. Use this.href instead.
$("#scroller a").click(function () {
var y=$('#boxMaster').scrollTop()
$('#boxMaster').animate({
scrollTop: $(this.href).offset().top + y
}, 100);
});
You need to scroll the #boxMaster element relative to the link's position within the element and relative to the #boxMaster element's top position within the body element.
You can do this by adding the #boxMaster element's scrollTop() value with its top position, and then subtracting that from the link's offset top value:
$(this.hash).offset().top - $('#boxMaster').position().top + $('#boxMaster').scrollTop()
Updated Example
var $boxMaster = $('#boxMaster');
$boxMaster.animate({
scrollTop: $(this.hash).offset().top - $boxMaster.position().top + $boxMaster.scrollTop()
}, 700);
You may also need to prevent the link element's default behavior using e.preventDefault(), and then manually scroll the html/body element to the #boxMaster element:
Updated Example
$('html, body').animate({
scrollTop: $boxMaster.offset().top
}, 700);
I have a fixed header. I started with w3school's code. However, I've been struggling with this same problem for so long, finally found a workaround for the "first click incorrect" issue:
Just before (outside) of my click event, I simply created a variable "x", initialized:
var x=1;
Then I have a conditional statement inside the click event checking for x:
if (x==1) {
console.log("x is now: " + x);
x=0;
console.log("x is now: " + x);
jQuery("html, body").animate({
scrollTop: jQuery("div.class-of-element-i-am-scrolling-to" + hash).position().top - jQuery("div.header-container").outerHeight(true) - jQuery("h3.another-element-in-my-way").outerHeight(true)
}, 2000, function(){
return false;
});
} else {
jQuery("html, body").animate({
scrollTop: jQuery("div.class-of-element-i-am-scrolling-to" + hash).position().top
}, 2000, function(){
return false;
});
}
In other words, using "x" as a flag to check if it is the first time the code is run.
If it is, then I am kind of cheating by subtracting the fixed header and the other elements that are pulling my desired div up. Remember to make "x=0" to "drop" the flag.
If it isn't, then it works fine anyway.

Problems calculating absolute div

i have created vertical Menu with fixed width and absolute position ul
.categories ul.sub {
position: absolute;
right: -191px;
top: 0;
background: #fff;
width: 190px;}
but the problem is that i dont want to use fixed width and right. I want to calculate the width and the right of a ul depending of h2 class width inside ul with js. example : how is now: http://prntscr.com/rzcvx , how i need: http://prntscr.com/rzd3t
html example:
<div class="categories">
<ul class="maincats">
<li>
<a class="first"><img/><span>Category Name</span></a>
<ul class="sub first">
<li><h2>H2 Title</h2></li>
<li>Title</li>
<li>Title</li>
<li>Title</li>
<li>Title</li>
</ul>
</li>
</ul></div>
i have nothing tried yet, i only use this js
$(".categories li a").hover(
function () {
$(this).addClass("hover");
$(this).next('ul.sub').show();
},
function () {
$(this).removeClass("hover");
$(this).next('ul.sub').hide();
}
);
$(".categories ul.sub").hover(
function () {
$(this).prev().addClass("hover");
$(this).show();
},
function () {
$(this).prev().removeClass("hover");
$(this).hide();
}
);
$(function () {
var zIndexNumber = 10;
// Put your target element(s) in the selector below!
$(".categories ul.sub").each(function () {
$(this).css('zIndex', zIndexNumber);
});
});
Please help me i have basic js skils :)
You may want to try this:
.categories ul.sub {
position: absolute;
right: -100%; /* Not sure if this works, can't test without your html */
top: 0;
background: #fff;
white-space: nowrap; /* Prevent spaces from wrapping when text's overflowing. */
}

Categories