I would like to achieve the following:
On a mobile device, when someone starts scrolling from the top, a text starts to shrink down, and after a given amount, it takes its final size and stays like so for the rest of the page. The idea is that I have a Company name in the middle of the screen, and on scroll, it shrinks to the top left corner of the screen, and a menu bar appears behind it, and the Company name becomes the logo on the menu bar. The menu bar's background is the Hero image of the page. Here is my code:
window.onscroll = scrolled
function scrolled(){
let fromTop = window.scrollY
if (fromTop < 300) {
heroText.style.fontSize = `${2 - fromTop/160}em`
hero.classList.remove('hero-fixed')
heroNav.classList.remove('hero-nav-fixed')
heroText.classList.remove('h1-fixed')
heroImg.classList.remove('hero-img-fixed')
} else {
hero.classList.add('hero-fixed')
heroNav.classList.add('hero-nav-fixed')
heroText.classList.add('h1-fixed')
heroImg.classList.add('hero-img-fixed')
}
if (fromTop > 360) {
heroNav.classList.add('nav-mobile', 'hidden')
intro.classList.add('intro-fixed')
hamburger.classList.remove('hidden')
} else {
hamburger.classList.add('hidden')
heroNav.classList.remove('nav-mobile','hidden')
intro.classList.remove('intro-fixed')
}
}
}
It works, but I have to adjust for every screen size I want to support, and it is extremely laggy! It is probably a very wrong way to do it, so could someone help me make it more efficient and less laggy on mobile devices?
My guess is that the constant resizing of the text is one of the problems, as well as the height change of the hero image. I play with position fixed, and padding-top changes in the CSS to compensate the disappearing (becoming fixed positioned) elements.
Could some library, like RxJS help, or is there a VanillaJS elegant solution as well?
To make this more efficient in the Javascript side, you could use something like lodash's debounce.
Changing layout can be a very resource intensive operation so you might want to try leaving the element fixed position all the time and only adjusting its size (and/or the size of its parents) with the CSS transform property. scale() would work quite nicely here.
Related
I have this following demo website: http://woohooo.fortleet.com/
Pieces of content as well as navigation are set to 100% height. When I'm on my phone, there's this url bar up top that hides when I scroll up. However, this effect messes the 100% height up because it adjusts to the new browser size, creating an unpleasing effect. The same goes for 'vh' and 'vw' units.
I've tried the following:
function windowDimensions() {
if (html.hasClass('touch')) {
height = window.screen.height;
width = window.screen.width;
} else {
height = win.height();
width = win.width();
}
}
function screenFix() {
if (html.hasClass('touch')) {
touch = true;
nav.css({'height' : height + 'px'});
home.css({'height' : height + 'px'});
header.css({'height' : height/2 + 'px'});
content.css({'min-height' : height + 'px'});
}
}
This, however, creates a problem, because at the VERY TOP there's this bar with battery, wifi, signal info that is also accounted to the screen height, making the '100%' and 'vh' elements a tad bigger.
I couldn't believe I didn't find any other question about this, as I assumed this is a pretty common problem for 100%/100% sites.
Do you guys know any fix for this?
Your viewport meta tag seems fine. 100vh will not take into account the menu/wifi/top bar. It will only provide the viewport height, which does not account for the menubar on phones. It's important to note that 100vh, and 100% are not going to be the same height. I took a look at your site in mobile and on desktop, each section appears to be 100vh without any additional padding (so it looks correct to me).
If you are referring to the "iPhone" URL bar that automatically toggles in and out when scrolling, then you won't have any way to hide or toggle that display. The URL bar shows up when you scroll up... so yes... it may mean that you will have 20px or so that will not be visible when the user is scrolling upwards. However, it's usually not a problem, because when you are scrolling downwards IOS hides that bar... as to not affect the view of the screen. This may not answer your question, but the URL bar is what I assumed you meant.
It sounds as if your viewport isn't properly set. I'm pretty sure it should not take that extra 10 - 20 pixels into account.
If you haven't already, try setting the view port meta and disabling all zooming options. Hope this helps :)
Ref: https://developer.mozilla.org/en/docs/Mozilla/Mobile/Viewport_meta_tag
I have seen some scrolling effects for example on Google SketchUp's site, their banner is initially "built into the page" and then it seems to pop out and remain stuck at the top after a certain position down (scrolling).
Google Plus seems to have some special effects as well, like changing the banner entirely once the scrolling has reached a certain position.
Attached is what I am trying to accomplish. A square logo is on the right, and then when the page is scrolled down, the logo starts to scale to the same height as the banner/header / fade and then becomes a word rather than the image.
What am I looking at here? jQuery or javascript? How do I track the scrolling and connect the two?
Is it what you want to achieve?
http://jsfiddle.net/agdbd8x6/15/
If so, it is quite easy. If you use jQuery, attach 'scroll' event handler and check current scroll position. Show the image only with zero scroll position:
var img = $('#image');
var txt = $('#text');
$(".container").scroll(function(){
txt.text('Scroll position = ' + $(this).scrollTop());
var showImage = $(this).scrollTop() == 0;
if (showImage){
img.css('display', 'inline');
txt.hide();
}
else{
img.hide();
txt.css('display', 'inline-block');
}
});
I am looking to create a scrolling effect similar to that shown here: http://www.seaham-hall.co.uk/
However I am unable to achieve the desired effect, and inspecting the sites code gives me no hints. Quite difficult to google for as it is also quite difficult to describe. The closest I can get to finding a solution is this JSFiddle:
http://jsfiddle.net/xtyus/1/
(function($){
/* Store the original positions */
var d1 = $('.one');
var d1orgtop = d1.position().top;
var d2 = $('.two');
var d2orgtop = d2.position().top;
var d3 = $('.three');
var d3orgtop = d3.position().top;
var d4 = $('.four');
var d4orgtop = d4.position().top;
/* respond to the scroll event */
$(window).scroll(function(){
/* get the current scroll position */
var st = $(window).scrollTop();
/* change classes based on section positions */
if (st >= d1orgtop) {
d1.addClass('latched');
} else {
d1.removeClass('latched');
}
if (st >= d2orgtop) {
d2.addClass('latched');
} else {
d2.removeClass('latched');
}
if (st >= d3orgtop) {
d3.addClass('latched');
} else {
d3.removeClass('latched');
}
if (st >= d4orgtop) {
d4.addClass('latched');
} else {
d4.removeClass('latched');
}
});
})(window.jQuery);
However I am not sure that is going in the right direction, this pulls images up and covers the previous image, but notice on the Seaham Hall site the images don't appear to move up at all, they are stationary and become revealed as you scroll.
How do I recreate this effect? My initial thought was to have the first image shrink as you scroll from 1000px down to 0px, and the second image grow to 1000px, and as you continue to scroll this image then shrinks and the third grows, and so on. However this means that after the first image all the other images have a starting size of 0px and there would technically be no scrolling on the page to begin with, so that is an issue.
My second thought is that perhaps the second image is fixed to the page, the first image slides up revealing the second as you scroll, the second image would not appear to move. Once the first image has gone off the top of the page the second image is detached from the page and allowed to move up with scrolling, while the third image is attached and revealed as the second moves up, this would give the exact effect seen in the Seaham website but I have no clue of it is the correct answer.
If anyone can point me to tutorials or a JSFiddle with a basic concept I can probably figure it out from there. Just stumped what direction to approach this from.
That's a nice effect. Here's one way to do it.
Put each image in a fixed position div, which takes up the entire viewport (initially) and has overflow:hidden.
Set each div's z-index to be higher than the next div's.
As the window scrolls, adjust the height of the divs as a function of the window height times the div's position (index) in the DOM, minus the window's scrollTop:
$(window).scroll(function() {
$('.D').each(function(index) {
$(this).css({
height: $(window).height()*(index+1) - $(window).scrollTop()
});
});
});
Additional content will need a higher z-index than the image divs. And note that z-index works with positioned elements only.
Fiddle
Your desired effect isn't technically a parallax background, but it's close enough that parallax jQuery frameworks should work for you.
I would suggest you research jQuery Parallax plugins as they'll likely provide the functionality you'd like without much custom work. Of course since you're dealing with large images it's also best to keep an eye on the resource management; a good plugin should be fairly efficient but others may be slow or resource intensive.
Check this jquery plugin:ScrollMagic
usage: taken from github
The basic ScrollMagic design pattern is one controller, which has several scenes attached.
Each scene has a definite start and end position and defines what happens when the container is scrolled to the specific offset.
/*
Basic workflow example
*/
// init controller
var controller = new ScrollMagic();
// assign handler "scene" and add it to controller
var scene = new ScrollScene({duration: 100})
.setPin("#my-sticky-element") // pins the element for a scroll distance of 100px
.addTo(controller); // add scene to controller
// adding multiple scenes at once
var scene2 = new ScrollScene();
var scene3;
controller.addScene([
scene2,
scene3 = new ScrollScene({duration: 200}), // add scene and assign handler "scene2"
new ScrollScene({offset: 20}) // add anonymous scene
]);
I have been looking into parallax effects for vertical scrolling on my web page, and after some research, I'm not sure that what I want to do is technically a parallax effect.
From what I've seen, most parallax effects assume you want to be able to scroll indefinitely with many background images rolling by, or with huge images that repeat.
What I want to do is have the background of two DIVs be filled with a background image as the scroll bar reaches the bottom of the page. Note that I do not want the background images to stretch. I'm assuming to get the effect I want that these images would have a vertical height bigger than most people's viewport, and then their vertical position would change. When the user's scrollbar is at the top, a certain amount of the background is visible, and then it moves vertically to fill the background space as the user scrolls down.
Please see the image below for a visual explanation of the effect I hope to acheive:
The height of the veiwport will vary depending on the length of content inside the inner DIV.
My trouble is that if what I am trying to do is not exactly a parallax effect, then I don't know what else to call it, and my attempts to search by describing it keep landing me back at pages offering tutorials on parallax effects. So I've been stumped by a lack of terminology.
If someone could direct me to how I can control the vertical position of the background depending on the scrollbar position, that would be much appreciated. If this can be done with just CSS that would be great, but I'm assuming some Javascript would be required. A jQuery solution would also work for me.
Update:
After searching using the terms provided in comments, I've got the background image in the outer DIV to almost do what I want with the following code:
$(window).scroll(function () {
var yPos = $("#outerDiv").height() - ($("#outerDIV").height() * ($(window).scrollTop() / $(window).height()));
document.getElementById('outerDIV').style.backgroundPosition="0px " + yPos + "px";
});
It moves the background image in the right direction relative to the scrolling, but what it lacks is constraining that motion to within the viewport. Getting the right proportions based on the viewport and DIV sizes is proving to be just a little beyond my mathematical abilities.
For your requirement, you have to use a jquery parallax plugin to guide this activity, my best suggest it to use a Superscollorama and play with the elements as your wish...
As far as your question, Try this example,
controller.addTween(
'#examples-background',
(new TimelineLite())
.append([
TweenMax.fromTo($('#parallax-it-left'), 1,
{css:{backgroundPosition:"(0 -54px)"}, immediateRender:true},
{css:{backgroundPosition:"(0 -54px)"}}),
TweenMax.fromTo($('#parallax-it-right'), 1,
{css:{backgroundPosition:"(0 -54px)"}, immediateRender:true},
{css:{backgroundPosition:"(0 54px)"}})
]),
1000 // scroll duration of tween
);
You serial vice change as far as your wish...
Try practice this plugin, hope that works for you...
http://johnpolacek.github.io/superscrollorama/
Thanks...
Turns out what I want to acheive is possible with no special plugins, just some carefully thought out math. I did use a little jQuery syntax, but I don't think it's strictly necessary.
The code below has copious notes, so hopefully it's largely explanatory. In summary, you just need to find the position of the background image when the scroll would be at the top, and the position it would be if the scroll bar was at the bottom, and then you can use the percentage of the scrollbar's movement to work out where you are between those two points. It's a little tricker than just that, of course, in that you have to account for the difference between the total height of the scroll bar and where your DIV appears on the page and a few other adjustments, but the details of what I did are below.
What I've done here is just for the "outer DIV" that I described in my question. To get a background to move like the "inner DIV" I described, you'd have to modify the code, presumeably by reversing a few parameters. I haven't done that yet, but it seems like a straightforward task.
Hope others find this code useful. If anyone has suggestions on how it can be made more efficient or better, please let me know.
function moveBG(){
// imageHeight is not the total height of the image,
// it's the vertical amount you want to ensure remains visible no matter what.
var imageHeight = 300;
// Get the maximum amount within the DIV that the BG can move vertically.
var maxYPos = $("#outerDIV").height() - imageHeight;
// Get the amount of vertical distance from the top of the document to
// to the top of the DIV.
var headerHeight = document.getElementById("outerDIV").offsetTop;
// Calculate the BG Y position for when the scrollbar is at the very top.
var bgTopPos = $(window).height() - headerHeight - imageHeight;
// I don't want the image to wander outside of the DIV, so ensure it never
// goes below zero.
if (bgTopPos < 0)
{
bgTopPos = 0;
}
// Calculate the BG Y position when the scrollbar is at the very top.
var bgBottomPos = $(document).height() - $(window).height() - headerHeight;
// To prevent the BG image from getting cut off at the top, make sure
// its position never exceeds the maximum distance from the top of the DIV.
if (bgBottomPos > maxYPos)
{
bgBottomPos = maxYPos;
}
// Subtract the top position from the bottom, and you have the spread
// the BG will travel.
var totalYSpan = bgBottomPos - bgTopPos;
// Get the scrollbar position as a "percentage". Note I simply left it as a
// value between 0 and 1 instead of converting to a "true" percentage between
// 0 and 100, 'cause we don't need that in this situation.
var scrollPercent = ($(window).scrollTop() / ( $(document).height() - $(window).height()));
// The percentage of spread is added to the top position, and voila!
// You have your Y position for the BG image.
var bgYPos = bgTopPos + (Math.round(totalYSpan * scrollPercent));
// Apply it to the DIV.
document.getElementById('outerDIV').style.backgroundPosition="0px " + bgYPos + "px";
}
// Place the BG image correctly when opening the page.
$(document).ready(function() {
moveBG();
});
// Make it update when the scrollbar moves.
$(window).scroll(function () {
moveBG();
});
I have a content slideshow:
slide container
|--> wrapper
|------> slide1, slide2, etc.
that works as simple as calculating wrapper's position X and slide's position X to determine where to slide the wrapper for the next/previous slide to show up within container's viewport. It's pretty straight forward.
For Firefox and Chrome I am using CSS3 transform and transition-duration to animate the slides. Everything works perfect. Almost.
The problem is only when I click next button very fast. I am using jQuery's
$(selector).position().left
to read the slide's position X (left) and position becomes 0 (instead of expected, say, 300px). I do have a flag isAnimating to prevent users from going too fast but that does not help either. It does prevent from scrolling content too fast but position left may still be 0 as if something else is causing it to fail to determine.
I did a brief search and discovered that if it was image being loaded, some browsers would fail to determine its position until loading is over. However, each slide has an image but inside of it. The slide's CSS seems to have all widths and margins set fine.
The question is why may this be happening based on the scenario I described and possibly what can be improved to determine position X at all times for Firefox, Chrome browsers?
I've decided that if offsetLeft is not reliable for me at all times, I could use width of an element and its index position within container to figure out position X
var newWrapperPos = undefined;
$(lotWrapper).children('div').each(function(index){
if($(this).attr("id") === "slot"+id){
var width = $(this).width();
newWrapperPos = index * width;
return false;
}
});
//now I can shift wrapper to position = newWrapperPos
Sorry I couldn't share the code - it is a bit time consuming to rip off all pieces of functionality involved. But if somebody has a better answer, let me know. For now this works fine for me.