scroll to section by section - javascript

I have HTML markup:
HTML:
<body>
<header></header>
<nav>
<ul>
<li>one</li>
<li>two</li>
</ul>
</nav>
<section id="one"></section>
<section id="two"></section>
<footer></footer>
</body>
where section is fullscreen (width: 100%; height:100%;) and menu have absolute position.
Question:
How can I use mouse scroll (or keys ) to scroll and snap to each section?
When scroll to last section then scroll-down to #one again and repeat it.
When I click on link, it scroll to section.
Thank you for your suggestions, ideas, code.

Interesting
I stole this code, changed the layout and tried to add the functions you mentioned (1. scroll-snap + 2. scroll when link is clicked).
Unfortunately, I can't have this second function to work.
Adding scroll-snap is not a problem
You need scroll-snap-type: y mandatory; on the container and scroll-snap-align: start; on the sections.
var doc = window.document,
context = doc.querySelector('.js-loop'),
clones = context.querySelectorAll('.is-clone'),
disableScroll = false,
scrollHeight = 0,
scrollPos = 0,
clonesHeight = 0,
i = 0;
function getScrollPos () {
return (context.pageYOffset || context.scrollTop) - (context.clientTop || 0);
}
function setScrollPos (pos) {
context.scrollTop = pos;
}
function getClonesHeight () {
clonesHeight = 0;
for (i = 0; i < clones.length; i += 1) {
clonesHeight = clonesHeight + clones[i].offsetHeight;
}
return clonesHeight;
}
function reCalc () {
scrollPos = getScrollPos();
scrollHeight = context.scrollHeight;
clonesHeight = getClonesHeight();
if (scrollPos <= 0) {
setScrollPos(1); // Scroll 1 pixel to allow upwards scrolling
}
}
function scrollUpdate () {
if (!disableScroll) {
scrollPos = getScrollPos();
if (clonesHeight + scrollPos >= scrollHeight) {
// Scroll to the top when you’ve reached the bottom
setScrollPos(1); // Scroll down 1 pixel to allow upwards scrolling
disableScroll = true;
} else if (scrollPos <= 0) {
// Scroll to the bottom when you reach the top
setScrollPos(scrollHeight - clonesHeight);
disableScroll = true;
}
}
if (disableScroll) {
// Disable scroll-jumping for a short time to avoid flickering
window.setTimeout(function () {
disableScroll = false;
}, 40);
}
}
function init () {
reCalc();
context.addEventListener('scroll', function () {
window.requestAnimationFrame(scrollUpdate);
}, false);
window.addEventListener('resize', function () {
window.requestAnimationFrame(reCalc);
}, false);
}
if (document.readyState !== 'loading') {
init()
} else {
doc.addEventListener('DOMContentLoaded', init, false)
}
html,
body {
height: 100%;
overflow: hidden;
}
.Loop {
position: relative;
height: 100%;
overflow: scroll;
-webkit-overflow-scrolling: touch;
scroll-snap-type: y mandatory;
}
section {
position: relative;
text-align: center;
height: 100%;
scroll-snap-align: start;
}
::scrollbar {
display: none;
}
body {
font-family: "Avenir Next", Helvetica, sans-serif;
font-weight: normal;
font-size: 100%;
position: relative;
}
nav {
position: absolute;
top: 0;
left: 0;
width: 100%;
z-index: 10;
}
nav ul {
display: flex;
justify-content: space-around;
margin: 0;
padding: 1rem 0;
}
nav ul li{
display: flex;
justify-content: space-around;
}
.nav-link{
text-decoration: none;
color: grey
}
.one {
background: black;
}
.two {
background: darkblue;
}
.three {
background: lightgreen;
}
.four {
background: lightcoral;
}
.five {
background: lightskyblue;
}
.six {
background: orange;
}
h1 {
margin: 0;
position: absolute;
top: 50%;
transform: translateY(-50%);
width: 100%;
font-size: 80px;
letter-spacing: 5px;
color: #fff;
text-transform: uppercase;
}
<nav>
<ul>
<li><a class="nav-link" href="#one">one</a></li>
<li><a class="nav-link" href="#two">two</a></li>
<li><a class="nav-link" href="#three">three</a></li>
<li><a class="nav-link" href="#four">four</a></li>
<li><a class="nav-link" href="#five">five</a></li>
<li><a class="nav-link" href="#six">six</a></li>
</ul>
</nav>
<main class="Loop js-loop">
<section class="one" id="one">
<h1>One</h1>
</section>
<section class="two" id="two">
<h1>Two</h1>
</section>
<section class="three" id="three">
<h1>Three</h1>
</section>
<section class="four" id="four">
<h1>Four</h1>
</section>
<section class="five" id="five">
<h1>Five</h1>
</section>
<section class="six" id="six">
<h1>Six</h1>
</section>
<!--
These blocks are the same as the first blocks to get that looping illusion going.
You need to add clones to fill out a full viewport height.
-->
<section class="one is-clone">
<h1>One</h1>
</section>
<section class="two is-clone">
<h1>Two</h1>
</section>
</main>
Adding the scrolling when you click on the link is a problem
With a normal container you only need to add the scroll-behaviour: smooth; to it. But here if you do that, you will lose the loop illusion because you will see it scroll back to the first instead of seemingly continue. (and it will also start an infinite back and forth scrolling that I couldn't fix yet)
var doc = window.document,
context = doc.querySelector('.js-loop'),
clones = context.querySelectorAll('.is-clone'),
disableScroll = false,
scrollHeight = 0,
scrollPos = 0,
clonesHeight = 0,
i = 0;
function getScrollPos () {
return (context.pageYOffset || context.scrollTop) - (context.clientTop || 0);
}
function setScrollPos (pos) {
context.scrollTop = pos;
}
function getClonesHeight () {
clonesHeight = 0;
for (i = 0; i < clones.length; i += 1) {
clonesHeight = clonesHeight + clones[i].offsetHeight;
}
return clonesHeight;
}
function reCalc () {
scrollPos = getScrollPos();
scrollHeight = context.scrollHeight;
clonesHeight = getClonesHeight();
if (scrollPos <= 0) {
setScrollPos(1); // Scroll 1 pixel to allow upwards scrolling
}
}
function scrollUpdate () {
if (!disableScroll) {
scrollPos = getScrollPos();
if (clonesHeight + scrollPos >= scrollHeight) {
// Scroll to the top when you’ve reached the bottom
setScrollPos(1); // Scroll down 1 pixel to allow upwards scrolling
disableScroll = true;
} else if (scrollPos <= 0) {
// Scroll to the bottom when you reach the top
setScrollPos(scrollHeight - clonesHeight);
disableScroll = true;
}
}
if (disableScroll) {
// Disable scroll-jumping for a short time to avoid flickering
window.setTimeout(function () {
disableScroll = false;
}, 40);
}
}
function init () {
reCalc();
context.addEventListener('scroll', function () {
window.requestAnimationFrame(scrollUpdate);
}, false);
window.addEventListener('resize', function () {
window.requestAnimationFrame(reCalc);
}, false);
}
if (document.readyState !== 'loading') {
init()
} else {
doc.addEventListener('DOMContentLoaded', init, false)
}
html,
body {
height: 100%;
overflow: hidden;
}
.Loop {
position: relative;
height: 100%;
overflow: scroll;
-webkit-overflow-scrolling: touch;
scroll-snap-type: y mandatory;
scroll-behavior: smooth;
}
section {
position: relative;
text-align: center;
height: 100%;
scroll-snap-align: start;
}
::scrollbar {
display: none;
}
body {
font-family: "Avenir Next", Helvetica, sans-serif;
font-weight: normal;
font-size: 100%;
position: relative;
}
nav {
position: absolute;
top: 0;
left: 0;
width: 100%;
z-index: 10;
}
nav ul {
display: flex;
justify-content: space-around;
margin: 0;
padding: 1rem 0;
}
nav ul li{
display: flex;
justify-content: space-around;
}
.nav-link{
text-decoration: none;
color: grey
}
.one {
background: black;
}
.two {
background: darkblue;
}
.three {
background: lightgreen;
}
.four {
background: lightcoral;
}
.five {
background: lightskyblue;
}
.six {
background: orange;
}
h1 {
margin: 0;
position: absolute;
top: 50%;
transform: translateY(-50%);
width: 100%;
font-size: 80px;
letter-spacing: 5px;
color: #fff;
text-transform: uppercase;
}
<nav>
<ul>
<li><a class="nav-link" href="#one">one</a></li>
<li><a class="nav-link" href="#two">two</a></li>
<li><a class="nav-link" href="#three">three</a></li>
<li><a class="nav-link" href="#four">four</a></li>
<li><a class="nav-link" href="#five">five</a></li>
<li><a class="nav-link" href="#six">six</a></li>
</ul>
</nav>
<main class="Loop js-loop">
<section class="one" id="one">
<h1>One</h1>
</section>
<section class="two" id="two">
<h1>Two</h1>
</section>
<section class="three" id="three">
<h1>Three</h1>
</section>
<section class="four" id="four">
<h1>Four</h1>
</section>
<section class="five" id="five">
<h1>Five</h1>
</section>
<section class="six" id="six">
<h1>Six</h1>
</section>
<!--
This block is the same as the first block to get that looping illusion going.
You need to add clones to fill out a full viewport height.
-->
<section class="one is-clone">
<h1>One</h1>
</section>
<section class="two is-clone">
<h1>Two</h1>
</section>
</main>
I know this code is not 100% functional yet, but I think it can lead us to a better answer.

You can use ID in this case.
Set the ID for your section and add anchor tag and set href attribute to your section id.
Go Up <!-- don't forget # before write your ID. -->
Don't forget set scroll-behavior to smooth for smooth scrolling.

Related

Looking to make a scrolling (left to right) highlighted in page navigation bar

I'm looking to make a left to right scrolling navigation menu that's items are highlighted as you scroll down the page. This navigation will look similarly to the following in page navigation on Chase.com (https://www.chase.com/digital/customer-service?jp_cmp=rb/tap/off/na/prt). Please note that I want this navigation to stay scrollable on all devices.
Below is what I have so far. I'm currently having the issue with getting the nav options to scroll into focus as they are highlighted.
window.onscroll = function() {
myFunction()
};
var navbar = document.getElementById("inpagenav");
var sticky = inpagenav.offsetTop;
function myFunction() {
if (window.pageYOffset >= sticky) {
inpagenav.classList.add("sticky")
} else {
inpagenav.classList.remove("sticky");
}
}
// cache the navigation links
var $navigationLinks = $('#inpagenav > ul > li > a');
// cache (in reversed order) the sections
var $sections = $($(".pagenavsection").get().reverse());
// map each section id to their corresponding navigation link
var sectionIdTonavigationLink = {};
$sections.each(function() {
var id = $(this).attr('id');
sectionIdTonavigationLink[id] = $('#inpagenav > ul > li > a[href=\\#' + id + ']');
});
// throttle function, enforces a minimum time interval
function throttle(fn, interval) {
var lastCall, timeoutId;
return function() {
var now = new Date().getTime();
if (lastCall && now < (lastCall + interval)) {
// if we are inside the interval we wait
clearTimeout(timeoutId);
timeoutId = setTimeout(function() {
lastCall = now;
fn.call();
}, interval - (now - lastCall));
} else {
// otherwise, we directly call the function
lastCall = now;
fn.call();
}
};
}
function highlightNavigation() {
// get the current vertical position of the scroll bar
var myPadding = $('#inpagenav').height();
var scrollPosition = $(window).scrollTop();
// iterate the sections
$sections.each(function() {
var currentSection = $(this);
// get the position of the section
var sectionTop = currentSection.offset().top;
// if the user has scrolled over the top of the section
if (scrollPosition + myPadding >= sectionTop) {
// get the section id
var id = currentSection.attr('id');
// get the corresponding navigation link
var $navigationLink = sectionIdTonavigationLink[id];
// if the link is not active
if (!$navigationLink.hasClass('active')) {
// remove .active class from all the links
$navigationLinks.removeClass('active');
// add .active class to the current link
$navigationLink.addClass('active');
}
// we have found our section, so we return false to exit the each loop
return false;
}
});
}
$(window).scroll(throttle(highlightNavigation, 100));
// if you don't want to throttle the function use this instead:
// $(window).scroll( highlightNavigation );
.mainimage {
text-align: center;
height: 300px;
background: gray
}
nav {
background: white;
}
.sticky {
position: fixed;
top: 0;
width: 100%;
}
nav ul {
list-style: none;
padding: 0rem;
overflow: auto;
white-space: nowrap;
margin: 0rem;
overflow-x: scroll;
}
nav ul::-webkit-scrollbar-thumb {
background: #000;
}
nav ul li {
padding-top: 1rem;
vertical-align: center;
display: inline-block;
}
nav ul li a {
text-decoration: none;
color: dodgerblue;
display: inline-block;
margin: 0rem 2rem;
padding-bottom: 1rem;
border-bottom: 3px solid transparent;
}
nav ul li a:hover {
color: #0054a4;
border-bottom: 3px solid #0054a4;
}
nav ul li .active {
color: #308ce3;
font-weight: bold;
border-bottom: 3px solid #308ce3;
}
#section1 {
text-align: center;
height: 500px;
padding: 4rem 0rem;
background: orange;
}
#section2 {
text-align: center;
height: 200px;
padding: 4rem 0rem;
background: green;
}
#section3 {
text-align: center;
height: 300px;
padding: 4rem 0rem;
background: blue;
}
#section4 {
text-align: center;
height: 500px;
padding: 4rem 0rem;
background: red;
}
#section5 {
text-align: center;
height: 500px;
padding: 4rem 0rem;
background: pink;
}
#section6 {
text-align: center;
height: 500px;
padding: 7rem 0rem;
background: purple;
}
#section7 {
text-align: center;
height: 500px;
padding: 7rem 0rem;
background: purple;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<!DOCTYPE html>
<html>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="menu.css">
<body>
<div id="contentwrapper">
<div class="mainimage">
<h1>The whole world</h1>
</div>
<nav id="inpagenav">
<ul>
<li>Section 1</li>
<li>Section 2</li>
<li>Section 3</li>
<li>Section 4</li>
<li>Section 5</li>
<li>Section 6</li>
</ul>
</nav>
<section id="section1" class="pagenavsection">
I'm section 1
</section>
<section id="section2" class="pagenavsection">
I'm section 2
</section>
<section id="section3" class="pagenavsection">
I'm section 3
</section>
<section id="section4" class="pagenavsection">
I'm section 4
</section>
<section id="section5" class="pagenavsection">
I'm section 5
</section>
<section id="section6" class="pagenavsection">
I'm section 6
</section>
<section id="section7">lo</section>
</div>
<script src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
<script src="ScrollMenu.js"></script>
</body>
</html>
You might just need to call $navigationLink.scrollIntoView() when you toggle the active class.
Per this answer, you may need to pass special options to scrollIntoView because the items are laid out horizontally.
$navigationLink.scrollIntoView({ inline: 'end' })
// end is my guess; allowable values are: start, center, end, or nearest (the default)

How to observe DOM element position changes

I need to observe a DOM element position as I need to show a popup panel relative to it (but not in the same container) and the panel should follow the element. How I should implement such logic?
Here is a snippet where you can see the opening of outer and nested popup panels, but they do not follow the horizontal scroll. I want them both to follow it and keep showing near the corresponding icon (and it should be a generic approach that will work in any place). You may ignore that nested popup is not closed together with outer - it's just to make the snippet simpler. I expect no changes except the showPopup function. Markup is specially simplified for this example; do not try to change it - I need it as it is.
~function handlePopups() {
function showPopup(src, popup, popupContainer) {
var bounds = popupContainer.getBoundingClientRect()
var bb = src.getBoundingClientRect()
popup.style.left = bb.right - bounds.left - 1 + 'px'
popup.style.top = bb.bottom - bounds.top - 1 + 'px'
return () => {
// fucntion to cleanup handlers when closed
}
}
var opened = new Map()
document.addEventListener('click', e => {
if (e.target.tagName === 'I') {
var wasActive = e.target.classList.contains('active')
var popup = document.querySelector(`.popup[data-popup="${e.target.dataset.popup}"]`)
var old = opened.get(popup)
if (old) {
old.src.classList.remove('active')
popup.hidden = true
old.close()
opened.delete(old)
}
if (!wasActive) {
e.target.classList.add('active')
popup.hidden = false
opened.set(popup, {
src: e.target,
close: showPopup(e.target, popup, document.querySelector('.popup-dest')),
})
}
}
})
}()
~function syncParts() {
var scrollLeft = 0
document.querySelector('main').addEventListener('scroll', e => {
if (e.target.classList.contains('inner') && e.target.scrollLeft !== scrollLeft) {
scrollLeft = e.target.scrollLeft
void [...document.querySelectorAll('.middle .inner')]
.filter(x => x.scrollLeft !== scrollLeft)
.forEach(x => x.scrollLeft = scrollLeft)
}
}, true)
}()
* {
box-sizing: border-box;
}
[hidden] {
display: none !important;
}
html, body, main {
height: 100%;
margin: 0;
}
main {
display: grid;
grid-template: auto 1fr 17px / auto 1fr auto;
}
section {
overflow: hidden;
display: flex;
flex-direction: column;
outline: 1px dotted red;
outline-offset: -1px;
position: relative;
}
.inner {
overflow: scroll;
padding: 0 1px 1px 0;
margin: 0 -18px -18px 0;
flex: 1 1 0px;
display: flex;
flex-direction: column;
}
.top {
grid-row: 1;
}
.bottom {
grid-row: 2;
}
.left {
grid-column: 1;
}
.middle {
grid-column: 2;
}
.right {
grid-column: 3;
}
.wide, .scroller {
width: 2000px;
flex: 1 0 1px;
}
.wide {
background: repeating-linear-gradient(to right, rgba(0,255,0,.5), rgba(0,0,255,.5) 16em);
}
.visible-scroll .inner {
margin-top: -1px;
margin-bottom: 0;
}
.scroller {
height: 1px;
}
.popup-dest {
pointer-events: none;
grid-row: 1 / 3;
position: relative;
}
.popup {
position: absolute;
border: 1px solid;
pointer-events: all;
}
.popup-outer {
width: 8em;
height: 8em;
background: silver;
}
.popup-nested {
width: 5em;
height: 5em;
background: antiquewhite;
}
i {
display: inline-block;
border-radius: 50% 50% 0 50%;
border: 1px solid;
width: 1.5em;
height: 1.5em;
line-height: 1.5em;
text-align: center;
cursor: pointer;
}
i::after {
content: "i";
}
i.active {
background: rgba(255,255,255,.5);
}
<main>
<section class="top left">
<div><div class="inner">
<div>Smth<br>here</div>
</div></div>
</section>
<section class="top middle">
<div class="inner">
<div class="wide">
<i data-popup="outer" style="margin-left:10em"></i>
<i data-popup="outer" style="margin-left:10em"></i>
<i data-popup="outer" style="margin-left:10em"></i>
<i data-popup="outer" style="margin-left:10em"></i>
<i data-popup="outer" style="margin-left:10em"></i>
<i data-popup="outer" style="margin-left:10em"></i>
<i data-popup="outer" style="margin-left:10em"></i>
</div>
</div>
</section>
<section class="top right">
<div class="inner">Smth here</div></section>
<section class="bottom left">
<div class="inner">Smth here</div>
</section>
<section class="bottom middle">
<div class="inner">
<div class="wide"><script>document.write("Smth is here too... ".repeat(1000))</script></div>
</div>
</section>
<section class="bottom right">
<div class="inner">Smth here</div>
</section>
<section class="middle visible-scroll">
<div class="inner">
<div class="scroller"></div>
</div>
</section>
<section class="middle popup-dest">
<div class="popup popup-outer" data-popup="outer" hidden>
<i data-popup="nested" style="margin-left:5em;margin-top:5em;"></i>
</div>
<div class="popup popup-nested" data-popup="nested" hidden>
</div>
</section>
</main>
Now I have following ideas:
Listening to the scroll event on the capturing phase on body and getting the actual position of the element via getBoundingClientRect and the reposition panel according to the current location. I am currently using a similar solution, but there is an issue. When the element is moving by another script, it doesn't force panel repositioning. One of the cases - when the element itself is another panel - simple filtering of unrelated scroll events filters such scrolls out. Also I have some cases with debounce and they are difficult to handle too.
Create IntersectionObserver to track moves. The problem seems to be in the fact that it only works on intersection size changes, not on any moves. I have an idea to crop viewport by rootMargin to the same rectangle that the element covers, but as options are readonly. It means I would need to create new observer on each move. I'm not sure about the performance impact of such a solution. Also as it provides only an approximate position, so I think that I can't eliminate calls to getBoundingClientRect.
A hybrid solution as scrolls are usually taking some continuous time. Use the previous idea with IntersectionObserver, but when the first move is detected, just subscribe to requestAnimationFrame and check the element position there. While position differs, handle it and recursively use requestAnimationFrame. If the position is the same (I am not sure if one frame is enough, maybe in 5 frames?), stop subscribing requestAnimationFrame and create a new IntersectionObserver.
I'm afraid that such solutions will have issues with performance. Also they seem to me too complex. Maybe there is some known solution which I should use?
Implementation of the first approach. Just subscribe all scroll events across the document and update the position in the handler. You can't filter events by the parents of an src element as in case of a nested popup scrolling element is not presented in the events chain.
Also it doesn't work if the popup is moved programmatically - you may notice it when the outer popup is moved to the other icon and nested stays in the old place.
function showPopup(src, popup, popupContainer) {
function position() {
var bounds = popupContainer.getBoundingClientRect()
var bb = src.getBoundingClientRect()
popup.style.left = bb.right - bounds.left - 1 + 'px'
popup.style.top = bb.bottom - bounds.top - 1 + 'px'
}
position()
document.addEventListener('scroll', position, true)
return () => { // cleanup
document.removeEventListener('scroll', position, true)
}
}
Full code:
~function syncParts() {
var sl = 0
document.querySelector('main').addEventListener('scroll', e => {
if (e.target.classList.contains('inner') && e.target.scrollLeft !== sl) {
sl = e.target.scrollLeft
void [...document.querySelectorAll('.middle .inner')]
.filter(x => x.scrollLeft !== sl)
.forEach(x => x.scrollLeft = sl)
}
}, true)
}()
~function handlePopups() {
function showPopup(src, popup, popupContainer) {
function position() {
var bounds = popupContainer.getBoundingClientRect()
var bb = src.getBoundingClientRect()
popup.style.left = bb.right - bounds.left - 1 + 'px'
popup.style.top = bb.bottom - bounds.top - 1 + 'px'
}
position()
document.addEventListener('scroll', position, true)
return () => { // cleanup
document.removeEventListener('scroll', position, true)
}
}
var opened = new Map()
document.addEventListener('click', e => {
if (e.target.tagName === 'I') {
var wasActive = e.target.classList.contains('active')
var popup = document.querySelector(`.popup[data-popup="${e.target.dataset.popup}"]`)
var old = opened.get(popup)
if (old) {
old.src.classList.remove('active')
popup.hidden = true
old.close()
opened.delete(old)
}
if (!wasActive) {
e.target.classList.add('active')
popup.hidden = false
opened.set(popup, {
src: e.target,
close: showPopup(e.target, popup, document.querySelector('.popup-dest')),
})
}
}
})
}()
* {
box-sizing: border-box;
}
[hidden] {
display: none !important;
}
html, body, main {
height: 100%;
margin: 0;
}
main {
display: grid;
grid-template: auto 1fr 17px / auto 1fr auto;
}
section {
overflow: hidden;
display: flex;
flex-direction: column;
outline: 1px dotted red;
outline-offset: -1px;
position: relative;
}
.inner {
overflow: scroll;
padding: 0 1px 1px 0;
margin: 0 -18px -18px 0;
flex: 1 1 0px;
display: flex;
flex-direction: column;
}
.top {
grid-row: 1;
}
.bottom {
grid-row: 2;
}
.left {
grid-column: 1;
}
.middle {
grid-column: 2;
}
.right {
grid-column: 3;
}
.wide, .scroller {
width: 2000px;
flex: 1 0 1px;
}
.wide {
background: repeating-linear-gradient(to right, rgba(0,255,0,.5), rgba(0,0,255,.5) 16em);
}
.visible-scroll .inner {
margin-top: -1px;
margin-bottom: 0;
}
.scroller {
height: 1px;
}
.popup-dest {
pointer-events: none;
grid-row: 1 / 3;
position: relative;
}
.popup {
position: absolute;
border: 1px solid;
pointer-events: all;
}
.popup-outer {
width: 8em;
height: 8em;
background: silver;
}
.popup-nested {
width: 5em;
height: 5em;
background: antiquewhite;
}
i {
display: inline-block;
border-radius: 50% 50% 0 50%;
border: 1px solid;
width: 1.5em;
height: 1.5em;
line-height: 1.5em;
text-align: center;
cursor: pointer;
}
i::after {
content: "i";
}
i.active {
background: rgba(255,255,255,.5);
}
<main>
<section class="top left">
<div><div class="inner">
<div>Smth<br>here</div>
</div></div>
</section>
<section class="top middle">
<div class="inner">
<div class="wide">
<i data-popup="outer" style="margin-left:10em"></i>
<i data-popup="outer" style="margin-left:10em"></i>
<i data-popup="outer" style="margin-left:10em"></i>
<i data-popup="outer" style="margin-left:10em"></i>
<i data-popup="outer" style="margin-left:10em"></i>
<i data-popup="outer" style="margin-left:10em"></i>
<i data-popup="outer" style="margin-left:10em"></i>
</div>
</div>
</section>
<section class="top right">
<div class="inner">Smth here</div></section>
<section class="bottom left">
<div class="inner">Smth here</div>
</section>
<section class="bottom middle">
<div class="inner">
<div class="wide"></div>
</div>
</section>
<section class="bottom right">
<div class="inner">Smth here</div>
</section>
<section class="middle visible-scroll">
<div class="inner">
<div class="scroller"></div>
</div>
</section>
<section class="middle popup-dest">
<div class="popup popup-outer" data-popup="outer" hidden>
<i data-popup="nested" style="margin-left:5em;margin-top:5em;"></i>
</div>
<div class="popup popup-nested" data-popup="nested" hidden>
</div>
</section>
</main>

click button scroll to specific div

I have a page that has a fixed menu and content box(div).
When click the menu, content box scroll to specific div.
So far so good.
This is the sample here.
https://jsfiddle.net/ezrinn/8cdjsmb9/11/
The problem is when I wrap this whole div and, make them as show/hide toggle button, the scroll is not working.
This is the sample that not working.
https://jsfiddle.net/ezrinn/8cdjsmb9/10/
Also here is the snippet
$('.btn').click(function() {
$(".wrap").toggleClass('on');
});
var div_parent_class_name;
var divs_class;
var id_offset_map = {};
$(document).ready(function() {
div_parent_class_name = "wrap_scroll";
divs_class = "page-section";
var scroll_divs = $("." + div_parent_class_name).children();
id_offset_map.first = 0;
scroll_divs.each(function(index) {
id_offset_map["#" + scroll_divs[index].id] = scroll_divs[index].offsetTop
});
$('a').bind('click', function(e) {
e.preventDefault();
var target = $(this).attr("href")
$('.wrap_scroll').stop().animate({
scrollTop: id_offset_map[target]
}, 600, function() {
/* location.hash = target-20; */ //attach the hash (#jumptarget) to the pageurl
});
return false;
});
});
$(".wrap_scroll").scroll(function() {
var scrollPos = $(".wrap_scroll").scrollTop();
$("." + divs_class).each(function(i) {
var divs = $("." + divs_class);
divs.each(function(idx) {
if (scrollPos >= id_offset_map["#" + this.id]) {
$('.menu>ul>li a.active').removeClass('active');
$('.menu>ul>li a').eq(idx).addClass('active');
}
});
});
}).scroll();
body,
html {
margin: 0;
padding: 0;
height: 3000px;
}
.wrap { display:none;}
.wrap.on { display:block;}
.menu {
width: 100px;
position: fixed;
top: 40px;
left: 10px;
}
.menu a.active {
background: red
}
.wrap_scroll {
position: absolute;
top: 20px;
left: 150px;
width: 500px;
height: 500px;
overflow-y: scroll
}
#home {
background-color: #286090;
height: 200px;
}
#portfolio {
background: gray;
height: 600px;
}
#about {
background-color: blue;
height: 800px;
}
#contact {
background: yellow;
height: 1000px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<button class="btn">show/hide</button>
<div class="wrap">
<div class="menu">
<ul>
<li><a class="active" href="#home">Home</a> </li>
<li>Portfolio </li>
<li>About </li>
<li>Contact </li>
</ul>a
</div>
<div class="wrap_scroll">
<div class="page-section" id="home">hh</div>
<div class="page-section" id="portfolio">pp</div>
<div class="page-section" id="about">aa</div>
<div class="page-section" id="contact">cc</div>
</div>
</div>
What Do I need to fix the code? please help.
When you calculate your offset, the div is hidden with display: none. This results in the offsets being set/calculated to zero.
Here's a quick fix I threw together: https://jsfiddle.net/hrb58zae/
Basically, moved the logic to determine offset after clicking show/hide.
var setOffset = null;
...
if (!setOffset) {
var scroll_divs = $("." + div_parent_class_name).children();
id_offset_map.first = 0;
scroll_divs.each(function(index) {
id_offset_map["#" + scroll_divs[index].id] = scroll_divs[index].offsetTop
});
setOffset = true;
}
In your CSS, instead of using display: none and display: block, try using visible instead:
.wrap { visibility:hidden;}
.wrap.on { visibility:visible;}
This will hide the element without affecting the layout.
Updated fiddle: https://jsfiddle.net/a5u683es/
The problem was you are trying to update id_offset_map when content was hidden. When you use 'display:none' prop you won't get dimensions for that element and so its not working.
I updated the logic please check the fiddle https://jsfiddle.net/qfrsmnh5/
var id_offset_map = {};
var div_parent_class_name = "wrap_scroll";
var divs_class = "page-section";
var scroll_divs = $("." + div_parent_class_name).children();
function updateOffsets(){
id_offset_map.first = 0;
scroll_divs.each(function(index) {
id_offset_map["#" + scroll_divs[index].id] = scroll_divs[index].offsetTop
});
}
$(document).ready(function() {
$('.btn').click(function() {
$(".wrap").toggleClass('on');
if($(".wrap").hasClass("on")){
updateOffsets();
}
});
$('a').on('click', function(e) {
e.preventDefault();
var target = $(this).attr("href")
$('.wrap_scroll').stop().animate({
scrollTop: id_offset_map[target]
}, 600, function() {
/* location.hash = target-20; */ //attach the hash (#jumptarget) to the pageurl
});
return false;
});
});
$(".wrap_scroll").on('scroll',function() {
var scrollPos = $(".wrap_scroll").scrollTop();
$("." + divs_class).each(function(i) {
var divs = $("." + divs_class);
divs.each(function(idx) {
if (scrollPos >= id_offset_map["#" + this.id]) {
$('.menu>ul>li a.active').removeClass('active');
$('.menu>ul>li a').eq(idx).addClass('active');
}
});
});
}).scroll();
body,
html {
margin: 0;
padding: 0;
height: 3000px;
}
.wrap { display:none;}
.wrap.on { display:block;}
.menu {
width: 100px;
position: fixed;
top: 40px;
left: 10px;
}
.menu a.active {
background: red;
}
.wrap_scroll {
position: absolute;
top: 20px;
left: 150px;
width: 500px;
height: 500px;
overflow-y: scroll;
}
#home {
background-color: #286090;
height: 200px;
}
#portfolio {
background: gray;
height: 600px;
}
#about {
background-color: blue;
height: 800px;
}
#contact {
background: yellow;
height: 1000px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<button class="btn">show/hide</button>
<div class="wrap">
<div class="menu">
<ul>
<li><a class="active" href="#home">Home</a></li>
<li>Portfolio </li>
<li>About </li>
<li>Contact </li>
</ul>
</div>
<div class="wrap_scroll">
<div class="page-section" id="home">hh</div>
<div class="page-section" id="portfolio">pp</div>
<div class="page-section" id="about">aa</div>
<div class="page-section" id="contact">cc</div>
</div>
</div>
works perfectly, it's just that when you use display: none you can not do the offsetTop calculations because in fact the element is not rendered, I'm not sure if all the values ​​give 0 or undefined, I guess undefined, a solution is always calculate Positions using a function:
var div_parent_class_name;
var divs_class;
var id_offset_map = {};
function calcTops(){
div_parent_class_name = "wrap_scroll";
divs_class = "page-section";
var scroll_divs = $("." + div_parent_class_name).children();
id_offset_map.first = 0;
scroll_divs.each(function(index) {
id_offset_map["#" + scroll_divs[index].id] = scroll_divs[index].offsetTop
});
}
https://jsfiddle.net/561oe7rb/1/
is not the optimal way, but it is to give you an idea. Sorry for my English.
Just Checkout This Working page I have designed
jQuery(document).on('scroll', function(){
onScroll();
});
jQuery(document).ready(function($) {
div_slider();
showhide();
});
/*show hide content*/
function showhide(){
$('.toggle-wrapper button').on('click', function(){
$('.wrapper').toggle();
// div_slider();
})
}
/*scrolling page on header elements click*/
function div_slider(){
$('ul li a').on('click', function(e){
e.preventDefault();
$('ul li a').removeClass('active');
$(this).addClass('active');
var attrval = $(this.getAttribute('href'));
$('html,body').stop().animate({
scrollTop: attrval.offset().top
}, 1000)
});
}
/*adding active class on header elements on page scroll*/
function onScroll(event){
var scrollPosition = $(document).scrollTop();
$('ul li a').each(function () {
var scroll_link = $(this);
var ref_scroll_Link = $(scroll_link.attr("href"));
if (ref_scroll_Link.position().top <= scrollPosition && ref_scroll_Link.position().top + ref_scroll_Link.height() > scrollPosition) {
$('ul li a').removeClass("active");
scroll_link.addClass("active");
}
else{
scroll_link.removeClass("active");
}
});
}
body {
margin: 0;
}
.toggle-wrapper {
position: fixed;
top: 0;
left: 0;
right: 0;
background-color: #ccd2cc;
text-align: center;
}
.toggle-wrapper button {
background-color: #ED4C67;
color: #ffffff;
padding: 10px 20px;
border: 0;
cursor: pointer;
border-radius: 5px;
}
.toggle-wrapper button:active{
background-color: #B53471;
}
header {
background-color: #6C5CE7;
position: fixed;
top: 36px;
z-index: 99;
left: 0;
right: 0;
}
header ul {
list-style: none;
display: flex;
justify-content: space-between;
align-items: center;
padding: 0;
margin: 0;
}
ul li {
flex: 1 100%;
display: flex;
justify-content: center;
}
.wrapper {
margin-top: 36px;
}
header a {
color: #ffffff;
padding: 15px;
display: block;
text-decoration: navajowhite;
text-transform: uppercase;
width: 100%;
text-align: center;
}
header a.active {
color: #000000;
background-color: #ffffff;
}
section {
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
}
section.section1 {
background-color: #FFEAA7;
}
section.section2{
background-color:#FAB1A0;
}
section.section3{
background-color:#7F8C8D;
}
section.section4{
background-color:#4CD137;
}
section.section5{
background-color:#A3CB38;
}
section.section6{
background-color:#70A1FF;
}
section.section7{
background-color:#079992;
}
<div class="toggle-wrapper">
<button>Toggle</button>
</div>
<div class="wrapper" style="display: none;">
<header>
<ul>
<li><a class="active" href="#one">one</a></li>
<li>two</li>
<li>three</li>
<li>four</li>
<li>five</li>
<li>six</li>
<li>seven</li>
</ul>
</header>
<section class="section1" id="one">SECTION ONE</section>
<section class="section2" id="two">SECTION TWO</section>
<section class="section3" id="three">SECTION THREE</section>
<section class="section4" id="four">SECTION FOUR</section>
<section class="section5" id="five">SECTION FIVE</section>
<section class="section6" id="six">SECTION SIX</section>
<section class="section7" id="seven">SECTION SEVEN</section>
</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

Scroll Points / overflow-y breaking javascript function with window.pageYOffset

I have a page where I was using JS - specifically window.pageYOffset - and HTML data to change the inner HTML of the h1 footer, use l1 links to scroll the page to each section, and to add classes to each li when I reached the top of each section.work-page.
However, after I implemented CSS scroll points and added the div.container over the scrollable sections my javascript stopped working. Specifically when I set the overflow-y: scroll.
Basically when I made the div.container overflow-y: scroll; the doWork function stopped working and I can't figure out why.
^^^^ div.container in CSS
const doWork = function () {
const p01Tag = document.getElementById("p01")
const p02Tag = document.getElementById("p02")
const p03Tag = document.getElementById("p03")
const p04Tag = document.getElementById("p04")
const container = document.querySelector("div.container")
const sections = document.querySelectorAll("section.work-page")
const clientTag = document.querySelector("h2.about")
document.addEventListener("scroll", function () {
const pixels = window.pageYOffset
console.log(pixels)
sections.forEach(section => {
if(section.offsetTop - 400 <= pixels) {
clientTag.innerHTML = section.getAttribute("data-client")
if (section.hasAttribute("data-seen-1")) {
p01Tag.classList.add("move")
} else {
p01Tag.classList.remove("move")
}
if (section.hasAttribute("data-seen-2")) {
p02Tag.classList.add("move")
} else {
p02Tag.classList.remove("move")
}
if (section.hasAttribute("data-seen-3")) {
p03Tag.classList.add("move")
} else {
p03Tag.classList.remove("move")
}
if (section.hasAttribute("data-seen-4")) {
p04Tag.classList.add("move")
} else {
p04Tag.classList.remove("move")
}
}
})
})
// scrolling between projects ============================
function smoothScroll(target, duration) {
const targetTag = document.querySelector(target);
let targetPosition = targetTag.getBoundingClientRect().top;
const startPosition = window.pageYOffset;
let startTime = null;
function animation(currentTime) {
if(startTime === null ) startTime = currentTime;
const timeElapsed = currentTime - startTime;
const run = ease(timeElapsed, startPosition, targetPosition, duration);
window.scrollTo(0,run);
if (timeElapsed < duration) requestAnimationFrame(animation)
}
function ease(t, b, c, d) {
t /= d / 2;
if (t < 1) return c / 2 * t * t + b;
t--;
return -c / 2 * (t * (t - 2) - 1) + b;
}
requestAnimationFrame(animation)
}
p01Tag.addEventListener("click", function() {
smoothScroll('section.fn-up', 800)
})
p02Tag.addEventListener("click", function() {
smoothScroll('section.cameron', 800)
})
p03Tag.addEventListener("click", function() {
smoothScroll('section.truax', 800)
})
p04Tag.addEventListener("click", function() {
smoothScroll('section.romero', 800)
})
}
doWork()
const doInfo = function () {
const toggleTag = document.querySelector("a.contact")
const sectionTag = document.querySelector("section.info-page")
toggleTag.addEventListener("click", function () {
sectionTag.classList.toggle("open")
if (sectionTag.classList.contains("open")) {
toggleTag.innerHTML = "Close"
} else {
toggleTag.innerHTML = "Info"
}
})
}
doInfo()
html {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
*, *:before, *:after {
-webkit-box-sizing: inherit;
-moz-box-sizing: inherit;
box-sizing: inherit;
}
body {
font-family: 'IBM Plex Mono', monospace;
font-size: 14px;
background-color: #050505;
color: #ffffff;
line-height: 1.1;
}
header {
width: 100%;
z-index: 3;
position: fixed;
top: 0;
left: 0;
padding-top: 40px;
padding-left: 40px;
padding-right: 40px;
}
.contact {
float: right;
}
ul {
font-family: 'IBM Plex Mono', Arial;
font-size: 14px;
}
p {
margin-bottom: 50px;
}
/* Info page -------------------- */
section.info-page {
z-index: 2;
position: fixed;
top: -100vh;
left: 0;
display: flex;
margin-top: 100px;
margin-left: 40px;
margin-right: 40px;
width: 100vw;
min-height: 100vh;
max-width: 100vw;
transition: top 0.5s;
}
section.info-page.open {
top: 0;
}
/* Work page ------------------------*/
div.container {
top: 0;
left: 0;
max-width: 100vw;
max-height: 100vh;
/* WHEN WE ADD THIS OVERFLOW SETTING IN ORDER TO GET THE CSS SCROLL SNAP POINTS TO WORK IT BREAKS THE JAVASCRIPT */
/* overflow-y: scroll; */
scroll-snap-type: y mandatory;
position: relative;
z-index: 1;
}
div.work-info {
width: 13vw;
top: 0;
left: 0;
height: 100vh;
position: fixed;
z-index: 2;
padding-right: 80px;
display: flex;
align-items: center;
margin-left: 40px;
}
div.work-info li {
padding-bottom: 30px;
transition: transform 0.3s;
}
div.work-info li.move {
transform: translateX(15px);
}
footer {
width: 100%;
z-index: 1;
position: fixed;
bottom: 0;
left: 0;
padding-left: 40px;
padding-right: 40px;
padding-bottom: 40px;
color: #979797;
}
section.work-page {
scroll-snap-align: start;
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
position: relative;
}
section.work-page img {
max-width: 60vw;
}
<body>
<!-- hidden modal that runs off of the info.js script -->
<section class="info-page">
<h1>
Hello
</h1>
</section>
<header>
<a class="contact" href="#">Info</a>
</header>
<!-- objects that get new classes with javascript on pageYOffset -->
<div class="work-info">
<ul>
<li id="p01" data-number="FN-UP Magazine">01</li>
<li id="p02" data-number="Cameron Tidball-Sciullo">02</li>
<li id="p03" data-number="Jacob Truax">03</li>
<li id="p04" data-number="Alexander Romero">04</li>
</ul>
</div>
<!-- scollable sections using the scroll points and triggering the pageYOffset -->
<div class="container">
<section class="work-page fn-up" data-client="FN-UP Magazine" data-seen-1="yes">
<div class="content">
<img src="lib/fn-up.png">
</div>
</section>
<section class="work-page cameron" data-client="Cameron Tidball-Sciullo" data-seen-2="yes">
<div class="content">
<img src="lib/alex.png">
</div>
</section>
<section class="work-page truax" data-client="Jacob Truax" data-seen-3="yes">
<div class="content">
<img src="lib/old.png">
</div>
</section>
<section class="work-page romero" data-client="Alexander Romero" data-seen-4="yes">
<div class="content">
<img src="lib/alex.png">
</div>
</section>
</div>
<footer class="footer">
<h2 class="about">FN-UP Magazine</h2>
</footer>
</body>
You have added a event listener to the page's Document object.
document.addEventListener("scroll", function () {
Then you calculate the number of pixels the document is currently scrolled along the vertical axis using window.pageYOffset.
const pixels = window.pageYOffset
When you set the CSS attribute overflow-y to scroll in the div.container element, new scrollbars appears on the window. According to MDN:
scroll
Content is clipped if necessary to fit the padding box. Browsers display scrollbars whether or not any content is actually clipped. (This prevents scrollbars from appearing or disappearing when the content changes.) Printers may still print overflowing content.
From that moment on, you are not scrolling the document, you are scrolling div.container. That won't trigger you scroll event.
You need to bound the event to the div element:
const container = document.querySelector("div.container")
container.addEventListener("scroll", function () {
And, instead of calculating how much document has scrolled, get the scrollTop property of the div.container:
const pixels = container.scrollTop
You need to make the same changes in whatever part of the code that involves the above calculations. In smoothScroll():
// const startPosition = window.pageYOffset;
const startPosition = container.scrollTop;
// window.scrollTo(0,run);
container.scrollTo(0,run);

Changing nav-bar color after scrolling?

How can I set the navbar with no background color?
When scrolling down after a div the nav-bar gets a new background-color (the nav-bar should be fixed at top, I use navbar-fixed-top in Bootstrap)
I've tried some tutorials but I didn't succeed.
This is the website : http://attafothman.olympe.in/
I'm talking about that black nav-bar on top.
Here is simplest way how to change navbar color after window scroll:
Add follow JS to head:
$(function () {
$(document).scroll(function () {
var $nav = $(".navbar-fixed-top");
$nav.toggleClass('scrolled', $(this).scrollTop() > $nav.height());
});
});
and this CSS code
.navbar-fixed-top.scrolled {
background-color: #fff !important;
transition: background-color 200ms linear;
}
Background color of fixed navbar will be change to white when scroll exceeds height of navbar.
See follow JsFiddle
this is a simple pure javascript
var myNav = document.getElementById('mynav');
window.onscroll = function () {
if (document.body.scrollTop >= 200 ) {
myNav.classList.add("nav-colored");
myNav.classList.remove("nav-transparent");
}
else {
myNav.classList.add("nav-transparent");
myNav.classList.remove("nav-colored");
}
};
in some chrome versions there is a bug with:
document.body.scrollTop
so you may add a condition like this:
if (document.body.scrollTop >= 200 || document.documentElement.scrollTop >= 200 )
sure you must have 2 classes
.nav-colored { background-color:#000; }
.nav-transparent { background-color:transparent;}
Here is a jsfiddle example. Using Jquery to change the background color based on scroll pixel position.
Here is a fiddle using bootstrap
$(document).ready(function(){
var scroll_start = 0;
var startchange = $('#startchange');
var offset = startchange.offset();
if (startchange.length){
$(document).scroll(function() {
scroll_start = $(this).scrollTop();
if(scroll_start > offset.top) {
$(".navbar-default").css('background-color', '#f0f0f0');
} else {
$('.navbar-default').css('background-color', 'transparent');
}
});
}
});
i think this solution is shorter and simpler than older answers.
This is Js Code:
const navbar = document.querySelector('.nav-fixed');
window.onscroll = () => {
if (window.scrollY > 300) {
navbar.classList.add('nav-active');
} else {
navbar.classList.remove('nav-active');
}
};
And my css:
header.nav-fixed {
width: 100%;
position: fixed;
transition: 0.3s ease-in-out;
}
.nav-active {
background-color:#fff;
box-shadow: 5px -1px 12px -5px grey;
}
Today I've gone through the same question, how to change navbar background-color as scrolling. And I was seeking for a solution using CSS only, no jquery, no bootstrap nor javascript. But then it turned out couldn't be done with CSS only yet (as of today Dec 2019). And have to choose, I'll stick with the core technology - javascript instead of jquery or bootstrap unless it's far more complicated using js than the others. But luckily it's not.
Here's the code:
- It uses onscroll/ scroll event of window to trigger the event listener.
- In the event listener, use pageYOffset/ scrollY of window to check the scroll status.
Browser support are seemingly the same between both:
- https://caniuse.com/#search=pageYOffset
- https://caniuse.com/#search=scrollY
var navbar = document.querySelector('nav')
window.onscroll = function() {
// pageYOffset or scrollY
if (window.pageYOffset > 0) {
navbar.classList.add('scrolled')
} else {
navbar.classList.remove('scrolled')
}
}
body {
margin: 0;
padding: 0;
background: url(https://occ-0-325-395.1.nflxso.net/dnm/api/v6/6AYY37jfdO6hpXcMjf9Yu5cnmO0/AAAABaKr-dQAdVTt7fuGCgzntgBBrFce2DMW72dF86eO7EnXbFZvzmX2TPnQAg3HwAsvt7ZnDnP0nwuHOtPwpWGGOE22fXq2.webp?r=847) top/contain no-repeat;
}
nav {
position: -webkit-sticky;
position: sticky;
/* sticky or fixed are fine */
position: fixed;
top: 0;
height: 69px;
width: 100%;
background: linear-gradient(to bottom, #000, #0003 70%,#0000); /* background when scroll is in the top */
transition: background .5s; /* control how smooth the background changes */
}
nav.scrolled {
background: #0a0a0a;
}
main {
height: 200vh;
}
<nav></nav>
<main></main>
<script>
$(document).ready(function(){
$(window).scroll(function() { // check if scroll event happened
if ($(document).scrollTop() > 50) { // check if user scrolled more than 50 from top of the browser window
$(".navbar-fixed-top").css("background-color", "#f8f8f8"); // if yes, then change the color of class "navbar-fixed-top" to white (#f8f8f8)
} else {
$(".navbar-fixed-top").css("background-color", "transparent"); // if not, change it back to transparent
}
});
});
</script>
This can be done using jQuery.
Here is a link to a fiddle.
When the window scrolls, the distance between the top of the window and the height of the window is compared. When the if statement is true, the background color is set to transparent. And when you scroll back to the top the color comes back to white.
$(document).ready(function(){
$(window).scroll(function(){
if($(window).scrollTop() > $(window).height()){
$(".menu").css({"background-color":"transparent"});
}
else{
$(".menu").css({"background-color":"white"});
}
})
})
window.addEventListener('scroll', function (e) {
var nav = document.getElementById('nav');
if (document.documentElement.scrollTop || document.body.scrollTop > window.innerHeight) {
nav.classList.add('nav-colored');
nav.classList.remove('nav-transparent');
} else {
nav.classList.add('nav-transparent');
nav.classList.remove('nav-colored');
}
});
best approach to use event listener. especially for Firefox browser, check this doc Scroll-linked effects and Firefox is no longer support document.body.scrollTop and alternative to use document.documentElement.scrollTop. This is completes the answer from Yahya Essam
How about the Intersection Observer API? This avoids the potential sluggishness from using the scroll event.
HTML
<nav class="navbar-fixed-top">Navbar</nav>
<main>
<div class="content">Some content</div>
</main>
CSS
.navbar-fixed-top--scrolled changes the nav bar background color. It's added to the nav bar when the content div is no longer 100% visible as we scroll down.
.navbar-fixed-top {
position: sticky;
top: 0;
height: 60px;
}
.navbar-fixed-top--scrolled {
/* change background-color to whatever you want */
background-color: grey;
}
JS
Create the observer to determine when the content div fully intersects with the browser viewport.
The callback function is called:
the first time the observer is initially asked to watch the target element
when content div is no longer fully visible (due to threshold: 1)
when content div becomes fully visible (due to threshold: 1)
isIntersecting indicates whether the content div (the target element) is fully intersecting with the observer's root (the browser viewport by default).
// callback function to be run whenever threshold is crossed in one direction or the other
const callback = (entries, observer) => {
const entry = entries[0];
// toggle class depending on if content div intersects with viewport
const navBar = document.querySelector('.navbar-fixed-top');
navBar.classList.toggle('navbar-fixed-top--scrolled', !entry.isIntersecting);
}
// options controls circumstances under which the observer's callback is invoked
const options = {
// no root provided - by default browser viewport used to check target visibility
// only detect if target element is fully visible or not
threshold: [1]
};
const io = new IntersectionObserver(callback, options);
// observe content div
const target = document.querySelector('.content');
io.observe(target);
IntersectionObserver options
The nav bar currently changes background color when the content div starts moving off the screen.
If we want the background to change as soon as the user scrolls, we can use the rootMargin property (top, right, bottom, left) and set the top margin to negative the height of the nav bar (60px in our case).
const options = {
rootMargin: "-60px 0px 0px 0px",
threshold: [1]
};
You can see all the above in action on CodePen. Kevin Powell also has a good explanation on this (Github & YouTube).
Slight variation to the above answers, but with Vanilla JS:
var nav = document.querySelector('nav'); // Identify target
window.addEventListener('scroll', function(event) { // To listen for event
event.preventDefault();
if (window.scrollY <= 150) { // Just an example
nav.style.backgroundColor = '#000'; // or default color
} else {
nav.style.backgroundColor = 'transparent';
}
});
So I'm using querySelector to get the navbar
I added a scroll event to the window to track the scrollY property
I check if it's higher than 50 then I add the active class to the navbar, else if it contains it already, I simply remove it and I'm pretty sure the conditions can be more currated and simplified.
I made this codepen to help you out!
const navbar = document.querySelector('#nav')
window.addEventListener('scroll', function(e) {
const lastPosition = window.scrollY
if (lastPosition > 50 ) {
navbar.classList.add('active')
} else if (navbar.classList.contains('active')) {
navbar.classList.remove('active')
} else {
navbar.classList.remove('active')
}
})
I use WordPress which comes with Underscore. So when you register your theme scripts, you would use 'jquery' and 'underscore' as the handle for the array of the dependancies. If you are not using WordPress, then make sure that you load both the jQuery framework and Underscore before your scripts.
CodePen: https://codepen.io/carasmo/pen/ZmQQYy
To make this demo (remember it requires both jQuery and Underscore).
HTML:
<header class="site-header">
<div class="logo">
</div>
<nav>navigation</nav>
</header>
<article>
Content with a forced height for scrolling. Content with a forced height for scrolling. Content with a forced height for scrolling. Content with a forced height for scrolling. Content with a forced height for scrolling. Content with a forced height for scrolling. Content with a forced height for scrolling
</article>
CSS:
body,
html {
margin: 0;
padding: 0;
font: 100%/180% sans-serif;
background: #eee;
}
html {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
*,
*::before,
*::after {
box-sizing: inherit;
}
article {
height: 2000px;
padding: 5%;
background: #fff;
margin: 2% auto;
max-width: 900px;
box-shadow: 0px 0px 30px 0px rgba(0, 0, 0, 0.10);
}
.site-header {
background: #fff;
padding: 20px 5%;
box-shadow: 0px 0px 12px 0px rgba(0, 0, 0, 0.23);
transition: all .5s ease-in-out;
-web-kit-position: sticky;
position: sticky;
top: 0;
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-orient: horizontal;
-webkit-box-direction: normal;
-ms-flex-direction: row;
flex-direction: row;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
-webkit-box-pack: center;
-ms-flex-pack: center;
justify-content: center;
}
.logo {
background-image: url('the-path-to-the-logo.svg');
background-repeat: no-repeat;
background-position: center center;
width: 200px;
height: 60px;
background-size: contain;
transition: width .5s ease-in-out, height .5s ease-in-out;
}
.site-header nav {
text-align: right;
-webkit-box-flex: 1;
-ms-flex-positive: 1;
flex-grow: 1;
-ms-flex-preferred-size: 0;
flex-basis: 0;
}
.site-header.is-scrolling {
opacity: .8;
background: tomato;
padding: 10px 5%;
}
.site-header.is-scrolling .logo {
height: 40px;
width: 100px;
}
jQuery:
( function( window, $, undefined ) {
'use strict';
////////////// Begin jQuery and grab the $ ////////////////////////////////////////
$(document).ready(function() {
function is_scrolling() {
var $element = $('.site-header'),
$nav_height = $element.outerHeight( true );
if ($(this).scrollTop() >= $nav_height ) { //if scrolling is equal to or greater than the nav height add a class
$element.addClass( 'is-scrolling');
} else { //is back at the top again, remove the class
$element.removeClass( 'is-scrolling');
}
}//end is_scrolling();
$(window).scroll(_.throttle(is_scrolling, 200));
}); //* end ready
})(this, jQuery);
I've recently done it slightly different to some of the examples above so thought I'd share, albeit very late!
Firstly the HTML, note there is only one class within the header:
<body>
<header class="GreyHeader">
</header>
</body>
And the CSS:
body {
height: 3000px;
}
.GreyHeader{
height: 200px;
background-color: rgba(107,107,107,0.66);
position: fixed;
top:200;
width: 100%;
}
.FireBrickRed {
height: 100px;
background-color: #b22222;
position: fixed;
top:200;
width: 100%;
}
.transition {
-webkit-transition: height 2s; /* For Safari 3.1 to 6.0 */
transition: height 2s;
}
The html uses only the class .greyHeader but within the CSS I have created another class to call once the scroll has reached a certain point from the top:
$(function() {
var header = $(".GreyHeader");
$(window).scroll(function() {
var scroll = $(window).scrollTop();
if (scroll >= 500) {
header.removeClass('GreyHeader').addClass("FireBrickRed ");
header.addClass("transition");
} else {
header.removeClass("FireBrickRed ").addClass('GreyHeader');
header.addClass("transition");
}
});
});
check this fiddle: https://jsfiddle.net/29y64L7d/1/
First things first, you have to include Jquery into your HTML file or whatever file you are using.
create a script code space in the head part of your file and include the code below.
$(document).ready(function(){
$(window).scroll(function(){
if($(window).scrollTop() > 100){
$(".navbar").css({"background-color":"black"});
}
else{
$(".navbar").css({"background-color":""});
}
})
})
With this where the code says ($(window).scrollTop() > 100) 100 is in "px" so you can specify the height at which the function is called.
This line of code $(".navbar").css({"background-color":"black"}); is where you replace your class name of the Nav element. This is just directly accessing the CSS and then editing the CSS.
HTML Code Below
<header class="hero">
<nav class="navbar ">
<div class="container">
<a class="navbar-brand" href="#">
<img src="" alt=""> </a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
<li class="nav-item">
<a class="nav-link active" aria-current="page" href="#">Home</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">TV shows</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">Movies</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">News and Popular</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">My List</a>
</li>
</ul>
</div>
</div>
</nav>
</header>
$(document).ready(function(){
$(window).scroll(function() {
if ($(document).scrollTop() >1290 ) {
$(".navbar-fixed-top").css("background-color", "rgb(255, 160, 160)");
}else if ($(document).scrollTop() >850) {
$(".navbar-fixed-top").css("background-color", "black");
}else if ($(document).scrollTop() >350) {
$(".navbar-fixed-top").css("background-color", "rgba(47, 73, 158, 0.514)");
}
else {
$(".navbar-fixed-top").css("background-color", "red");
}
});
});
#import url(https://fonts.googleapis.com/css?family=Roboto+Slab:400,700|Open+Sans);
body {
font-family: "Roboto Slab", sans-serif;
position: relative;
}
h1,
h2,
h3,
h4 {
font-family: "Open Sans", sans-serif;
}
.main {
padding-top: 50px;
}
#home {
padding-top: 20%;
background-image: linear-gradient( rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0.5)), url('https://s31.postimg.org/l5q32ptln/coffee_cup_mug_apple.jpg');
background-attachment: fixed;
background-repeat: no-repeat;
background-position: center center;
position: relative;
height: 100vh;
}
#home h2 {
color: white;
font-size: 4em;
}
#home h4 {
color: white;
font-size: 2em;
}
#home ul {
list-style-type: none;
text-align: center;
}
#home li {
padding-bottom: 12px;
padding-right: 12px;
display: inline;
}
#home li:last-child {
padding: 0;
}
#media (max-width: 710px) {
#home li {
display: block;
}
}
.img-style {
height: 200px;
width: 200px;
margin-top: 50px;
}
#about {
height: 100vh;
padding-top: 10%;
background: linear-gradient( rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0.5)), url('https://s32.postimg.org/sm6o6617p/photo_1432821596592_e2c18b78144f.jpg');
background-attachment: fixed;
background-repeat: no-repeat;
background-position: center center;
position: relative;
color: white;
}
#about p,
li {
font-size: 17px;
}
.navbar.color-yellow {
background-color: yellow;
height: 50px;
color: yellow;
}
.navbar.color-change {
background-color: #f45b69;
height: 50px;
color: rgba(255, 254, 255, 0.8);
}
#portfolio {
padding-top: 30px;
rgba(226,
226,
226,
1);
background: linear-gradient(to bottom, rgba(226, 226, 226, 1) 0%, rgba(209, 209, 209, 1) 25%, rgba(219, 219, 219, 1) 57%, rgba(254, 254, 254, 1) 100%);
height: 100vh;
}
#portfolio .block .portfolio-contant ul li {
float: left;
width: 32.22%;
overflow: hidden;
margin: 6px;
position: relative;
}
#portfolio .block .portfolio-contant ul li:hover .overly {
opacity: 1;
}
#portfolio .block .portfolio-contant ul li:hover .position-center {
position: absolute;
top: 50%;
-webkit-transform: translate(0%, -50%);
-moz-transform: translate(0%, -50%);
-ms-transform: translate(0%, -50%);
transform: translate(0%, -50%);
}
#portfolio .block .portfolio-contant ul li a {
display: block;
color: #fff;
}
#portfolio .block .portfolio-contant ul li a h2 {
font-size: 22px;
text-transform: uppercase;
letter-spacing: 1px;
}
#portfolio .block .portfolio-contant ul li a p {
font-size: 15px;
}
#portfolio .block .portfolio-contant ul li a span {
font-style: italic;
font-size: 13px;
color: #655E7A;
}
#portfolio .block .portfolio-contant ul img {
width: 100%;
height: auto;
}
#portfolio .block .portfolio-contant .overly {
position: absolute;
top: 0;
bottom: 0;
right: 0;
left: 0;
background: rgba(0, 0, 0, 0.9);
opacity: 0;
-webkit-transition: .3s all;
-o-transition: .3s all;
transition: .3s all;
text-align: center;
}
#portfolio .block .portfolio-contant .position-center {
position: absolute;
top: 50%;
left: 10%;
-webkit-transform: translate(0%, 50%);
-moz-transform: translate(0%, 50%);
-ms-transform: translate(0%, 50%);
transform: translate(0%, 50%);
-webkit-transition: .5s all;
-o-transition: .5s all;
transition: .5s all;
}
#contact {
height: 100vh;
padding-top: 10%;
background: linear-gradient( rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0.5)), url("https://s32.postimg.org/ex6q1qxkl/pexels_photo.jpg");
background-attachment: fixed;
background-size: cover;
background-repeat: no-repeat;
background-position: center center;
position: relative;
}
#contact h3 {
color: white;
}
footer ul {
list-style-type: none;
text-align: center;
}
footer li {
display: inline;
padding-right: 10px;
}
footer li:last-child {
padding: 0;
}
footer p {
color: grey;
font-size: 11px;
}
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js"></script>
<link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.4.0/css/font-awesome.min.css" rel="stylesheet" />
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css" rel="stylesheet" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script>
<!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>
<header>
<nav class="navbar navbar-default navbar-fixed-top" role="navigation">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#collapse" aria-expanded="false">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="#featured">Portfolio</a>
</div>
<!-- navbar-header -->
<div class="collapse navbar-collapse" id="collapse">
<ul class="nav navbar-nav navbar-right">
<li class="active">Home</li>
<li>About</li>
<li>Portfolio</li>
<li>Contact</li>
</ul>
</div>
<!-- collapse navbar-collapse -->
</div>
<!-- container -->
</nav>
</header>
<div class="main">
<div class="row " id="home" data-speed="2" data-type="background">
<div class="container">
<h2 class="text-center">Welcome to my portfolio</h2>
<h4 class="text-center">Where awesomeness is crafted</h4>
<hr>
<ul>
<li><i class="fa fa-github"></i> GitHub</li>
<li><i class="fa fa-linkedin"></i> LinkedIn</li>
<li><i class="fa fa-fire"></i> FreeCodeCamp</li>
</ul>
</div>
<!--container-->
</div>
<!--home-->
<div class="row" id="about" data-speed="2" data-type="background">
<div class="container">
<div class="row">
<div class="col-md-5 col-md-offset-1">
<h2>About me</h2>
<p>Courteous and Enthusiastic,I'm interested in IT and around in its globe. I began to be fascinated by web programming i.e, building websites and developing cross-platform apps.I'm always looking for new ventures where i can learn evolve and
expertise.
</marquee>
</div>
</p>
<p>My skills are:
<ul>
<li> Front-end : HTML5, CSS3 , jQuery, Bootstrap, AngularJS</li>
<li>Back-end: Ruby on Rails</li>
<li>Methodology: Agile, TDD</li>
</ul>
</p>
</div>
<!--col-md-5-->
<div class="col-md-4 col-md-offset-1">
<img class="img-circle img-style hidden-xs" src="https://www.triketech.site/images/log.png" />
</div>
</div>
<!--row-->
</div>
<!--container-->
</div>
<!--about-->
<div class="row" id="portfolio" data-speed="2" data-type="background">
<div class="container">
<h2 class="text-center">Portfolio projects</h2>
<div class="row">
<div class="col-md-12">
<div class="block">
<div class="portfolio-contant">
<ul id="portfolio-contant-active">
<li class="mix Branding">
<a href="#">
<img src="#" alt="">
<div class="overly">
<div class="position-center">
<h2>Local Support</h2>
</div>
</div>
<!--overly-->
</a>
</li>
</ul>
</div>
<!--portfolio-contant-->
</div>
<!--block-->
</div>
<!--col-->
</div>
<!--row-->
</div>
<!--container-->
</div>
<!--portfolio-->
<div class="row" id="contact" data-speed="2" data-type="background">
<div class="container">
<div class="col-md-4 col-md-offset-1">
<h3>Contact me at:</h3>
<h3>thegreatvamshi#triketech.com</h3>
</div>
<!--col-md-4-->
</div>
<!--container-->
</div>
<!--contact-->
</div>
<!--main-->
<footer>
<ul>
<li>Home </li>
<li>About </li>
<li>Portfolio </li>
<li>Contact </li>
</ul>
<p class="text-center">Copyright © - All Rights Reserved. </p>
</footer>
</body>
</html>
<script>
$(document).ready(function(){
$(window).scroll(function() {
if ($(document).scrollTop() >1920 ) {
$(".navbar-fixed-top").css("background-color", "rgb(255, 160, 160)");
} else if ($(document).scrollTop() >1580) {
$(".navbar-fixed-top").css("background-color", "black");
} else if ($(document).scrollTop() >620) {
$(".navbar-fixed-top").css("background-color", "rgba(47, 73, 158, 0.514)");
} else {
$(".navbar-fixed-top").css("background-color", "transparent");
}
});
});
</script>
First you make an id named nav (can change whatever you want) inside the nav div (exp: id="nav")
Then at the bottom where body tag had been finished. You add this code
<script>
$(document).ready(function()
$(window).scroll(function(){
var scroll = $(window).scrollTop();
if(scroll>50){
$("#nav").css("background", "#555");
}
else {
$("#nav").css("background", "transparent");
}
})
})
</script>
$(window).on('activate.bs.scrollspy', function (e,obj) {
if ((window.innerHeight + window.pageYOffset) >= document.body.offsetHeight) {
return;
}
var isBGLight = $(obj.relatedTarget).hasClass('nav_white');
var isBGDark = $(obj.relatedTarget).hasClass('nav_blue');
$('.menu').removeClass('nav_white');
$('.menu').removeClass('nav_blue');
if(isBGDark)
{
$('.menu').addClass('nav_white');
}else if(isBGLight)
{
$('.menu').addClass('nav_blue');
}
/*var isScrolled = $(document).scrollTop() > 1;
$('.menu').toggleClass('scrolled', isScrolled);
$(".demos").toggleClass("demo");
$(".demos").toggleClass("demo1");
var posicionActual = $(document).scrollTop();
$.each($('.nav_transparent'),function(){
if ($(this).position().top < posicionActual){
$("nav.menu").removeClass("nav_white");
$("nav.menu").removeClass("nav_blue");
$("nav.menu").addClass("nav_transparent");
$(".demos").removeClass("demo");
$(".demos").addClass("demo1");
$(".cls").removeClass("cls2");
$(".cls").addClass("cls1");
$(".cl").removeClass("cl2");
$(".cl").addClass("cl1");
$(".hamb-bottom").css({"background-color": "#fff"});
$(".hamb-middle").css({"background-color": "#fff"});
$(".hamb-top").css({"background-color": "#fff"});
}
});
$.each($('.nav_blue'),function(){
if ($(this).position().top <= posicionActual){
$("nav.menu").removeClass("nav_transparent");
$("nav.menu").removeClass("nav_white");
$("nav.menu").addClass("nav_blue");
$(".demos").removeClass("demo1");
$(".demos").addClass("demo");
$(".cls").removeClass("cls2");
$(".cls").addClass("cls1");
$(".cl").removeClass("cl2");
$(".cl").addClass("cl1");
$(".hamb-bottom").css({"background-color": "#fff"});
$(".hamb-middle").css({"background-color": "#fff"});
$(".hamb-top").css({"background-color": "#fff"});
}
});
$.each($('.nav_white'),function(){
if ($(this).position().top <= posicionActual){
$("nav.menu").removeClass("nav_blue");
$("nav.menu").removeClass("nav_transparent");
$("nav.menu").addClass("nav_white");
$(".demos").removeClass("demo");
$(".demos").addClass("demo1");
$(".cls").removeClass("cls1");
$(".cls").addClass("cls2");
$(".cl").removeClass("cl1");
$(".cl").addClass("cl2");
$(".hamb-bottom").css({"background-color": "#4285f4"});
$(".hamb-middle").css({"background-color": "#4285f4"});
$(".hamb-top").css({"background-color": "#4285f4"});
}
});*/
});
$(window).on("scroll", function(){
if($(document).scrollTop() < 10)
{
$('.nav').removeClass('nav_white');
$('.nav').removeClass('nav_blue');
$('.nav').removeClass('nav_transparent');
$('.nav').addClass('nav_transparent');
}
});
the solutions, maybe

Categories

Resources