I want to transition the background colour of a fixed header element on scroll. So as a user scrolls down a full page block website, the header subtly changes to complement the block colours. I have almost achieved this on a Pen, however I can't quite work out how to measure how much has been scrolled as a flag for when to change.
Some extra info: The scroll amount to change at is 400px. The background colours are stored and fetched in an array. For reference my jQuery code is below:
$(document).ready(function(){
var bgArray = ["#252525","#333333","#454545","#777777"];
var scrollHeight = 400;
var scrolled = $(window).scrollTop(); //What is this measuring?
$(window).scroll(function() { //Can these conditions be neatened into one function?
if(scrolled < scrollHeight) {
$('header').css('background', bgArray[0]);
}
if(scrolled > scrollHeight) { // i.e more than 400px
$('header').css('background', bgArray[1]);
}
// and so on (800, 1200...)
})
})
Please refer to the Pen for full code. Any suggestions are greatly appreciated!
Updated Solution (2019)
To set a background for the header based on the current block in view below the header while scrolling:
because header has fixed position, we can get the amount by which window has scrolled by using $header.offset().top,
(index of the current block in view) is the ratio of (the amount by which window has scrolled) to the (height of each block),
now adjusting for the height of the header, the index of the current block in view is Math.floor(($header.offset().top + headerHeight) / sectionHeight).
See simplified demo below:
$(function() {
var $header = $('header'),
$window = $(window),
bgArray = ["#252525", "red", "blue", "green"],
headerHeight = 50,
sectionHeight = 400;
$window.scroll(function() {
$header.css('background', bgArray[Math.floor(($header.offset().top + headerHeight)
/ sectionHeight)]);
});
});
:root {
--header: 50px; /* header height */
--block: 400px; /* block height */
}
* {
box-sizing: border-box; /* include padding in width / height calculations */
}
body {
margin: 0; /* reset default margin of body */
}
header {
height: var(--header); /* sets height of header */
position: fixed;
top: 0;
left: 0;
width: 100%;
color: #FFF;
padding: 12px 0;
background: #252525; /* initial background */
transition: background 1s ease;
}
.container {
margin: 0 auto;
}
.wrap>div {
height: var(--block); /* sets height of each block */
text-align: center;
}
p {
margin: 0; /* reset margin of p */
}
.block-1 {
background: #27AACC;
color: #FFF;
}
.block-2 {
background: #668E99;
color: #FFF;
}
.block-3 {
background: #4AFFC1;
color: #444;
}
.block-4 {
background: #FF8F8A;
color: #FFF;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<header>
<div class="container">
Website Title.
</div>
</header>
<div class="wrap">
<div class="block-1">
<div class="container">
<p>This pen was made to solve a problem on a project...</p>
</div>
</div>
<div class="block-2">
<div class="container">
<p>...I needed a sticky header with thr right bg colour.</p>
</div>
</div>
<div class="block-3">
<div class="container">
<p>But this conflicted with the footer, which was the same colour...</p>
</div>
</div>
<div class="block-4">
<div class="container">
<p>So the solution was to subtley change the header's bg on scroll</p>
</div>
</div>
</div>
Original Solution
Check the top of each block with respect to how much the window has been scrolled (scrollTop) using $(window).scrollTop() > $('.block-1').offset().top. So now we can use this to change color on entering the block - see demo below:
$(document).ready(function() {
var $header = $('header'),
$window = $(window),
bgArray = ["#252525", "#333333", "#454545", "#777777"],
headerHeight = $header.outerHeight();
$window.scroll(function() {
for (var i = 1; i < 5; i++) {
if ($window.scrollTop() + headerHeight > $('.block-' + i).offset().top) {
$header.css('background', bgArray[i - 1]);
}
}
});
});
#import url('https://fonts.googleapis.com/css?family=Roboto:300,400,700');
body {
font-family: 'Roboto', sans-serif;
font-size: 30px;
font-weight: 300;
margin-top: 0;
}
header {
width: 100%;
height: 50px;
line-height: 50px;
position: fixed;
font-size: 24px;
font-weight: 700;
color: #FFF;
padding: 12px 0;
margin: 0;
background: #252525;
transition: background 1s ease;
}
.wrap {
padding-top: 74px;
margin: 0;
}
.container {
width: 960px;
margin: 0 auto;
overflow: hidden;
}
.block-1,
.block-2,
.block-3,
.block-4 {
height: 400px;
text-align: center;
}
p {
margin-top: 185px;
}
.block-1 {
background: #27AACC;
color: #FFF;
}
.block-2 {
background: #668E99;
color: #FFF;
}
.block-3 {
background: #4AFFC1;
color: #444;
}
.block-4 {
background: #FF8F8A;
color: #FFF;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<header>
<div class="container">
Website Title.
</div>
</header>
<div class="wrap">
<div class="block-1">
<div class="container">
<p>This pen was made to solve a problem on a project...</p>
</div>
</div>
<div class="block-2">
<div class="container">
<p>...I needed a sticky header with thr right bg colour.</p>
</div>
</div>
<div class="block-3">
<div class="container">
<p>But this conflicted with the footer, which was the same colour...</p>
</div>
</div>
<div class="block-4">
<div class="container">
<p>So the solution was to subtley change the header's bg on scroll</p>
</div>
</div>
</div>
Note that this solution needlessly loops through the sections on each scroll update called by the browser - and I don't like the look of it.
you are using scrolled as a fixed variable you should use it directly in your condition
this will make it dynamic for all elements inside wrap div
$(document).ready(function(){
var bgArray = ["#252525","#333333","#454545","#777777"];
$(window).scroll(function() {
for(var i = 1; i < bgArray.length; i++) {
if ($(window).scrollTop() > $('.wrap div:nth-child(' + i + ')').offset().top) {
$('header').css('background', bgArray[i-1]);
}
}
});
})
Try Like this:
$(document).ready(function(){
var bgArray = ["#252525","#333333","#454545","#777777"];
var scrollHeight = 400;
$(window).scroll(function() {
var scrolled = $(window).scrollTop();
var index=Number((scrolled/scrollHeight).toFixed());
if(bgArray[index]!=undefined)
$('header').css('background', bgArray[index]);
});
})
This is current scroll, so it should be inside: $(window).scrollTop()
Related
I'm currently working on a project where the logo color should change depending on the background color. I would prefer to do this with CSS classes.
Unfortunately, the problem is: As soon as the first DIV of the class "bg02" is scrolled, the class changes for the logo too, but as soon as the following "bg02" divs are scrolled, nothing happens anymore. What am I doing wrong? Can you help me?
Here's my code:
JavaScript
$(document).on("scroll", function() {
var scrollPos = $(document).scrollTop();
$('#logo').each(function() {
var currDiv = $(this);
var refElement = $('.bg02');
if (refElement.position().top <= scrollPos && refElement.position().top + refElement.height() > scrollPos) {
$('#logo').removeClass("inverted");
currDiv.addClass("inverted");
} else {
currDiv.removeClass("inverted");
}
});
});
CSS
#logo {
position: fixed;
top: 20px;
left: 5%;
z-index: 100;
font-size: 26px;
font-weight: 700;
color: #000;
}
#logo.inverted {
color: #fff;
}
.bg01, .bg02 {
position: relative;
width: 100%;
height: 600px;
}
.bg01 {
background: #fff;
}
.bg02 {
background: #000;
}
HTML
<div id="logo">Logo</div>
<div class="bg01"></div>
<div class="bg02"></div>
<div class="bg01"></div>
<div class="bg02"></div>
<div class="bg01"></div>
<div class="bg02"></div>
Your issue is that $('.bg02').position() can only return a single position, so it returns the position for the first one.
To use your method of checking scrollTop(), you need to loop .bg02 not #logo
Couple of small changes to your code:
Loop .bg02:
$('.bg02').each(function() {
var refElement = $(this);
and a "break" inside the if - return false to stop the loop continuing and removing the inverted class for the later .bg02 that doesn't match
if (positioncheck) {
$("#logo").addClass("inverted");
return false;
}
You can also "tweak" when the logo gets inverted by considering its position, eg:
var scrollPos = $(document).scrollTop()
+ $("#logo").position().top
+ ($("#logo").height() / 2)
as it was, it would only invert when bg02 got to the top.
Updated snippet:
$(document).on("scroll", function() {
var scrollPos = $(document).scrollTop()
+ $("#logo").position().top
+ ($("#logo").height() / 2)
$('.bg02').each(function() {
var refElement = $(this);
if (refElement.position().top <= scrollPos
&& refElement.position().top + refElement.height() > scrollPos) {
$('#logo').addClass("inverted");
// found one, so exit .each
return false;
} else {
$('#logo').removeClass("inverted");
}
});
});
#logo {
position: fixed;
top: 20px;
left: 5%;
z-index: 100;
font-size: 26px;
font-weight: 700;
color: #000;
}
#logo.inverted {
color: #fff;
}
.bg01, .bg02 {
position: relative;
width: 100%;
height: 200px;
}
.bg01 {
background: #fff;
}
.bg02 {
background: #000;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="logo">Logo</div>
<div class="bg01"></div>
<div class="bg02"></div>
<div class="bg01"></div>
<div class="bg02"></div>
<div class="bg01"></div>
<div class="bg02"></div>
Good day,
I've came across the following CodePen from Estelle Pasquin. I would like to add this Apple-like scroll effect to my website.
Getting this to work on my site is no problem. However I would like to place content above this animation and this is where the problem comes in.
Based on the above CodePen content is structured like this:
<div class="intro mac"></div>
<div id="mac" class="mac"></div>
<div class="content">
<h2>Heading</h2>
<p>Content here</p>
</div>
However I need additional content above this animation section, like:
<div class="contentOne">
<h2>Heading 1</h2>
<p>Content here</p>
</div>
<div class="animationContent">
<div class="intro mac"></div>
<div id="mac" class="mac"></div>
</div>
<div class="content">
<h2>Heading 2 </h2>
<p>More content here</p>
</div>
In other words:
User scrolls through website content
User gets to a content break section where they see this big image, scroll, see the nice animation
User continues scrolling through rest of site
However this existing code only works when placed at the top of the page. Like a hero image.
In the JS file is can see the following variable declarations:
var $window = $(window);
var $intro = $('.intro');
var $mac = $('#mac');
var $h1 = $('h1');
My attempt
Looking at
var $window = $(window);
I can see the scroll is set on the window size. However I was thinking can't this be changed to a div. For example
var $window = $('#animationContent');
I would like this animation to work exactly as is just within a div placed on the page as opposed to being the first piece of content.
$(function() {
// cache all elements before we do anything
var $window = $(window);
var $intro = $('.intro');
var $mac = $('#mac');
var $h1 = $('h1');
// define variables and prefill
var offset = $mac.offset();
var windowHeight = $window.height();
var windowTop = $window.scrollTop();
var scrollPercent = (offset.top - windowTop) / offset.top;
var scale = 'scale(' + scrollPercent + ')';
// listen to scroll
$window.on('scroll', function() {
windowTop = $window.scrollTop();
// hide intro if point is reached
if (windowTop >= 940) {
$intro.hide();
} else {
if (windowTop < 200 && windowTop > 100) {
// only perform in a 100px range
$h1.fadeOut(500);
}
$intro.show();
scrollPercent = (offset.top - windowTop) / offset.top;
scale = 'scale(' + scrollPercent + ')';
$intro.css({
'transform': scale
});
}
});
});
#import url(https://fonts.googleapis.com/css?family=Open+Sans:400,700,800);
body {
color: #333;
font-family: Open sans;
}
h1 {
position: fixed;
top: 50%;
transform: translateY(-50%);
width: 100%;
text-align: center;
font-size: 52px;
z-index: 999;
color: rgba(255, 255, 255, 0.3);
}
.mac {
height: 613px;
width: 764px;
margin: 1340px auto 100px;
background: white url("https://i.imgur.com/AyELvGR.jpg") no-repeat 0 0;
background-size: 764px 613px;
backface-visibility: hidden;
}
.mac.intro {
position: fixed;
width: 2548px;
height: 2052px;
background-size: 100% auto;
margin: 0;
top: 0;
left: 50%;
margin-top: -300px;
margin-left: -1274px;
transform-origin: 50%;
}
.content {
width: 500px;
margin: 0 auto 150px;
}
.content h2 {
font-size: 52px;
line-height: 1.0865;
font-weight: 300;
margin-bottom: 48px;
}
.content p {
font-size: 18px;
margin: 1em 0 0 0;
line-height: 1.8;
color: #555;
font-weight: 400;
}
.content p a {
color: #555;
text-decoration: underline;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<h1>Just scroll!</h1>
<div class="intro mac"></div>
<div id="mac" class="mac"></div>
<div class="content">
<h2>Apple iMac scrolling effect.</h2>
<p>
iMac 27" mockup by Koy Carraway.<br/> Picture from WallWideHD - Transfagarasan.<br/> Read more about Transfagarasan <a href="http://en.wikipedia.org/wiki/Transf%C4%83g%C4%83r%C4%83%C8%99an"
target="_blank">here</a>.
</p>
</div>
Hey this is the plugin of Scrollmagic.io I am using this in my work.
But this is slow. How increase the duration time I want to change the content faster.
I looked at documentation but not much clear in docs.
Please help me out
//First the variables our app is going to use need to be declared
//References to DOM elements
var $window = $(window);
var $document = $(document);
//Only links that starts with #
var $navButtons = $("nav a").filter("[href^=#]");
var $navGoPrev = $(".go-prev");
var $navGoNext = $(".go-next");
var $slidesContainer = $(".slides-container");
var $slides = $(".slide");
var $currentSlide = $slides.first();
//Animating flag - is our app animating
var isAnimating = false;
//The height of the window
var pageHeight = $window.innerHeight();
//Key codes for up and down arrows on keyboard. We'll be using this to navigate change slides using the keyboard
var keyCodes = {
UP : 38,
DOWN: 40
}
//Going to the first slide
goToSlide($currentSlide);
/*
* Adding event listeners
* */
$window.on("resize", onResize).resize();
$window.on("mousewheel DOMMouseScroll", onMouseWheel);
$document.on("keydown", onKeyDown);
$navButtons.on("click", onNavButtonClick);
$navGoPrev.on("click", goToPrevSlide);
$navGoNext.on("click", goToNextSlide);
/*
* Internal functions
* */
/*
* When a button is clicked - first get the button href, and then slide to the container, if there's such a container
* */
function onNavButtonClick(event)
{
//The clicked button
var $button = $(this);
//The slide the button points to
var $slide = $($button.attr("href"));
//If the slide exists, we go to it
if($slide.length)
{
goToSlide($slide);
event.preventDefault();
}
}
/*
* Getting the pressed key. Only if it's up or down arrow, we go to prev or next slide and prevent default behaviour
* This way, if there's text input, the user is still able to fill it
* */
function onKeyDown(event)
{
var PRESSED_KEY = event.keyCode;
if(PRESSED_KEY == keyCodes.UP)
{
goToPrevSlide();
event.preventDefault();
}
else if(PRESSED_KEY == keyCodes.DOWN)
{
goToNextSlide();
event.preventDefault();
}
}
/*
* When user scrolls with the mouse, we have to change slides
* */
function onMouseWheel(event)
{
//Normalize event wheel delta
var delta = event.originalEvent.wheelDelta / 30 || -event.originalEvent.detail;
//If the user scrolled up, it goes to previous slide, otherwise - to next slide
if(delta < -1)
{
goToNextSlide();
}
else if(delta > 1)
{
goToPrevSlide();
}
event.preventDefault();
}
/*
* If there's a previous slide, slide to it
* */
function goToPrevSlide()
{
if($currentSlide.prev().length)
{
goToSlide($currentSlide.prev());
}
}
/*
* If there's a next slide, slide to it
* */
function goToNextSlide()
{
if($currentSlide.next().length)
{
goToSlide($currentSlide.next());
}
}
/*
* Actual transition between slides
* */
function goToSlide($slide)
{
//If the slides are not changing and there's such a slide
if(!isAnimating && $slide.length)
{
//setting animating flag to true
isAnimating = true;
$currentSlide = $slide;
//Sliding to current slide
TweenLite.to($slidesContainer, 1, {scrollTo: {y: pageHeight * $currentSlide.index() }, onComplete: onSlideChangeEnd, onCompleteScope: this});
//Animating menu items
TweenLite.to($navButtons.filter(".active"), 0.5, {className: "-=active"});
TweenLite.to($navButtons.filter("[href=#" + $currentSlide.attr("id") + "]"), 0.5, {className: "+=active"});
}
}
/*
* Once the sliding is finished, we need to restore "isAnimating" flag.
* You can also do other things in this function, such as changing page title
* */
function onSlideChangeEnd()
{
isAnimating = false;
}
/*
* When user resize it's browser we need to know the new height, so we can properly align the current slide
* */
function onResize(event)
{
//This will give us the new height of the window
var newPageHeight = $window.innerHeight();
/*
* If the new height is different from the old height ( the browser is resized vertically ), the slides are resized
* */
if(pageHeight !== newPageHeight)
{
pageHeight = newPageHeight;
//This can be done via CSS only, but fails into some old browsers, so I prefer to set height via JS
TweenLite.set([$slidesContainer, $slides], {height: pageHeight + "px"});
//The current slide should be always on the top
TweenLite.set($slidesContainer, {scrollTo: {y: pageHeight * $currentSlide.index() }});
}
}
body, div, p {
margin: 0;
padding: 0;
}
body {
font-family: "HelveticaNeue-Light", "Helvetica Neue Light", "Helvetica Neue", Helvetica, Arial, "Lucida Grande", sans-serif;
font-weight: 300;
letter-spacing: 0.0625em;
}
a {
text-decoration: none;
}
nav {
position: fixed;
top: 0;
left: 0;
width: 100%;
z-index: 100;
}
nav ul {
list-style: none;
text-align: center;
margin-top: 30px;
}
nav ul li {
display: inline-block;
margin-right: 20px;
}
nav ul li:last-child {
margin-right: 0;
}
#back-to-tutorial {
margin-left: 100px;
}
nav a {
position: relative;
top: 0;
padding: 10px 20px;
font-weight: normal;
font-size: 20px;
text-align: center;
border-radius: 4px;
background-color: #FFFFFF;
color: #83C78E;
-webkit-box-shadow: none;
-moz-box-shadow: none;
box-shadow: none;
}
nav a.active {
top: -4px;
background-color: #69C773;
color: #FFFFFF;
-webkit-box-shadow: 0 4px 0 0 #51a65f;
-moz-box-shadow: 0 4px 0 0 #51a65f;
box-shadow: 0 4px 0 0 #51a65f;
}
.slides-container {
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
overflow: hidden;
z-index: 10;
}
.slide {
position: relative;
width: 100%;
height: 100%;
overflow: hidden;
}
.slide .centered {
width: 60%;
margin: 200px auto 0;
}
.slide .centered h1 {
text-align: center;
}
.slide .centered p {
text-align: center;
margin-top: 20px;
font-size: 20px;
}
#slide-1 {
background-color: #FFFFFF;
}
#slide-2 {
background-color: #45959b;
}
#slide-3 {
background-color: #778899;
}
#slide-4 {
color: #FFFFFF;
background-color: #291F37;
}
.go-prev, .go-next {
cursor: pointer;
font-weight: bold;
text-decoration: underline;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<!-- Popper JS -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.3/umd/popper.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/modernizr/2.8.3/modernizr.min.js" type="text/javascript"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/1.11.6/TweenLite.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/1.11.6/plugins/CSSPlugin.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/1.11.6/plugins/ScrollToPlugin.min.js"></script>
<nav>
<ul>
<li>Slide 1</li>
<li>Slide 2</li>
<li>Slide 3</li>
<li>Slide 4</li>
</ul>
</nav>
<div class="slides-container">
<div class="slide" id="slide-1">
<div class="centered">
<h1>Fullscreen slides with GSAP</h1>
<p>Let's go to the <span class="go-next">next slide</span>.</p>
</div>
</div>
<div class="slide" id="slide-2">
<div class="centered">
<h1>It is so easy to navigate through slides</h1>
<p>You can go back to <span class="go-prev">previous slide</span> or go to the <span class="go-next">next slide</span>.</p>
</div>
</div>
<div class="slide" id="slide-3">
<div class="centered">
<h1>Use mouse wheel</h1>
<p>No, really. Try to scroll up and down with the mouse wheel to switch between slides.</p>
</div>
</div>
<div class="slide" id="slide-4">
<div class="centered">
<h1>... Or use keyboard arrows</h1>
<p>You go to previous and next slide, using up and down keyboard arrows.</p>
</div>
</div>
</div>
This is the link of scroll.io docs http://scrollmagic.io/docs/ScrollMagic.Scene.html#duration
How to apply this I bit confused please have a look
It's actually a TweenLite parameter: https://greensock.com/tweenlite
Change
TweenLite.to($slidesContainer, 1, {scrollTo: {y: pageHeight * $currentSlide.index() }, onComplete: onSlideChangeEnd, onCompleteScope: this});
To a lower value, e.g.:
TweenLite.to($slidesContainer, 0.2, {scrollTo: {y: pageHeight * $currentSlide.index() }, onComplete: onSlideChangeEnd, onCompleteScope: this});
If you take a look at KIOSK WEBSITE HERE they have the 'WE ARE OPEN" circular type in javascript (I know how to do that) but what I don't know is how to achieve that when scrolling. Like how does the text move when scrolling up or down. How do you get that in HTML/CSS/JS ?
View the code I worked on here https://codepen.io/noel_emmanuel/pen/WJxRZW
HTML:
<!--just a container used to position in the page-->
<div class="container">
<!--the holders/targets for the text, reuse as desired-->
<div class="circTxt" id="test"></div>
</div>
<!--I told you it was simple! :)-->
CSS:
body {
background: #111;
}
.container {
/*centers in the container*/
text-align: center;
}
div.circTxt {
/*allows for centering*/
display: inline-block;
/*adjust as needed*/
margin-bottom: 128px;
color: whitesmoke;
}
JS:
function circularText(txt, radius, classIndex) {
txt = txt.split(""),
classIndex = document.getElementsByClassName("circTxt")[classIndex];
var deg = 360 / txt.length,
origin = 0;
txt.forEach((ea) => {
ea = `<p style='height:${radius}px;position:absolute;transform:rotate(${origin}deg);transform-origin:0 100%'>${ea}</p>`;
classIndex.innerHTML += ea;
origin += deg;
});
}
circularText("WE ARE OPEN", 100, 0);
OPEN FOR SUGGESTIONS.
You could rotate this on a scroll event. This simply rotates the div depending on how far from the top of the page you have scrolled.
I added a height and width to the text, as well as positioned it fixed to see the effect.
function circularText(txt, radius, classIndex) {
txt = txt.split(""),
classIndex = document.getElementsByClassName("circTxt")[classIndex];
var deg = 360 / txt.length,
origin = 0;
txt.forEach((ea) => {
ea = `<p style='height:${radius}px;position:absolute;transform:rotate(${origin}deg);transform-origin:0 100%'>${ea}</p>`;
classIndex.innerHTML += ea;
origin += deg;
});
}
circularText("WE ARE OPEN", 100, 0);
$(document).ready(function(){
$(window).scroll(function(e){
rotateText();
});
function rotateText(){
var scrolled = $(window).scrollTop();
$('div.circTxt').css('transform','rotate('+scrolled+'deg)');
}
});
body {
background: #111;
}
.container {
/*centers in the container*/
text-align: center;
height: 4000px;
}
div.circTxt {
/*allows for centering*/
display: inline-block;
/*adjust as needed*/
margin-bottom: 128px;
color: whitesmoke;
position: fixed;
height: 200px;
width: 200px;
transform-origin: 0% 59%;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<!--just a container used to position in the page-->
<div class="container">
<!--the holders/targets for the text, reuse as desired-->
<div class="circTxt" id="test"></div>
</div>
<!--I told you it was simple! :)-->
So I have a set of elements called .project-slide, one after the other. Some of these will have the .colour-change class, IF they do have this class they will change the background colour of the .background element when they come into view. This is what I've got so far: https://codepen.io/neal_fletcher/pen/eGmmvJ
But I'm looking to achieve something like this: http://studio.institute/clients/nike/
Scroll through the page to see the background change. So in my case what I'd want is that when a .colour-change was coming into view it would slowly animate the opacity in of the .background element, then slowly animate the opacity out as I scroll past it (animating on scroll that is).
Any suggestions on how I could achieve that would be greatly appreciated!
HTML:
<div class="project-slide fullscreen">
SLIDE ONE
</div>
<div class="project-slide fullscreen">
SLIDE TWO
</div>
<div class="project-slide fullscreen colour-change" data-bg="#EA8D02">
SLIDE THREE
</div>
<div class="project-slide fullscreen">
SLIDE TWO
</div>
<div class="project-slide fullscreen colour-change" data-bg="#cccccc">
SLIDE THREE
</div>
</div>
jQuery:
$(window).on('scroll', function () {
$('.project-slide').each(function() {
if ($(window).scrollTop() >= $(this).offset().top - ($(window).height() / 2)) {
if($(this).hasClass('colour-change')) {
var bgCol = $(this).attr('data-bg');
$('.background').css('background-color', bgCol);
} else {
}
} else {
}
});
});
Set some data-gb-color with RGB values like 255,0,0…
Calculate the currently tracked element in-viewport-height.
than get the 0..1 value of the inViewport element height and use it as the Alpha channel for the RGB color:
/**
* inViewport jQuery plugin by Roko C.B.
* http://stackoverflow.com/a/26831113/383904
* Returns a callback function with an argument holding
* the current amount of px an element is visible in viewport
* (The min returned value is 0 (element outside of viewport)
*/
;
(function($, win) {
$.fn.inViewport = function(cb) {
return this.each(function(i, el) {
function visPx() {
var elH = $(el).outerHeight(),
H = $(win).height(),
r = el.getBoundingClientRect(),
t = r.top,
b = r.bottom;
return cb.call(el, Math.max(0, t > 0 ? Math.min(elH, H - t) : (b < H ? b : H)), H);
}
visPx();
$(win).on("resize scroll", visPx);
});
};
}(jQuery, window));
// OK. Let's do it
var $wrap = $(".background");
$("[data-bg-color]").inViewport(function(px, winH) {
var opacity = (px - winH) / winH + 1;
if (opacity <= 0) return; // Ignore if value is 0
$wrap.css({background: "rgba(" + this.dataset.bgColor + ", " + opacity + ")"});
});
/*QuickReset*/*{margin:0;box-sizing:border-box;}html,body{height:100%;font:14px/1.4 sans-serif;}
.project-slide {
height: 100vh;
display: flex;
align-items: center;
justify-content: center;
}
.project-slide h2 {
font-weight: 100;
font-size: 10vw;
}
<div class="project-slides-wrap background">
<div class="project-slide">
<h2>when in trouble...</h2>
</div>
<div class="project-slide" data-bg-color="0,200,255">
<h2>real trouble...</h2>
</div>
<div class="project-slide">
<h2>ask...</h2>
</div>
<div class="project-slide" data-bg-color="244,128,36">
<h2>stack<b>overflow</b></h2>
</div>
</div>
<script src="//code.jquery.com/jquery-3.1.0.js"></script>
Looks like that effect is using two fixed divs so if you need something simple like that you can do it like this:
But if you need something more complicated use #Roko's answer.
var fixed = $(".fixed");
var fixed2 = $(".fixed2");
$( window ).scroll(function() {
var top = $( window ).scrollTop();
var opacity = (top)/300;
if( opacity > 1 )
opacity = 1;
fixed.css("opacity",opacity);
if( fixed.css('opacity') == 1 ) {
top = 0;
opacity = (top += $( window ).scrollTop()-400)/300;
if( opacity > 1 )
opacity = 1;
fixed2.css("opacity",opacity);
}
});
.fixed{
display: block;
width: 100%;
height: 200px;
background: blue;
position: fixed;
top: 0px;
left: 0px;
color: #FFF;
padding: 0px;
margin: 0px;
opacity: 0;
}
.fixed2{
display: block;
width: 100%;
height: 200px;
background: red;
position: fixed;
top: 0px;
left: 0px;
color: #FFF;
padding: 0px;
margin: 0px;
opacity: 0;
}
.container{
display: inline-block;
width: 100%;
height: 2000px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="container">
Scroll me!!
</div>
<div class="fixed">
</div>
<div class="fixed2">
</div>