I've made a parallax effect on my site. Now i want to realize actions for buttons.
Click on button must move user's screen to the anker. But it's work wrong. Function defines offset and use this data, but parallax effect change that parameter. How i can use ankers and parallax together?
$(document).ready(function() {
$(window).bind('scroll',function(e){
parallaxScroll();
});
var div1Height = $('.div1').height();
var div2Height = $('.div2').height();
var div3Height = $('.div3').height();
var div2Top = div1Height;
$('.div2').css('top', div2Top);
var div3Top = div2Top + div2Height;
$('.div3').css('top', div3Top);
div1Position = $('.div1').position().top;
div2Position = $('.div2').position().top;
div3Position = $('.div3').position().top;
// Navigation
$('a.firstImage').click(function(){
$('html, body').animate({
scrollTop:0
}, 1000, function() {
parallaxScroll();
});
return false;
});
$('a.secondDiv1').click(function(){
$('html, body').animate({
scrollTop:$('.div1').offset().top
}, 1000, function() {
parallaxScroll();
});
return false;
});
$('a.thirdDiv2').click(function(){
$('html, body').animate({
scrollTop:$('.div2').offset().top
}, 1000, function() {
parallaxScroll();
});
return false;
});
$('a.fouthDiv3').click(function(){
$('html, body').animate({
scrollTop:$('.div3').offset().top
}, 1000, function() {
parallaxScroll();
});
return false;
});
});
// Parallax
var div1Position = 0;
var div2Position = 0;
var div3Position = 0;
var scrolledAlbum = 0;
var scrolledFooter = 0;
function parallaxScroll(){
var scrolled = $(window).scrollTop();
if ($(document).scrollTop() + $(window).height() < $('.div2').height() + $('.div2').offset().top) {
if ($(document).scrollTop() + $(window).height() < $('.div1').height() + $('.div1').offset().top) {
$('.div1').css('top', div1Position - scrolled * 0.95);
$('.div2').css('top', div2Position - scrolled * 0.95);
$('.div3').css('top', div3Position - scrolled * 0.95);
scrolledAlbum = scrolled;
} else {
$('.div1').css('top', div1Position - scrolled * 0.95);
$('.div2').css('top', div2Position -scrolled*1.9 + scrolledAlbum);
$('.div3').css('top', div3Position -scrolled*1.9 + scrolledAlbum);
scrolledFooter = scrolled;
}
} else {
$('.div1').css('top', div1Position - scrolled * 0.95);
$('.div2').css('top', div2Position -scrolled*1.9 + scrolledAlbum);
$('.div3').css('top', div3Position -scrolled*2.85 + scrolledAlbum + scrolledFooter);
}
}
body {
margin: 0;
padding: 0;
background: #000000;
font-family: 'Roboto', sans-serif;
letter-spacing: 0.5px;
color: #ffffff;
font-size: 20px;
width: 100%;
}
p {
color: white;
font-size: 24px;
}
ol, ul {
list-style: none;
}
/* Content */
.bodyImage {
width: 100%;
height: 100vh;
background: url(https://images.wallpaperscraft.ru/image/tekstura_treshchiny_chernyj_116899_1600x1200.jpg) no-repeat;
background-size: 100%;
display:flex;
justify-content: center;
align-items: center;
}
.body {
position: relative;
height: 115vh;
background-attachment: fixed;
}
.div1 {
width: 100%;
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
background: #000000;
position: absolute;
top: 0px;
z-index: 2;
}
.div2 {
width: 100%;
height: 100vh;
display: flex;
flex-direction: column;
text-align: center;
justify-content: center;
align-items: center;
position: absolute;
z-index: 3;
background: url(https://images.wallpaperscraft.ru/image/tekstura_treshchiny_chernyj_116899_1600x1200.jpg) no-repeat;
background-size: 100%;
}
/* Footer */
.div3 {
width: 100%;
height: 100vh;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
position: absolute;
z-index: 4;
background-color: #000000;
}
/* Navigation */
nav#primary {
z-index: 5;
position: fixed;
top: 50%;
right: 16px;
margin-top: -40px;
}
nav#primary li {
position: relative;
height: 20px;
}
nav#primary a {
display: block;
width: 20px;
height: 20px;
text-indent: -9999px;
background: transparent url(http://s1.iconbird.com/ico/0612/vistabasesoftwareicons/w48h481339252451BoxGrey4.png) 4px 4px no-repeat;
}
nav#primary a:hover, nav#primary a.active {
background: transparent url(http://s1.iconbird.com/ico/0612/vistabasesoftwareicons/w48h481339252451BoxGrey4.png) 4px 4px no-repeat;
}
nav#primary h1 {
position: absolute;
right: 22px;
top: -7px;
display: none;
padding: 4px 20px 4px 7px;;
color: #fff;
white-space: nowrap;
background: #000000 100% 50% no-repeat;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>DECAY</title>
<link type="text/css" rel="stylesheet" href="styles/style.css">
<link href="https://fonts.googleapis.com/css?family=Kaushan+Script|Roboto&display=swap" rel="stylesheet">
</head>
<body>
<div class="content">
<!-- Navigation -->
<nav id="primary">
<ul>
<li>
<h1>Image</h1>
<a class="firstImage" href="#bodyImage">View</a>
</li>
<li>
<h1>div1</h1>
<a class="secondDiv1" href="#div1">View</a>
</li>
<li>
<h1>div2</h1>
<a class="thirdDiv2" href="#div2">View</a>
</li>
<li>
<h1>div3</h1>
<a class="fouthDiv3" href="#div3">View</a>
</li>
</ul>
</nav>
<!-- Content -->
<div class="bodyImage">
<p>bodyImage</p>
</div>
<div class="body">
<div class="div1">
<p>div1</p>
</div>
<div class="div2">
<p>div2</p>
</div>
<div class="div3">
<p>div3</p>
</div>
</div>
</div>
<script type="text/javascript" src="js/jquery.js"></script>
<script type="text/javascript" src="js/script.js"></script>
</body>
Related
I created a modal and I had to do some extra work because ios is a pain with modals and setting overflow: hidden is not enough. The workaround on ios is to set the body to position: fixed when the modal is open and you can also set the top property to however far the page is scrolled like I did in the below example.
The thing that is tripping me up here is that the header should stay as it is wherever the user is on the page. When the body is set to fixed the header thinks that the page is not scrolled and always becomes transparent.
How can we fix the header logic so that when the modal is open, the header class does not change?
let scrollY
window.addEventListener('scroll', e => {
if (window.scrollY > 100) {
document.querySelector('.header').classList.remove('header--is-transparent')
} else {
document.querySelector('.header').classList.add('header--is-transparent')
}
})
const btn = document.querySelector('.btn')
btn.addEventListener('click', openModal)
function openModal() {
scrollY = window.scrollY
document.body.style.position = 'fixed'
document.body.style.overflow = 'hidden'
document.body.style.width = '100%'
document.body.style.top = `-${scrollY}px`
document.querySelector('.main').insertAdjacentHTML('beforeend', `
<div class="modal">
<div class="modal-backdrop"></div>
<div class="modal-content">
<h3>Modal content</h3>
<button class="closeBtn">X</button>
</div>
</div>
`)
}
function closeModal() {
document.body.style.position = ''
document.body.style.overflow = ''
document.body.style.width = ''
document.querySelector('.modal').remove()
}
document.addEventListener('click', e => {
if (e.target.closest('.closeBtn')) {
closeModal()
}
})
.main {
height: 2000px;
width: 100%;
}
.header {
position: fixed;
top: 0;
width: 100%;
height: 50px;
background-color: rgba(255, 255, 255);
opacity: 1;
}
.header.header--is-transparent {
opacity: 0.5;
}
li {
height: 300px;
list-style: none;
}
.li1 {
background: red;
}
.li2 {
background: blue;
}
.li3 {
background: green;
}
.btn {
color: #fff;
background: #000;
height: 60px;
width: 100px;
position: fixed;
bottom: 20px;
left: 20px;
}
.modal {
position: fixed;
top: 0;
right: 0;
height: 100%;
width: 100%;
z-index: 999;
display: flex;
align-items: center;
justify-content: center;
}
.modal-wrapper {
display: flex;
align-items: center;
justify-content: center;
}
.modal-content {
height: 200px;
width: 200px;
background: #fff;
position: absolute;
}
.modal-backdrop {
height: 100%;
width: 100%;
background-color: rgba(0, 0, 0, 0.5);
position: fixed;
top: 0;
left: 0;
}
<div class="main">
<div class="header header--is-transparent">HEADER</div>
<li class="li1"></li>
<li class="li2"></li>
<li class="li3"></li>
<button class="btn">open modal</button>
</div>
Just check if the body position is fixed when adding the transparent class, I would suggest to check out https://developer.mozilla.org/en-US/docs/Web/CSS/:modal the :modal property and how to set up your dialog so you can use it
let scrollY
window.addEventListener('scroll', e => {
if (window.scrollY > 100 || document.body.style.position == "fixed") {
document.querySelector('.header').classList.remove('header--is-transparent')
} else {
document.querySelector('.header').classList.add('header--is-transparent')
}
})
const btn = document.querySelector('.btn')
btn.addEventListener('click', openModal)
function openModal() {
scrollY = window.scrollY
document.body.style.position = 'fixed'
document.body.style.overflow = 'hidden'
document.body.style.width = '100%'
document.body.style.top = `-${scrollY}px`
document.querySelector('.main').insertAdjacentHTML('beforeend', `
<div class="modal">
<div class="modal-backdrop"></div>
<div class="modal-content">
<h3>Modal content</h3>
<button class="closeBtn">X</button>
</div>
</div>
`)
}
function closeModal() {
document.body.style.position = ''
document.body.style.overflow = ''
document.body.style.width = ''
document.querySelector('.modal').remove()
}
document.addEventListener('click', e => {
if (e.target.closest('.closeBtn')) {
closeModal()
}
})
.main {
height: 2000px;
width: 100%;
}
.header {
position: fixed;
top: 0;
width: 100%;
height: 50px;
background-color: rgba(255, 255, 255);
opacity: 1;
}
.header.header--is-transparent {
opacity: 0.5;
}
li {
height: 300px;
list-style: none;
}
.li1 {
background: red;
}
.li2 {
background: blue;
}
.li3 {
background: green;
}
.btn {
color: #fff;
background: #000;
height: 60px;
width: 100px;
position: fixed;
bottom: 20px;
left: 20px;
}
.modal {
position: fixed;
top: 0;
right: 0;
height: 100%;
width: 100%;
z-index: 999;
display: flex;
align-items: center;
justify-content: center;
}
.modal-wrapper {
display: flex;
align-items: center;
justify-content: center;
}
.modal-content {
height: 200px;
width: 200px;
background: #fff;
position: absolute;
}
.modal-backdrop {
height: 100%;
width: 100%;
background-color: rgba(0, 0, 0, 0.5);
position: fixed;
top: 0;
left: 0;
}
<div class="main">
<div class="header header--is-transparent">HEADER</div>
<li class="li1"></li>
<li class="li2"></li>
<li class="li3"></li>
<button class="btn">open modal</button>
</div>
I am trying to achieve parallax effect where I have almost done but I have problem in Heading tag <h1 id="text">Merry Chrismas</h1> which is not animating. <h1 id="text">Merry Chrismas</h1> goes to top when scrolling.
let text = document.getElementById('text');
let moon = document.getElementById('moon');
let snow = document.getElementById('snow');
let leftMountain = document.getElementById('left-mountain');
let rightMountain = document.getElementById('right-mountain');
let btn = document.getElementById('btn');
window.addEventListener('scroll', function() {
let value = window.scrollY;
text.style.top = value * -0.5 + '%';
moon.style.top = value * -0.5 + '%';
snow.style.top = value * 1 + 'px';
leftMountain.style.left = value * -0.5 + 'px';
rightMountain.style.left = value * 0.5 + 'px';
btn.style.marginTop = value * 2 + 'px';
})
/* To reset all margin and padding */
* {
margin: 0;
padding: 0;
}
/* Now To remove horizontal scroll bar we have to use box sizing properties */
html {
box-sizing: border-box;
}
*,
*:before,
*:after {
box-sizing: inherit;
}
body {
font-family: 'lato', sans-serif;
/* min-height: 100vh; */
background: #fff;
transition: all 0.2s linear;
color: #000;
overflow-x: hidden;
}
header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 10px;
/* position: relative;
z-index: 1000; */
}
.logo {
font-size: 2rem;
}
header a {
text-decoration: none;
padding: 10px 20px;
position: relative;
z-index: 1000;
}
header a:hover {
color: #ff556e;
}
header a.active {
border: 0.125rem solid #ff556e;
border-radius: 2rem;
color: #ff556e;
}
.hero-section {
/* position: relative; */
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
width: 100%;
}
.hero-section h1 {
font: italic bold 4rem lato, sans-serif;
position: absolute;
}
.hero-section img {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-size: cover;
pointer-events: none;
}
#base {
transform: translateY(200px);
}
.btn {
position: absolute;
display: inline-block;
text-decoration: none;
background: #ff0;
padding: 6px 15px;
border-radius: 20px;
font-size: 1.2rem;
font-weight: bold;
transform: translateY(50px);
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>JS Bin</title>
</head>
<body>
<header id="header">
Chrismas
<nav id="navigation">
Home
Description
Features
Contact Us
</nav>
</header>
<section id="heroSection" class="hero-section">
<img src="https://i.ibb.co/R605wLx/bg.png" alt="bg" id="bg">
<img src="https://i.ibb.co/LZpM2k2/moon.png" alt="moon" id="moon">
<img src="https://i.ibb.co/QnPgdXG/snow.png" alt="snow" id="snow">
<img src="https://i.ibb.co/mGgD2s7/back-mountain.png" alt="back-mountain" id="back-mountain">
<h1 id="text">Merry Chrismas</h1>
<img src="https://i.ibb.co/wCx7SMd/left-mountain.png" alt="left-mountain" id="left-mountain">
<img src="https://i.ibb.co/4YnDZTM/right-mountain.png" alt="right-mountain" id="right-mountain">
Explore
<img src="https://i.ibb.co/3kdcSVZ/base.png" alt="base" id="base">
</section>
</body>
</html>
[JSBIN Demo]
Try modifying to this:
text.style.top = value * -0.2 + '%';
#text {
position: fixed;
top: 0;
}
You can adjust to the speed that you need
< script >
document.getElementById("bottommenu").style.bottom = "-10vh";
var prevScrollpos = window.pageYOffset;
window.onscroll = function() {
var currentScrollPos = window.pageYOffset;
if (prevScrollpos < currentScrollPos) {
document.getElementById("bottommenu").style.bottom = "-10vh";
} else {
document.getElementById("bottommenu").style.bottom = "0";
}
if (currentScrollPos == 0) {
document.getElementById("bottommenu").style.bottom = "-10vh";
}
prevScrollpos = currentScrollPos;
}
<
/script>
<style>body,
html {
height: 100%;
margin: 0;
font-family: 'Karla';
font-size: 22px;
}
* {
box-sizing: border-box;
}
.container1 {
height: 10vh;
background-color: white;
z-index: 100;
position: absolute;
top: 0;
}
.header {
margin-left: 190px;
margin-top: 40px;
text-align: left;
opacity: 0.4;
z-index: 100;
}
.backgroundimage {
background-image: url("M0000-021-014_edited.jpg");
/* Full height */
height: 100vh;
/* Center and scale the image nicely */
background-position: center bottom;
background-repeat: no-repeat;
background-size: cover;
opacity: 0.7;
position: relative;
}
.leftthing {
width: calc(100% - 400px);
float: left;
}
.leftthing img {
width: 100%;
}
.clear {
clear: both;
}
.show {
display: none;
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: "Poppins", sans-serif;
}
.container {
height: 10vh;
background-color: white;
}
a {
text-decoration: none;
font-family: 'Karla';
}
a:visited {
text-decoration: none;
}
/* menu*/
ul {
list-style-type: none;
margin: 0;
padding: 0;
overflow: hidden;
background-color: transparent;
height: 10vh;
margin-right: 30px;
margin-bottom: 30px;
}
li {
float: right;
}
li a {
display: block;
color: black;
text-align: center;
text-decoration: none;
opacity: 0.4;
padding: 16px 16px;
margin-left: 30px;
margin-right: 30px;
transition: 0.2s;
}
li a:hover,
li a:focus {
color: black;
opacity: 1;
}
/* menu moving footer*/
#bottommenu {
position: fixed;
z-index: 100;
/* margin-left: 60px;*/
bottom: 0px;
background-color: transparent;
/* padding: 0px;*/
/* text-align: left;*/
width: 100%;
display: block;
transition: bottom 0.5s;
height: 10vh;
}
</style>
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta charset="UTF-8">
</head>
<body>
<div class="backgroundimage"></div>
<div class="container1">
<div class="header">
<div class="logo" onclick="scrollWin()">|bacheva
</div>
</div>
</div>
<div class="leftthing">
<img src="82213112_611171039713397_1145784978357878784_n.jpg" alt="building concept">
<img src="INTERIOR%20RENDER.jpg" alt="interior render">
<img src="exterior%20render.jpg" alt="exterior render">
<img src="big%20ground%20floor%20plan.jpg" alt="floor plan">
<img src="READY%20CLIMATE%20SCHEME.jpg" alt="climate scheme">
</div>
<div class="clear"></div>
<div class="container">
<ul style="font-family: 'Karla';font-size:22px;">
<li>|about</li>
<li>|work</li>
<li>|home</li>
</ul>
</div>
<div id="bottommenu">
<ul style="font-size:22px;">
<li>|about</li>
<li>|work</li>
<li>|home</li>
</ul>
</div>
</body>
</html>
I have the following page:
I full-screen background picture
some content with pictures when you scroll down
and a menu on the bottom right (with a height of 10vh)
I am using a javascript function that does the following: When you scroll down the menu is not shown, but when you scroll up the content, the menu appears on the bottom right. When you reach the full-screen background picture on the top the menu is set to hide again to not obstruct the picture. However, currently when you reach the top of the page, you see the menu for a millisecond before it hides again. Therefore, my question is: Can I alternate the javascript function and tell the menu to disappear 10vh before it reaches the full-size background picture so I would not see it before it disappears when I reach the top of the page.
Here is the function I am using:
<script>
document.getElementById("bottommenu").style.bottom = "-10vh";
var prevScrollpos = window.pageYOffset;
window.onscroll = function() {
var currentScrollPos = window.pageYOffset;
if (prevScrollpos < currentScrollPos) {
document.getElementById("bottommenu").style.bottom = "-10vh";
} else {
document.getElementById("bottommenu").style.bottom = "0";
}
if (currentScrollPos == 0) {
document.getElementById("bottommenu").style.bottom = "-10vh";
}
prevScrollpos = currentScrollPos;
}
</script>
Looking at the last 'if' the menu disappears when the current scroll is '0', but I would rather have it disappear before it reaches this last possible scroll (before it reaches the full-screen background picture.)
Thank you in advance for your help.
I am trying to combine code from #David, with code from #Luisdanielroviracontreras to make a cool index menu for my portfolio case studies. So far I have been able to animate the item background when clicked:
https://codepen.io/andyradall/pen/BaKJpbM
But as you can see, I run into problems when trying to animate the background of the menu item based on scroll position. The background item ends up in the wrong place: https://codepen.io/andyradall/pen/WNwdRLq
Note. My problem:
specificity and selecting the right HTML elements in the js.
Attaching the active class to the button rather than just the a
Alternatively I need to remove the button and attach the .effect to the a
Here is the current code for my hightlight navigation section:
// Header Sticky
window.onscroll = function() {myFunction()};
var header = document.getElementById("navigation");
var sticky = header.offsetTop;
function myFunction() {
if (window.pageYOffset > sticky) {
header.classList.add("sticky");
} else {
header.classList.remove("sticky");
}
}
/* Header buttons Luis that attatches active to buttons on click. */
/*
const buttons = document.querySelectorAll('.header-navbar button')
const effect = document.querySelector('.effect')
buttons.forEach((item) => {
item.addEventListener('click', (evt) => {
const x = evt.target.offsetLeft
buttons.forEach((btn) => { btn.classList.remove('active') })
evt.target.classList.add('active')
anime({
targets: '.effect',
left: `${x}px`,
duration: 600,
})
})
})
*/
/* header buttons on scroll from #Daniel at stackoverflow that misses the buttons and only attatches the active to the link*/
// caches the navigation links
var $navigationLinks = $('#navigation > ul > li > a');
// what I really want:
/*var buttons = document.querySelectorAll('.header-navbar button')
var effect = document.querySelector('.effect')*/
// cache (in reversed order) the sections
var $sections = $($(".section").get().reverse());
// map each section id to their corresponding navigation link
// here i really want to map each section id to the corresponding button
var sectionIdTonavigationLink = {};
$sections.each(function() {
var id = $(this).attr('id');
sectionIdTonavigationLink[id] = $('#navigation > 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 scrollPosition = $(window).scrollTop();
const effect = document.querySelector('.effect')
// iterate the sections
$sections.each(function() {
var currentSection = $(this);
// get the position of the section
var sectionTop = currentSection.offset().top;
var x = currentSection.offset().top;
console.log(x);
// if the user has scrolled over the top of the section
if (scrollPosition >= 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')
anime({
targets: '.effect',
left: `${x}px`,
duration: 600,
});
}
// 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 );
/* Global */
* {
list-style: none;
outline: none;
padding: 0;
margin: 0;
font-family: 'Poppins', sans-serif;
box-sizing: border-box;
}
body {
--primary: 25,91,255;
--color: 44, 62, 80;
display: flex;
align-items: flex-start;
justify-content: center;
background: #f4f7f8;
/* height: calc(var(--vh, 1vh) * 100); */
/* overflow: hidden; */
color: rgb(var(--color));
width: 100%;
}
main {
width: 100%;
}
/* .sticky attatch to #navigation on scroll past #navigation */
.sticky {
position: fixed;
top: 0;
}
.header-navbar ul {
list-style: none;
display: flex;
align-items: center;
justify-content: space-evenly;
width: 100%;
background: #fff;
}
.header-navbar {
display: flex;
align-items: center;
justify-content: space-evenly;
width: 100%;
background: #fff;
padding: 24px 8px 24px 8px;
box-shadow: 0px 0px 30px 0px rgba(0,0,0,.05);
}
.header-navbar button {
width: 140px;
height: 60px;
display: flex;
align-items: center;
justify-content: center;
border: 0px;
background: transparent;
border-radius: 20px;
transition: all .25s ease;
}
/*.header-navbar a {
width: 160px;
height: 50px;
display: flex;
align-items: center;
justify-content: center;
border: 0px;
background: transparent;
border-radius: 20px;
transition: all .25s ease;
}*/
.header-navbar a{
/*color: #333; */
font-size: 1rem;
padding: 10px 10px 10px 10px;
text-decoration: none;
}
/* to use if adding back link*/
.header-navbar a:active:not(.float) {
transform: scale(1.2);
}
.header-navbar button.active {
color: rgb(232, 76, 79);
}
/* if icon not text */
.header-navbar button i {
font-size: 1.2rem;
pointer-events: none;
}
/*background effect*/
.con-effect {
position: absolute;
width: 100%;
height: 100%;
/*top: 0px;
left: 0px;*/
overflow: hidden;
pointer-events: none;
display: flex;
align-items: center;
justify-content: center;
}
.effect {
background: rgba(232, 76, 232, 0.15);
width: 160px;
height: 70px;
position: absolute;
left: 100px;
border-radius: 20px;
}
/* Content sections styling */
.hero {
width:100%;
padding: 32px;
}
.section{
width:100%;
height: 500px;
padding: 32px;
}
#first {
background-color: #8face0;
}
#second {
background-color: #a388e8;
}
#third {
background-color: #f4769e;
}
#fourth {
background-color: #8face0;
}
#fifth {
background-color: #a388e8;
}
#bottom-spacer {
height: 2200px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src=https://cdnjs.cloudflare.com/ajax/libs/animejs/3.2.0/anime.min.js></script>
<body>
<main>
<section id="intro" class="hero">
<div>
<h1>This will be the hero section</h1>
</div>
</section>
<div id="navigation" class="header-navbar">
<div class="con-effect">
<div class="effect"></div>
</div>
<ul>
<li><button>Introduction</button></li>
<li><button>1. User research</button></li>
<li><button>2. Ideation</button></li>
<li><button>3. Design phase</button></li>
<li><button>4. Testing</button></li>
<li><button>5. Results</button></li>
</ul>
</div>
</div>
<section class="sections">
<section id="first" class="section">
<h2>1. User research</h2>
</section>
<section id="second" class="section">
<h2>2. Ideate</h2>
</section>
<section id="third" class="section">
<h2>3. Design phase</h2>
</section>
<section id="fourth" class="section">
<h2>4. Testing</h2>
</section>
<section id="fifth" class="section">
<h2>5. Results</h2>
</section>
<section id="bottom-spacer">
</section>
</section>
</main>
</body>
Finally solve it!
Solution:
Find the active navigationlink offset left, store it in var x
Use navigationlink offset left value (x) to place the background effect
Now, there is only styling and finetuning left :)
Final will receive updates here: https://codepen.io/andyradall/pen/WNwdRLq
// sticky header
window.onscroll = function() {myFunction()};
var header = document.getElementById("navigation");
//var effectClass = document.getElementById("effectClass")
var sticky = header.offsetTop;
function myFunction() {
if (window.pageYOffset > sticky) {
header.classList.add("sticky");
//effectClass.classList.add("effect")
} else {
header.classList.remove("sticky");
//effectClass.classList.remove("effect")
}
}
// cache the navigation links
var $navigationLinks = $('#navigation > ul > li > a');
// cache (in reversed order) the sections
var $sections = $($(".section").get().reverse());
// map each section id to their corresponding navigation link
var sectionIdTonavigationLink = {};
$sections.each(function() {
var id = $(this).attr('id');
sectionIdTonavigationLink[id] = $('#navigation > 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 scrollPosition = $(window).scrollTop();
const effect = document.querySelector('.effect')
// 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 >= 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');
var x = $navigationLink.offset().left;
anime({
targets: '.effect',
left: `${x-28}px`,
duration: 600,
endDelay: 1000,
})
}
// 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 );
* {
list-style: none;
outline: none;
padding: 0;
margin: 0;
font-family: 'Poppins', sans-serif;
box-sizing: border-box;
}
body {
--primary: 25,91,255;
--color: 44, 62, 80;
display: flex;
align-items: flex-start;
justify-content: center;
background: #f4f7f8;
/* height: calc(var(--vh, 1vh) * 100); */
/* overflow: hidden; */
color: rgb(var(--color));
width: 100%;
}
main {
width: 100%;
}
/* .sticky attatch to #navigation on scroll past #navigation */
.sticky {
position: fixed;
top: 0;
}
.header-navbar ul {
list-style: none;
display: flex;
align-items: center;
justify-content: space-evenly;
width: 100%;
background: #fafafa;
}
.header-navbar {
display: flex;
align-items: center;
justify-content: space-evenly;
width: 100%;
background: #fafafa;
padding: 2px 0 2px 0;
box-shadow: 0 1px 2px rgba(0,0,0,0.06),
0 2px 4px rgba(0,0,0,0.06),
0 4px 8px rgba(0,0,0,0.06),
0 8px 16px rgba(0,0,0,0.06),
0 16px 32px rgba(0,0,0,0.06),
0 32px 64px rgba(0,0,0,0.06);
}
.header-navbar li {
width: 160px;
height: 50px;
display: flex;
align-items: center;
justify-content: center;
border: 0px;
background: transparent;
border-radius: 20px;
transition: all .25s ease;
}
/*.header-navbar a {
width: 160px;
height: 50px;
display: flex;
align-items: center;
justify-content: center;
border: 0px;
background: transparent;
border-radius: 20px;
transition: all .25s ease;
}*/
.header-navbar a{
color: #333;
font-size: 1rem;
/*padding: 8px 8px 8px 8px;*/
text-decoration: none;
}
/* :not excludes class for specific use */
.header-navbar a:active:not(.float) {
transform: scale(1.2);
}
.active {
color: rgb(232, 76, 79)!important;
}
.header-navbar a:active {
color: rgb(232, 76, 79)!important;
}
/* if icon not text */
.header-navbar a i {
font-size: 1.2rem;
pointer-events: none;
}
/*background effect*/
.con-effect {
position: absolute;
width: 100%;
height: 100%;
top: 0px;
left: 0px;
overflow: hidden;
pointer-events: none;
display: flex;
align-items: center;
justify-content: center;
}
.effect {
background: rgba(232, 76, 232, 0.15);
width: 178px;
height: 40px;
position: absolute;
left: 1px;
border-radius: 40px;
}
/* Content sections styling */
.hero {
width:100%;
padding: 32px;
}
.section{
color: #666;
width:100%;
/*height: 500px;*/
padding: 32px;
}
#first {
background-color: #8face0;
}
#second {
background-color: #a388e8;
}
#third {
background-color: #f4769e;
}
#fourth {
background-color: #8face0;
}
#fifth {
background-color: #a388e8;
}
#bottom-spacer {
height: 2200px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/animejs/3.2.0/anime.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<body>
<main>
<section id="intro" class="hero section">
<div>
<h1>This will be the hero section</h1>
</div>
</section>
<div id="navigation" class="header-navbar">
<div class="con-effect">
<div id="effectClass" class="effect"></div>
</div>
<ul>
<li>Introduction</li>
<li>1. User research</li>
<li>2. Ideation</li>
<li>3. Design phase</li>
<li>4. Testing</li>
<li>5. Results</li>
</ul>
</div>
<section class="sections">
<section id="first" class="section">
<h2>1. User research</h2>
</section>
<section id="second" class="section">
<h2>2. Ideate</h2>
</section>
<section id="third" class="section">
<h2>3. Design phase</h2>
</section>
<section id="fourth" class="section">
<h2>4. Testing</h2>
</section>
<section id="fifth" class="section">
<h2>5. Results</h2>
</section>
<section id="bottom-spacer">
</section>
</section>
</main>
</body>
I need the menu items to look like they are now (like in iOS), but so far I have two big problems.
First, when I try to click on one of the links, it's not possible because of my linear-gradient. And second, when I click the down arrow to explore other menu items, all the gradient does not work.
How can I make it work properly?
I have also made a codepen for this
document.querySelectorAll('.slide').forEach(function (next) {
next.addEventListener('click', function () {
var container = this.parentElement.querySelector('.select');
sideScroll(container, 'bottom', 20, 25, 15);
});
});
document.querySelectorAll('.slideBack').forEach(function (back) {
back.addEventListener('click', function () {
var container = this.parentElement.querySelector('.select');
sideScroll(container, 'top', 20, 25, 15);
});
});
function sideScroll(element, direction, speed, distance, step) {
scrollAmount = 0;
var slideTimer = setInterval(function () {
if (direction == 'top') {
element.scrollTop -= step;
} else {
element.scrollTop += step;
}
scrollAmount += step;
if (scrollAmount >= distance) {
window.clearInterval(slideTimer);
}
}, speed);
}
* {
background: #80acdc;
}
.larger {
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
}
.larger .select {
width: 240px;
height: 270px;
display: flex;
flex-direction: column;
text-align: center;
overflow-y: hidden;
-ms-overflow-style: scroll;
scrollbar-width: none;
position: relative;
}
.larger .select::after {
content: '';
position: absolute;
display: block;
width: 100%;
height: 100%;
top: 0;
left: 0;
background-image: linear-gradient(#80acdc, transparent, #80acdc);
}
.larger .select a {
color: white;
margin: 3.5px 0;
}
.larger .select a:first-child {
margin-top: 0;
}
.larger #slide {
position: absolute;
left: 47%;
bottom: 38px;
color: #fff;
font-size: 15px;
cursor: pointer;
}
.larger #slideBack {
position: absolute;
top: 38px;
left: 47%;
color: #fff;
font-size: 15px;
cursor: pointer;
}
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.11.2/css/all.min.css">
<div class="container">
<div class="row">
<div class="col-lg-3">
<div class="larger">
<div class="select">
Action Lorem
Test Text
Action Lorem
Test Text
Action Lorem
Test Text
Action Lorem
Test Text
Action Lorem
Test Text
Action Lorem
Test Text
Action Lorem
Test Text
Action Lorem
Test Text
</div>
<i id="slideBack" class="slideBack fas fa-chevron-up"></i>
<i id="slide" class="slide fas fa-chevron-down"></i>
</div>
</div>
</div>
</div>
For the gradient to allow interaction with the underling elements you can use pointer-events: none
Your gradient is absolute positioned with top: 0 so it goes together with the scroll. In order to fix this you can set the position of the gradient to fixed (but then it will be stretched to the sizes of the vewport). The better way would be to wrap the list of the options with another container so the scroll won't influence the gradient position.. Something like this:
<div class="select-wrap">
<div class="select">
...
</div>
</div>
.larger .select-wrap {
width: 240px;
height: 270px;
}
.larger .select-wrap .select {
height: 100%;
display: flex;
flex-direction: column;
text-align: center;
overflow-y: hidden;
-ms-overflow-style: scroll;
scrollbar-width: none;
position: relative;
}
.larger .select-wrap::after {
content: '';
position: absolute;
display: block;
width: 100%;
height: 100%;
top: 0;
left: 0;
background-image: linear-gradient(#80acdc, transparent, #80acdc);
pointer-events: none; /* this allows for the mouse clicks go through */
}
document.querySelectorAll('.slide').forEach(function(next) {
next.addEventListener('click', function() {
var container = this.parentElement.querySelector('.select');
sideScroll(container, 'bottom', 20, 25, 15);
});
});
document.querySelectorAll('.slideBack').forEach(function(back) {
back.addEventListener('click', function() {
var container = this.parentElement.querySelector('.select');
sideScroll(container, 'top', 20, 25, 15);
});
});
function sideScroll(element, direction, speed, distance, step) {
scrollAmount = 0;
var slideTimer = setInterval(function() {
if (direction == 'top') {
element.scrollTop -= step;
} else {
element.scrollTop += step;
}
scrollAmount += step;
if (scrollAmount >= distance) {
window.clearInterval(slideTimer);
}
}, speed);
}
* {
background: #80acdc;
}
.larger {
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
}
.larger .select-wrap {
width: 240px;
height: 270px;
}
.larger .select-wrap .select {
height: 100%;
display: flex;
flex-direction: column;
text-align: center;
overflow-y: hidden;
-ms-overflow-style: scroll;
scrollbar-width: none;
position: relative;
}
.larger .select-wrap::after {
content: '';
position: absolute;
display: block;
width: 100%;
height: 100%;
top: 0;
left: 0;
background-image: linear-gradient(#80acdc, transparent, #80acdc);
pointer-events: none;
}
.larger .select a {
color: white;
margin: 3.5px 0;
}
.larger .select a:first-child {
margin-top: 0;
}
.larger #slide {
position: absolute;
left: 47%;
bottom: 38px;
color: #fff;
font-size: 15px;
cursor: pointer;
}
.larger #slideBack {
position: absolute;
top: 38px;
left: 47%;
color: #fff;
font-size: 15px;
cursor: pointer;
}
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.11.2/css/all.min.css">
<div class="container">
<div class="row">
<div class="col-lg-3">
<div class="larger">
<div class="select-wrap">
<div class="select">
Action Lorem
Test Text
Action Lorem
Test Text
Action Lorem
Test Text
Action Lorem
Test Text
Action Lorem
Test Text
Action Lorem
Test Text
Action Lorem
Test Text
Action Lorem
Test Text
</div>
</div>
<i id="slideBack" class="slideBack fas fa-chevron-up"></i>
<i id="slide" class="slide fas fa-chevron-down"></i>
</div>
</div>
</div>
</div>