CSS Zoom interfering with jQuery scrollTop - javascript

I'm creating a Website that, on Mobile Browsers, zooms out, as it's a fixed width website. Instead of using the viewport meta tags I've taken to the following:
html, body {
zoom: 0.8;
}
This works great, but the problem is with my jQuery. I'm using simple jQuery code for a one-page website smooth scrolling, shown below:
/* Start Navigation */
jQuery('nav ul.menu li').click(function(e) {
if(!scrollingAnim) {
var page = jQuery(this).attr('data-page');
updateMenu(page);
scrollingAnim = true;
jQuery('html, body').stop().animate({
scrollTop: (jQuery(page).offset().top - 70)
}, 2000, 'swing', function() {
scrollingAnim = false;
});
}
e.preventDefault();
return false;
});
/* End Navigation */
This used to work fine, but for obvious reasons will not work with my zoom. I've tried multiplying it by the zoom level, but it doesn't work. Is there anything you'd suggest?

jQuery's .offset().top is changing with the change of the window scroll when you have CSS zoom involved...
Take a look at my answer here https://stackoverflow.com/a/21048208/1090395
Hope it helps

Faced with similar problem related to zoom and offset().Top. Tried to play with values in JS console and found this formula:
var scrollTopAnimateTo = ($(anchor).offset().top - $(".header").height()) * zoom + $(window).scrollTop() * (1 - zoom);
where zoom < 1.

Related

Scrolling is jittery in IE, Safari, OSX

I'm trying to do some basic parallax animation, but the movement is extremely jittery as soon as I test in IE or any OSX browser - not sure why!
http://willmurdoch.com/scrolltest/
$(window).scroll(function(){
$('.hero').each(function(){
if($(this).offset().top - $(window).scrollTop() > -$(window).height() && $(this).offset().top - $(window).scrollTop() < $(window).height()){
var myTranslate = Math.ceil($(window).scrollTop() - $(this).offset().top);
$(this).find('.heroSlides').css('-webkit-transform', 'translateY('+myTranslate/2+'px)');
$(this).find('.scrollWrap').css('-webkit-transform', 'translateY('+myTranslate/5+'px)');
}
});
});
I've tried locking scroll functions to only fire every 100ms and transition in between, adding hardware acceleration to every animated element, but nothing seems to do it! Any help would be appreciated!
One of the things that I've found that adds smoothness to my CSS transformations, is to add the CSS Transformations
https://www.w3schools.com/css/css3_transitions.asp
Another thing you can do is look at skrollr and how that project works. It does math based easing for its smooth scrolling.
EDIT
On the page you posted, try changing the following functions:
$(window).scroll(function(){
scrollLogic();
console.log($(window).scrollTop());
closeNav();
});
change to:
$(window).scroll(function(){
//scrollLogic();
console.log($(window).scrollTop());
closeNav();
});
var scrollInterval = setInterval(function() {
scrollLogic();
}, 1000/30);
Then change the myTranslate part of scrollLogic. Play with different values to make the change more/less gradual.

Positioning the top attribute of a element with jquery

I'm having an annoying issue trying to position the responsive navigation hamburger. I am using a plugin called responsive menu which creates the hamburger and uses absolute positioning.
I am trying to position the hamburger in the centre of the header at all times.
To achieve this I am using the following jQuery code.
However, the issue I have is when the hamburger is displayed and you scroll down the page and scroll back to the top of the page quickly. The hamburger does not position itself in the centre of the header. You need to scroll back down slightly for it to jump into place.
Any ideas how I can fix this please.. It's driving me crazy and I don't know jquery very well :(
Thank you for any advice in advance :)
Link to the site in question
$( window ).on("load resize scroll", function(e){
var headerHeight = $('nav').height()/2;
var iconHeight = $('#click-menu').height()/2;
var total = headerHeight - iconHeight;
if ($(window).scrollTop() >= 1) {
$('#click-menu').css('top', total);
}
else {
$('#click-menu').css('top', total);
}
});
It's hard for me to test and confirm this, but I believe the reason it's position is off when it hits the top is because the evaluation of $('nav').height()/2; happens immediately, but the header animates to size over 300 ms.
Although a bit hacky, I think you can solve the problem by adding a setTimeout
function setNavTop(){
var headerHeight = $('nav').height()/2;
var iconHeight = $('#click-menu').height()/2;
var total = headerHeight - iconHeight;
$('#click-menu').css('top', total);
}
$( window ).on("load resize scroll", function(e){
if ($(window).scrollTop() >= 1) {
setNavTop();
}
else {
setTimeout(setNavTop, 300); // wait for header to animate to size.
}
});
Since it has to delay for 300ms before adjusting the icon, its looks a bit glitchy. You can improve this by adding tweening the setTimeout. Not the most elegant, but it works
setNavTop();
setTimeout(setNavTop, 100);
setTimeout(setNavTop, 200);
setTimeout(setNavTop, 300);

jQuery: set if else statement to perform offset based on browser width

Finishing up a parallax, one page site and I've got a fixed nav, so I have to offset the various div's / sections on my page so they don't get cut off on top. Problem is performing this for different browser widths, since my fixed nav will be about half the height on mobile as it is on desktop.
Trying this jQuery out and it only seems to perform the else action, not the if. So the offset is too much on mobile. Here's what I'm currently using:
<script type="text/javascript">
jQuery(document).ready(function() {
jQuery('.main-navigation a[href^="http://example.com/#"]' ).click(function() {
if (jQuery(window).width() < 677) {
jQuery.scrollTo( this.hash, 1000, { easing:'swing', offset:-20 });
} else {
jQuery.scrollTo( this.hash, 1000, { easing:'swing', offset:-141 });
}
});
});
</script>
I think this will provide a more responsive solution:
$(document).ready(function() {
$.resizeContentHeight = function(){
$('#main-content').css("margin-top", $(".header-fixed").height());
}
$(window).load(function() {
$.resizeContentHeight();
});
$(window).resize(function() {
$.resizeContentHeight();
});
});
In this JSfiddle I calculate the height of the .header-fixed and apply that as a margin-top to the content below it (#main-content). I think this is what you are trying to achieve right? I have tested this and modified it to work across multiple browsers. Not sure if this will be relevant in a parallax site if you could provide examples of the HTML you are working with it would help. This will also adjust if the user changes the orientation of their device.
This could also be adapted to add or remove the height of the header to the anchor links.

Change scrollTop offset

I am using bootstrap 3 and have a fullscreen hero unit at the top of my page, below that is my navigation. I have some js which allows my navbar to stick to be fixed at the top after you scroll past the full screen hero. Also some js for my smooth scrolling links.
The problem is the offset is different before you scroll past the full screen hero and after. But it works fine when you are past the jumbotron. I have tried a bunch of different things but I can seem to get this to work exactly.
Check out the fiddle here.
Here is my js for the smooth scrolling links:
$(document).ready(function() {
// navigation click actions
$('.scroll-link').on('click', function(event){
event.preventDefault();
var sectionID = $(this).attr("data-id");
scrollToID('#' + sectionID, 750);
});
// scroll to top action
$('.scroll-top').on('click', function(event) {
event.preventDefault();
$('html, body').animate({scrollTop:0}, 1200);
});
// mobile nav toggle
$('#nav-toggle').on('click', function (event) {
event.preventDefault();
$('#main-nav').toggleClass("open");
});
});
// scroll function
function scrollToID(id, speed){
var offSet = 95;
var targetOffset = $(id).offset().top - offSet;
var mainNav = $('#main-nav');
$('html,body').animate({scrollTop:targetOffset}, speed);
if (mainNav.hasClass("open")) {
mainNav.css("height", "1px").removeClass("in").addClass("collapse");
mainNav.removeClass("open");
}
}
if (typeof console === "undefined") {
console = {
log: function() { }
};
}
By changing var offSet = 95; I am able to adjust the offset but what would be the best way to use 180 before the navbar sticks to the top but 95 when it does?
Also here is the js I am using for my navbar:
$(function () {
/* $(".navbar-fixed-top").css({"top":$(".jumbotron").height()});
$(window).resize(function (e) {
$(".navbar-fixed-top").css({"top":$(".jumbotron").height()});
});*/
$(document).on( 'scroll', function(){
console.log('scroll top : ' + $(window).scrollTop());
if($(window).scrollTop()>=$(".jumbotron").height())
{
$(".navbar").addClass("navbar-fixed-top");
}
if($(window).scrollTop()<$(".jumbotron").height())
{
$(".navbar").removeClass("navbar-fixed-top");
}
});
});
Are you open to angular.js? I have a directive i use for this. As seen here.
I'll grab the plunker link for you. you might find the code helpful.
Essentially you need to create a ghost dom element to take the place of the menu when you pull it to an new layout position.
EDIT: Here it is
I won't suggest grabbing angular just for this. But you can use the basis of the events and logic to build your own solution.
This here is creating an element and placing in its place
$scope.spacer = $element.after(
'<div class="spacer" style="height:' + $element[0].clientHeight + 'px"> </div>').next();
then this element is removed when the menu is back to its static position.
Inspect the dom and watch how it changes, this will probably help you see the events and changes that need to take place.
EDIT 2 SOLUTION:
HERE is the concepts applied to your JSFiddle
It's not the best solution but by adding margin: 0 0 -100px 0; to your .navbaryou lose the spacing issue.
Also you're getting 22 console errors because of missing images. I'm not saying that this is causing any major problems but you would be better off losing them.
The problem is that when you have not scrolled past the hero, navigation is still part of the layout and pushes content bellow it a little lower. When you scroll past (either manually or via a script) the hero, navigation is removed and fix positioned. That makes everything which was bellow to "jump up" exactly of the navigation height.
That means if portfolio was 1000px from the top, on click you say: go 1000px from top; but then porfolio moves 100px up (as explained above) meaning it is now 900px from the top while the window scrolled 1000px as you asked.
When you have scrolled past the hero, nothing changes its position.

Rendering glitch in Chrome

I've created a menu that moves to the current window position by scrolling. When I scroll up and down right after, sometimes a glitch appears on Chrome 30 with OS X 10.9 and Windows 7. After hovering, the anchor tag jumps to the right position (1 pixel up). Is there anything wrong with my code? Is this a known bug?
Check this JSFiddle Demo!
$(document).ready(function(){
$(window).scroll(function(){
var newTop = ($(window).scrollTop() + 40) +'px';
$('#menu').stop().animate({ top: newTop}, 500);
});
});
Edit: It's fixed in Chrome 31.
I'm fairly certain this is a rendering bug since:
Manually triggering a repaint causes the glitch to go away.
The glitch doesn't occur in other browsers I tested.
Fortunately, triggering a repaint is a fairly straight-forward workaround, albeit an annoying one:
I added a callback to the animation:
$('#menu').stop().animate({ top: newTop }, 500, function(){
$('#menu').css('overflow', 'hidden');
setTimeout(function(){
$('#menu').css('overflow', 'auto');
}, 10);
});
jsFiddle Demo
Unfortunately, it seems both the setting and unsetting of some property (here I chose overflow) was necessary. The 10 is a little sketchy, but when you're working around a browser rendering bug, I'm not sure you can do much better.
Best of luck!
I agree with Adam, this is definitely a rendering bug. If you animate the menu using the translate() transform-function instead, it does not happen.
There are other bonuses to using this method as well: http://www.paulirish.com/2012/why-moving-elements-with-translate-is-better-than-posabs-topleft/
jQuery core does not allow you to animate using translate() out of the box, but there is a plugin that enables this at http://ricostacruz.com/jquery.transit/ , or you can opt for using .css() and let css transitions do the heavy lifting.
Here is an example using the plugin:
var menu = $("#menu");
$(window).scroll(function(){
var newTop = $(window).scrollTop();
menu.stop().transit({ y: newTop +'px' }, 500);
});
Plugin demo at http://jsfiddle.net/Hb3jS/5/
Here is an example using CSS transitions:
js
var menu = $("#menu");
$(window).scroll(function(){
var newTop = $(window).scrollTop();
menu.css({ transform: 'translateY(' + newTop +'px)' });
});
css
#menu {
transition: all .5s;
}
CSS demo at http://jsfiddle.net/Hb3jS/6/

Categories

Resources