I was looking for an sticky footer and I found this
https://gist.github.com/robertvunabandi/b66dc9872f51c93af796094e08155731
It's pretty useful but the problem is when I refresh the page the footer appears on the top first and 1 second after it takes the right place at the bottom, it's there's way to avoid that? I mean when I refresh the page the footer appears at the bottom as it should be?
window.addEventListener("load", activateStickyFooter);
function activateStickyFooter() {
adjustFooterCssTopToSticky();
window.addEventListener("resize", adjustFooterCssTopToSticky);
}
function adjustFooterCssTopToSticky() {
const footer = document.querySelector("#footer");
const bounding_box = footer.getBoundingClientRect();
const footer_height = bounding_box.height;
const window_height = window.innerHeight;
const above_footer_height = bounding_box.top - getCssTopAttribute(footer);
if (above_footer_height + footer_height <= window_height) {
const new_footer_top = window_height - (above_footer_height + footer_height);
footer.style.top = new_footer_top + "px";
} else if (above_footer_height + footer_height > window_height) {
footer.style.top = null;
}
}
function getCssTopAttribute(htmlElement) {
const top_string = htmlElement.style.top;
if (top_string === null || top_string.length === 0) {
return 0;
}
const extracted_top_pixels = top_string.substring(0, top_string.length - 2);
return parseFloat(extracted_top_pixels);
}
I guess its not a good idea to manipulate DOM-elements with JS at the page load event. Better use CSS to do the trick:
How to make a sticky footer using CSS?
If you do it in CSS you shouldn't have this issue, plus it's very few lines of code, I made a quick mock-up as an example.
HTML:
<header>Header</header>
<main>Main</main>
<footer>Footer</footer>
CSS:
header {
background-color:blanchedalmond;
height: 10vh;
min-height: 60px;
}
main {
background-color:beige;
height: 70vh;
min-height: 800px;
}
footer {
background-color:blanchedalmond;
height: 20vh;
min-height: 200px;
position: -webkit-sticky;
position: sticky;
bottom: 0;
}
Related
const rightSide = document.querySelector("#rightSide");
let scrollPercentage = () => {
let h = document.documentElement;
let st = h.scrollTop || document.body.scrollTop;
let sh = h.scrollHeight || document.body.scrollHeight;
let percent = st / (sh - h.clientHeight) * 100;
console.log(percent);
}
rightSide.onscroll = scrollPercentage;
.right-side {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
height: 90%;
width: 90%;
background-color: #eee;
overflow-y: scroll;
}
.top-page {
width: 100%;
height: 100%;
background-color: red;
}
.bot-page {
width: 100%;
height: 100%;
background-color: yellow;
}
<div class="right-side" id="rightSide">
<div id="top-page" class="top-page"></div>
<div id="bot-page" class="bot-page"></div>
</div>
I'm making a website and I want to get the scroll percentage of a div. I've used Tyler Pott's video on YouTube https://youtu.be/-FJSedZAers and he does that to the whole page (using the body). And this is my code:
const rightSide = document.querySelector("#rightSide")
let scrollPercentage = () => {
let h = document.documentElement;
let st = h.scrollTop || document.body.scrollTop;
let sh = h.scrollHeight || document.body.scrollHeight;
let percent = st / (sh - h.clientHeight) * 100;
console.log(percent);
}
rightSide.onscroll = scrollPercentage;
When I run this, the console just outputs "NaN" which is to be expected. I am not sure what I should do in order to transfer that code onto the divs. I've tried to use things like
const topPage = document.querySelector("#top-page");
And then add topPage instead of the body in document.body.scrollTop etc. but that obviously doesn't work.
This is sort of what the HTML looks like, and the top page has a width and height of the rightSide div and the bottom page has the same width but a minimum height of the rightSide div.
<div class="right-side" id="rightSide">
<div id="top-page" class="top-page"></div>
<div id="bot-page" class="bot-page"></div>
</div>
Coming back to this I knew that I had to understand the values assigned to the variables in order to make the equation simpler.
So, a quick search for documentElement led me to this answer:
"documentElement returns the Element that is the root element of the document (for example, the element for HTML documents)"
Then, I realised that maybe that is the issue and it was. I assigned rightSide to h and that's all that was needed.
let h = rightSide;
Not sure if this is fully correct, sometimes at the end of the scroll you can get 100.05 or more, but I didn't need the precise number. Hope this helps.
I'm trying to create a Sprite animation using the following image:
To do so I am using it as a background and am trying to manipulate the background's position when animating. Somehow I can't get it working though - it shows the last frame from the very beginning.
Image: https://i.imgur.com/06vjVVj.png - 30800x1398 and 27 frames
Here's a codepen: https://codepen.io/magiix/pen/MWewdYo
#skull {
position: absolute;
border: 1px solid red;
width: 1140px;
height: 1398px;
background: url("https://i.imgur.com/06vjVVj.png") 1140px 0;
}
const animateSkull = () => {
const interval = 50;
let pos = 30800 / 27;
tID = setInterval(() => {
document.getElementById("skull").style.backgroundPosition = `-${pos}px 0`;
if (pos < 30800) {
pos = pos + 1140;
}
}, interval);
};
If you check (with a console for example), you'll see that your animateSkull function is never called, because your addEventListener does not work. Change it to the following so it will be called (but your animateSkull function has another bug (or maybe your css I didn't checked) so it's not fully working after that but you should be able to fix that easily):
document.addEventListener('DOMContentLoaded', () => {
animateSkull();
});
This should do the work, but the frames in your sprite don't have the same width. So the animation looks buggy. (that is one huge image just for the animation)
const animateSkull = () => {
const interval = 1000;
let pos = -1140;
tID = setInterval(() => {
if (pos > -30800) {
pos -= 1140;
}
document.getElementById("skull").style.backgroundPosition = `${pos}px 0`;
}, interval);
};
animateSkull();
#skull {
position: absolute;
border: 1px solid red;
width: 1140px;
height: 1398px;
background-image: url("https://i.imgur.com/06vjVVj.png");
background-position: -1140px 0;
background-size: cover;
}
</style>
<p id="skull"></p>
I want to link the background color of the body element to the scroll position such that when the page is scrolled all the way to the top its color 1, but then but then when its scrolled past screen.height, its a completely different color, but I want it to be interpolated such that when it is half-way scrolled, the color is only half-way transitioned. So far, I have it linked to
$(window).scrollTop() > screen.height
and
$(window).scrollTop() < screen.height
to add and remove a class that changes background-color but I want it to be dependent on scroll position not just to trigger the event, but rather smoothly animate it so fast scrolling transitions quickly, slow scrolling transitions it slowly.
One of possible solutions is to bind a rgb color to current height, count the step and set new rgb color depending on current position of scrolling. Here I've created the simplest case - black and white transition:
const step = 255 / $('#wrapper').height();
const multiplier = Math.round(
$('#wrapper').height() /
$('#wrapper').parent().height()
);
$('body').scroll(() => {
const currentStyle = $('body').css('backgroundColor');
const rgbValues = currentStyle.substring(
currentStyle.lastIndexOf("(") + 1,
currentStyle.lastIndexOf(")")
);
const scrolled = $('body').scrollTop();
const newValue = step * scrolled * multiplier;
$('#wrapper').css('background-color', `rgb(${newValue}, ${newValue}, ${newValue})`);
});
html,
body {
padding: 0;
margin: 0;
width: 100%;
height: 100%;
overflow-x: hidden;
background-color: rgb(0, 0, 0);
}
#wrapper {
height: 200%;
width: 100%;
overflow: hidden;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
<section id="wrapper"></section>
And here is another one example with transition from yellow to blue:
const step = 255 / $('#wrapper').height();
const multiplier = Math.round(
$('#wrapper').height() /
$('#wrapper').parent().height()
);
$('body').scroll(() => {
const currentStyle = $('body').css('backgroundColor');
const rgbValues = currentStyle.substring(
currentStyle.lastIndexOf("(") + 1,
currentStyle.lastIndexOf(")")
);
const scrolled = $('body').scrollTop();
const newValue = step * scrolled * multiplier;
$('#wrapper').css('background-color', `rgb(${255 - newValue}, ${255 - newValue}, ${newValue})`);
});
html,
body {
padding: 0;
margin: 0;
width: 100%;
height: 100%;
overflow-x: hidden;
background-color: rgb(255, 255, 0);
}
#wrapper {
height: 200%;
width: 100%;
overflow: hidden;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
<section id="wrapper"></section>
var randomHex = function () {
return (parseInt(Math.random()*16)).toString(16) || '0';
};
var randomColor = function () {
return '#'+randomHex()+randomHex()+randomHex();
};
var randomGradient = function () {
$('.longContent').css('background', 'linear-gradient(0.5turn, #222, '+randomColor()+','+randomColor()+')');
};
$(window).on('load', randomGradient);
body {
margin: 0;
}
.longContent {
height: 400vh;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/tween.js/17.2.0/Tween.min.js"></script>
<div class="longContent"></div>
A much, much easier way to accomplish what you're looking to do is by simply using a gradient as the background.
There is absolutely zero need for any JS here, which will only slow down the page.
body {
height: 600vh;
background: linear-gradient(#2E0854, #EE3B3B)
}
Is there a particular reason you want to do this with JS?
I've been trying to create a page with several before and after images (Using a slider to swap between the two).
However when I add the second piece of JavaScript code, it breaks the page. Even if I try to amend the (var) code to be unique from the previous script
In all honesty I don't quite understand what the JavaScript is doing which is why I'm probably unable to Google the solution. Any help would be appreciated, if you could try to explain in as much detail what I need to do and explain any specific terms that would help me develop further.
You can see all my code on the link (and below): http://codepen.io/sn0wm0nkey/pen/DakbA
var inkbox = document.getElementById("inked-painted");
var colorbox = document.getElementById("colored");
var fillerImage = document.getElementById("inked");
inkbox.addEventListener("mousemove",trackLocation,false);
inkbox.addEventListener("touchstart",trackLocation,false);
inkbox.addEventListener("touchmove",trackLocation,false);
function trackLocation(e)
{
var rect = inked.getBoundingClientRect();
var position = ((e.pageX - rect.left) / inked.offsetWidth)*100;
if (position <= 100) { colorbox.style.width = position+"%"; }
}
/* -----second JavaScript code---- */
var inkbox1 = document.getElementById("inked1-painted");
var colorbox1 = document.getElementById("colored1");
var fillerImage1 = document.getElementById("inked1");
inkbox1.addEventListener("mousemove",trackLocation,false);
inkbox1.addEventListener("touchstart",trackLocation,false);
inkbox1.addEventListener("touchmove",trackLocation,false);
function trackLocation(e1)
{
var rect1 = inked.getBoundingClientRect();
var position1 = ((e1.pageX - rect1.left) / inked1.offsetWidth)*100;
if (position1 <= 100) { colorbox1.style.width = position1+"%"; }
}
body { background: #113; }
div#inked-painted {
position: relative; font-size: 0;
-ms-touch-action: none;
-webkit-touch-callout: none;
-webkit-user-select: none;
}
div#inked-painted img {
width: 100%; height: auto;
}
div#colored {
background-image: url(https://s3-us-west-2.amazonaws.com/s.cdpn.io/4273/colored-panel.jpg);
position: absolute;
top: 0; left: 0; height: 100%;
width: 50%;
background-size: cover;
}
div#inked-painted:hover {
cursor: col-resize;
}
/*-------- second css sheet --------- */
div#inked1-painted {
position: relative; font-size: 0;
-ms-touch-action: none;
-webkit-touch-callout: none;
-webkit-user-select: none;
}
div#inked1-painted img {
width: 100%; height: auto;
}
div#colored1 {
position: absolute;
top: 0;
left: 0;
height: 100%;
width: 50%;
background-size: cover;
background-image: url(https://s3-us-west-2.amazonaws.com/s.cdpn.io/4273/colored-panel.jpg);
}
div#inked1-painted:hover {
cursor: col-resize;
}
<Div>
<div id="inked-painted">
<img src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/4273/inked-panel.png" id="inked" alt>
<div id="colored"></div>
</div>
<p></p>
<div>
<div id="inked1-painted">
<img src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/4273/inked-panel.png" id="inked1" alt>
<div id="colored1"></div>
</div>
Howard's solution works but can be improved even more to remove duplication.
Use classes instead of Ids
Find the elements inside the div that is receiving the mousemove instead of passing them in
Don't duplicate the CSS
function onMouseMove(e) {
var inked = this.getElementsByTagName("img")[0];
var colorbox = this.querySelector('.colored');
var rect = inked.getBoundingClientRect();
var position = ((e.pageX - rect.left) / inked.offsetWidth) * 100;
if (position <= 100) {
colorbox.style.width = position + "%";
}
}
function trackLocation(el) {
el.addEventListener("mousemove", onMouseMove, false);
el.addEventListener("touchstart", onMouseMove, false);
el.addEventListener("touchmove", onMouseMove, false);
}
var wrappers = document.querySelectorAll('.inked-painted');
for (var i = 0; i < wrappers.length; i++) {
trackLocation(wrappers[i]);
}
div.inked-painted {
position: relative;
font-size: 0;
-ms-touch-action: none;
-webkit-touch-callout: none;
-webkit-user-select: none;
}
div.inked-painted img {
width: 100%;
height: auto;
}
.colored {
background-image: url(https://s3-us-west-2.amazonaws.com/s.cdpn.io/4273/colored-panel.jpg);
position: absolute;
top: 0;
left: 0;
height: 100%;
width: 50%;
background-size: cover;
}
div.inked-painted:hover {
cursor: col-resize;
}
<div class="inked-painted">
<img src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/4273/inked-panel.png" />
<div class="colored"></div>
</div>
<p></p>
<div class="inked-painted">
<img src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/4273/inked-panel.png" />
<div class="colored"></div>
</div>
First, Java != JavaScript. They are two very different languages.
Second, your issue is that your second function is named the same as your first function. The second one essentially overwrites the first one, so the first doesn't exist any longer. Simply use a different name for your second function, and your code works just fine.
However, it would be better to find a way to reuse your first function, instead of having two almost identical functions.
Here is what you are doing with your JavaScript how it is currently written.
Declare and assign variables inkbox, colorbox, fillerImage
Add event handlers
Create a function in the global scope by the name of trackLocation
Declare and assign variables inkbox1, colorbox1, fillerImage1
Add event handlers
Overwrite the trackLocation function in the global scope
All of this is being done synchronously, just as I have it listed here. So, when an event fires on inkbox, it calls the new function that overwrote the original.
Another problem that I see (unless you omitted some code) is you have some variables that are not defined, which will cause a problem within your function.
function trackLocation (e) {
// inked is undefined
var rect = inked.getBoundingClientRect();
// inked is undefined
var position = ((e.pageX - rect.left) / inked.offsetWidth)*100;
if (position <= 100) { colorbox.style.width = position+"%"; }
}
You'll need to rewrite your function to accept local variables like this:
function trackLocation (e, inked, colorbox) {
var rect = inked.getBoundingClientRect();
var position = ((e.pageX - rect.left) / inked.offsetWidth)*100;
if (position <= 100) { colorbox.style.width = position+"%"; }
}
Now this one function can be reused in all of your event handlers, like this:
function trackLocation (e, inked, colorbox) {
var rect = inked.getBoundingClientRect();
var position = ((e.pageX - rect.left) / inked.offsetWidth)*100;
if (position <= 100) { colorbox.style.width = position+"%"; }
}
var inkbox = document.getElementById("inked-painted");
var colorbox = document.getElementById("colored");
var fillerImage = document.getElementById("inked");
inkbox.addEventListener("mousemove", function (e) { trackLocation(e, inkbox, colorbox); });
inkbox.addEventListener("touchstart", function (e) { trackLocation(e, inkbox, colorbox); });
inkbox.addEventListener("touchmove", function (e) { trackLocation(e, inkbox, colorbox); });
var inkbox1 = document.getElementById("inked1-painted");
var colorbox1 = document.getElementById("colored1");
var fillerImage1 = document.getElementById("inked1");
inkbox1.addEventListener("mousemove", function (e) { trackLocation(e, inkbox1, colorbox1); });
inkbox1.addEventListener("touchstart", function (e) { trackLocation(e, inkbox1, colorbox1); });
inkbox1.addEventListener("touchmove", function (e) { trackLocation(e, inkbox1, colorbox1); });
I have created this fiddle where I have flicking problem in IE. Even Chrome isnt good, but in fiddle it looks more or less fine. I think problem is in "size of step" for one scroll, when you grab scroller manualy everything is smooth, but using your mousewheel leads to jumping/flicking in IE and Chrome.
window.addEventListener('scroll', function() { ...}, false);
This is my current HTML:
<div id="fakeBody">
<div id="spacer">scroll down</div>
<div class="niceBanner hide roller" id="niceBannerFrame">
<div id="bannerShadow"></div>
<div id="thumb0">
<div id="niceBannerOriginal" class="roller thumb1 thumb2"></div>
<div id="niceBannerBlur" class="roller deblur thumb1 thumb2"></div>
<div id="blackRow"></div>
</div>
</div>
</div>
Script:
window.addEventListener('scroll', function () {
var totalHeigth, currentScroll, visibleHeight;
var newResolutionBannerHeight = 0;
currentScroll = (document.documentElement.scrollTop) ? document.documentElement.scrollTop : document.body.scrollTop;
totalHeigth = (document.height !== undefined) ? document.height : document.getElementById("fakeBody").offsetHeight;
visibleHeight = document.documentElement.clientHeight;
var w = window,
d = document,
e = d.documentElement,
g = d.getElementsByTagName('body')[0],
x = w.innerWidth || e.clientWidth || g.clientWidth,
y = w.innerHeight || e.clientHeight || g.clientHeight;
var curentWidth = x;
console.log('curent Width: ' + curentWidth);
if (curentWidth < 1070) {
var newBannerWidth = Math.round((curentWidth / 1070) * 1920);
var newMargin = Math.round((newBannerWidth - curentWidth) / 2);
newResolutionBannerHeight = Math.round((500 / 1920) * newBannerWidth);
} else {}
//now it is easy to recognize if visitor is at the bottom of page
if (visibleHeight + currentScroll >= totalHeigth) {
//do the magic with banner
document.getElementById("niceBannerFrame").className = "unhide";
var bannerHeight = visibleHeight + currentScroll - totalHeigth;
var style = document.createElement('style');
style.type = 'text/css';
var number = (curentWidth < 500) ? 10 + bannerHeight : 50 + bannerHeight; //not ideal solution, slower rolling for small screen, picture is realy small
if (curentWidth > 1070) {
number = (number > 500) ? 500 : number;
var opacityBlur = 1 - (number / 500);
style.innerHTML = '.roller {bottom:-' + number + 'px;} .deblur {opacity:' + opacityBlur + ';} .thumb2{height: 500px;} ';
} else {
number = (number > newResolutionBannerHeight) ? newResolutionBannerHeight : number;
var opacityBlur = 1 - (number / newResolutionBannerHeight);
style.innerHTML = '.roller {bottom:-' + number + 'px;} .deblur {opacity:' + opacityBlur + ';} .thumb2{height:' + newResolutionBannerHeight + 'px;} ';
}
document.head.appendChild(style);
} else {
//it is not good time for magic, scroll a bit more or I will hide already visible bilboard
document.getElementById("niceBannerFrame").className = "hide";
}
}, false);
and CSS:
#spacer {
height: 1000px;
background-color: whitesmoke;
}
#niceBannerOriginal {
background-image:url(http://nzworker.com/jakub-portfolio/justfiles/1920x500_original.jpg);
position: absolute;
z-index:-3;
}
#niceBannerBlur {
background-image:url(http://nzworker.com/jakub-portfolio/justfiles/1920x500_blur.jpg);
position: absolute;
z-index:-2;
}
#bannerShadow {
position:absolute;
background-image:url(http://nzworker.com/jakub-portfolio/justfiles/Stin.png);
background-repeat:repeat-x;
width:100%;
z-index:-1;
height:25px;
}
.hide {
display: none;
}
.unhide {
display: block;
}
#fakeBody {
height:1000px;
position:relative;
top:0;
left:0;
right:0;
}
#blackRow {
display:none;
}
#niceBannerFrame {
overflow: hidden;
}
#media (min-width: 1921px) {
#blackRow {
background-color: #000000;
display: block;
height:500px;
position: absolute;
width: 100%;
z-index: -6;
}
}
/*desktop resolution*/
#media (min-width: 1070px) and (max-width: 1920px) {
.thumb1 {
width: 100%;
height: 500px;
background-position: 50% 50%;
/*image centering*/
}
.thumb2 {
}
}
/*mobile and tablet resolution*/
#media (max-width: 1069px) {
.thumb2 {
width: 100%;
height: 500px;
background-repeat:no-repeat;
/*background-position: 50% 50%; image centering*/
}
#niceBannerOriginal {
background-image:url(http://nzworker.com/jakub-portfolio/justfiles/1920x500_original-thumb.jpg);
background-size: 100%;
}
#niceBannerBlur {
background-image:url(http://nzworker.com/jakub-portfolio/justfiles/1920x500_blur-thumb.jpg);
background-size: 100%;
}
}
My question is do you how to remove this flicking? Or do you know how to cut one mouse wheel step to more smaller ones?
PS: I can not use jQuery or other plugins.
I can't be 100% sure about this, but I think the flickering isn't from the amount you're scrolling, but due to the fact that you're changing the display mode, and pushing the view back up a tiny bit.
Essentially if you are just underneath the visibleHeight+currentScroll >= totalHeigth test by a couple of pixels, then currentScroll get's pushed up a tiny bit when whatever happens in there happens (I don't entirely understand what's going on, so I can't really give any better advice on that), so that it's no longer greater than totalHigth, and so it then fails the test immediately after, hence the flickering.
Worked this out by getting rid of the hide line at the end and it seems to work. Unfortunately I don't entirely understand the code, so I can't give you any better idea than that, though hopefully it points you towards a solution.