First off, I'd like to say that I'm sorry if this is an easy question. I'm fairly new to the HTML/CSS scene, and haven't even arrived at the Javascript one yet.
Here's my problem. I have a website I'm trying to build for my uncle, which you can see here. (it's still deep in pre-alpha stage, so the links don't work). It works fine as a local file, but as soon as I host it, my 'sticky' header starts to stick too soon, if at all. Reloading the page works about 1 time in 10.
I may or may not have isolated the cause of the problem: my placeholder. My sticky code itself works fine most of the time, except for one thing: as the sticky bar docks, it becomes fixed and the text jumps up 90-odd pixels. To combat this, I added lines 6 and 7 to my code below:
var sticky = document.querySelector('.sticky');
var origOffsetY = sticky.offsetTop;
function onScroll(e) {
window.scrollY >= origOffsetY ? sticky.classList.add('fixed') :
sticky.classList.remove('fixed');
window.scrollY >= origOffsetY ? jQuery('.content').css("paddingTop", "88.8125px"):
jQuery('.content').css("paddingTop", "0px");
}
document.addEventListener('scroll', onScroll);
It basically sticks a placeholder in there to stop that jump. It works fine, except now it's broken my code. I have experimented a bit and discovered that the placeholder seems to load randomly, and the header just goes weird. That's the best I can do.
It seems to be the placeholder code breaking it, as without the code it seems to work fine, perhaps after a couple of reloads. However, I am completely stumped. Has anyone got any idea how to fix it?
(Tested in Chrome 64 bit and 32 bit, as well as Chrome for Android, although that's glitchy on another level. Works fine as a local page, but not when hosted.)
It seems that the these code is executed too early that the image is not loaded yet, you can use chrome dev tool to add a pause to break to var origOffsetY = sticky.offsetTop;.
Then you can see 2 cases: 22 or 642
You can further inspect that the image, which should be the banner, is not completed when 22 condition is met, and if you use document.querySelector('.splash img') to get it and check its height, you'll see 0. While in the 642 case, you'll get 500.
The difference may be sometimes the image come from cache, sometimes it load from internet, so it may or may not able to decide the height when your script is executed.
So we have to make sure the image which is in the .splash is already loaded:
<script>
// Wrap the logic to a function for call.
var stickFunction = function() {
var sticky = document.querySelector('.sticky');
var origOffsetY = sticky.offsetTop;
function onScroll(e) {
window.scrollY >= origOffsetY ? sticky.classList.add('fixed') :
sticky.classList.remove('fixed');
window.scrollY >= origOffsetY ? jQuery('.content').css("paddingTop", "88.8125px"):
jQuery('.content').css("paddingTop", "0px");
}
document.addEventListener('scroll', onScroll);
}
// Get the image element
var splashImage = document.querySelector('.splash img');
// Check if image is complete or not.
if (splashImage.complete) { // If completed, do the logic.
stickFunction();
} else { // If not, tell the image to call the function for you when it is loaded.
splashImage.onload = stickFunction;
}
</script>
Related
I'm having trouble with an animated scrollbar. The intended behaviour should be on clicking the nav-button, scroll with ease to the end of the page(and a little break near the end).
Now the problem on PC works perfect. On android device (I tried my phone), the scrollTop value and the ($(document.body).height() - $(window).height()) do not match. There is exactly 55px less with the scrollTop thus acting all sorts of strange... Also sometimes it works sometimes it doesn't. I've figured it has something to do with the browser bar collapsing and upsetting the value...but i can't figure it out.
I've tried the following: initializing the variables on scroll event, i've tried vanilla js that didn't work. Need help :) for reference http://www.developer.morningmood.org , also i've printed out the values on bottom of the page if it helps. Here's the code.
contactF = Math.floor($(document.body).height() - $(window).height());
$("#cont").click(function(){
if ($(document).scrollTop() < contactF && flagScroll==true){ //flag stops other buttons from beying pushed
flagScroll = false;
var inter = setInterval(function(){
var doc = $(document).scrollTop();
if (doc == contactF){ // this is the final desired position
clearInterval(inter);
flagScroll = true;
pix = 10; //pixels to jump
return;
}
if (doc >= contactF-50){ // this is a break on aproach
pix = 1;
}
$(document).scrollTop(doc + pix);
}, 10);
}
})
EDIT: also to find the bug, you nedd to scroll from the top of the page all the way to the bottom, if from the top of the page you just push the contact button it works. but if you scroll it doesn't, it upsets the value...
Had the same exact problem and spent a whole day to figure it out.
You are right about the address bar collapse on Android chrome messing it up. Turns out the jQuery function $(window).height() always reports the viewport height that is before the address bar collapses. To get the correct value, use window.innerHeight instead. You can find more information about URL bar resizing here https://developers.google.com/web/updates/2016/12/url-bar-resizing
You can also find people asking similar questions regarding the safari address bar auto-hide, the solutions are similar. Mobile Safari $(window).height() URL bar discrepancy
Situation:
Suppose we are reading the content somewhere down the page that is built to be responsive. Suppose also that we resize the browser window to a smaller size and that some content above get extended down due to the thinner width, hence making the whole page longer. Then as we resize, whatever content we are looking at will get pushed down the page accordingly.
Example:
Suppose we were to look at the Helper classes section in this page. Then shrinking/expanding the window a sufficient amount moves the bit we were reading down/up the current view.
Prompt:
Is there any way we can fix this? I.e. maintain our current view of the page regardless of what happens to the contents above it when we resize the window.
Thoughts:
I am thinking that we could at least start with javascript and put an event on window resize. Then automatically scroll the page to the top-most element that was in our view on event fire. I don't know how this will affect the performance, however, especially in bigger pages.
There's also the problem of refering to the top-most element in current view. The top of our current view might be cutting off the top portion of some elements, not to mention that there's usually more than 1 element layered on top of one another at any point within the page. The notion of top-most element I've mentioned is not very well-defined :(
Also rather than a problem of responsive design in general, instead it seems to me like this is a problem with the default scrolling behaviour of web browsers? Or perhaps I am missing some circumstances where the current behaviour is desirable.
Edit 2 4
Updated fiddle (see fullscreen result) based on Rick Hitchcock's solution's solution.
With jQuery:
//onresize:
var scrollAmount;
if (topNode.getBoundingClientRect().top >= 0) {
scrollAmount = $(topNode).offset().top - topNode.getBoundingClientRect().top;
} else {
scrollAmount = $(topNode.offset().bottom - topNode.getBoundingClientRect().bottom;
}
$(window).scrollTop(scrollAmount);
The fiddle is acting a bit weird even in the same browsers, I've uploaded the same script using a free hosting here.
Still need to incorporate the IE, Opera and Safari fix for elementFromPoint.
Edit 3
Thanks for all the help, Rick Hitchcock. Welcome to stackoverflow, by the way :)
The discussion is turning into cross-browser compatibility issues so I've accepted your answer since we've pretty much got the answer to the original question. I'll still be fixing up my implementation though. The focus being cross-browser issues, topNode criteria, and topNode cut-off handling.
An edge case
While playing around with it, I noticed that when we were at the bottom of the page in a small viewport, then switch to a larger viewport (let us assume now that some more elements that were originally above the element we saw now came into view due to shorter container from wider viewport) the window cannot always lock the topNode to the top of the viewport in such a case since we've reached the scroll bottom. But then switching back to the small viewport now uses a new topNode that got into the viewport during the switch.
Although this should be expected from the behaviour being implemented, it is still a weird side-effect on scroll bottom.
I will also be looking into this in due course. Initially, I am thinking of simply adding a check for scroll bottom before we update topNode. I.e. to keep the old topNode when we've reached scroll bottom until we've scrolled up again. Not sure how this will turn out yet. I'll make sure to see how Opera handle this as well.
Here's what I've come up with:
(function(){
var topNode;
window.onscroll=function() {
var timer;
(function(){
clearTimeout(timer);
timer= setTimeout(
function() {
var testNode;
topNode= null;
for(var x = 0 ; x < document.body.offsetWidth ; x++) {
testNode= document.elementFromPoint(x,2);
if(!topNode || testNode.offsetTop>topNode.offsetTop) {
topNode = testNode;
}
}
},
100
)
}
)();
}
window.onresize=function() {
var timer;
(function(){
clearTimeout(timer);
if(topNode) {
timer= setTimeout(function(){topNode.scrollIntoView(true)},10);
}
}
)();
}
}
)();
If there were a window.onbeforeresize() function, this would be more straightforward.
Note that this doesn't take into account the scrolled position of the element's textNode. We could handle that if only the height of the window were resized. But resizing the width would generally cause reformatting.
This works in Chrome, Firefox, IE, and Safari.
Edit
How it works
The code's closures make variables private, and the timers prevent the code from running constantly during scrolling/resizing. But both tend to obfuscate the code, so here's another version, which may aid in understanding. Note that the onscroll timer is required in IE, because elementFromPoint returns null when it used in onscroll event.
var topNode;
window.onscroll=function() {
setTimeout(
function() {
var testNode;
topNode= null;
for(var x = 0 ; x < document.body.offsetWidth ; x++) {
testNode= document.elementFromPoint(x,2);
if(!topNode || testNode.offsetTop>topNode.offsetTop) {
topNode = testNode;
}
}
},
100
)
}
window.onresize=function() {
if(topNode) {
topNode.scrollIntoView(true)
}
}
topNode maintains the screen's top-most element as the window scrolls.
The function scans the screen left to right, along the 3rd row: document.elementFromPoint(x,2)*
It doesn't scan along the 1st row, because when IE does scrollIntoView, it pushes the element down a couple pixels, making the top-most screen element the previous element. (Figured this out through trial and error.)
When the window is resized, it simply positions topNode at the top of the screen.
[*Originally, onscroll scanned left to right along the 11th row (in pixels) until it found an element with just one child. The child would often be a textNode, but that wouldn't always be the case. Example:
<div><ul><li>...<li>...<li>...</ul></div>
The div has only one child – the ul. If the window were scrolled to the 50th li, scanning left to right would incorrectly return the div due to the inherent padding of lis.
The original code has been updated.
]
I have been writing a small script that shortens documents that are being output on a JSON feed of mine.
I realised that with longer messages, on minimising it could skip a few and you'd have to scroll back to find where you were and so added a scroll function to take you back to the top of the message on minifying. This turned out to be quite annoying when it fired every single time - so I thought, why not make it fire only when the top of the element is above the screen?
And this is where I am stuck --> $(window).scrollTop(); simply doesn't want to output the screen height for me, it's infuriating. I tried with different browsers and the only one .scrollTop() worked for correctly was Internet Explorer.
Here is the function below:
function jexpand(id){
var elm=$('#d'+jdesc[id].i); // element
var ofs=elm.offset().top; // element height - works fine
var top=$(window).scrollTop(); // Y U NO WORK?!!!
if(jdesc[id].e==true){ // boolean to check whether to expand or contract
jdesc[id].e=false; // change boolean flag
if(ofs < top) $('html').animate({scrollTop:($('#'+jdesc[id].i).offset().top)-(20)+'px'},'slow'); // animate to top minus 20 pixels
elm.html(jdesc[id].d.substring(0,347)+'...<br><div class="readmore"><span id="'+id+'">Show More</span></div>');
}else{
jdesc[id].e=true;
elm.html(jdesc[id].d+'<br><div class="readmore"><span id="'+id+'">Show Less</span></div>');
}
$('.readmore span').click(function(){jexpand(this.id)}); // reset click trigger
//alert(top+' <-> '+ofs);
}
When I uncomment the alert() at the bottom in a browser other than IE (I tried chrome, mozilla, chrome android, boat browser android) I get a message akin to:
[object Window] <-> 1077.5625
[object Window] is obviously not a number that can be greater or less than the element height! So what does this mean, is there another flag I need to ask of it? At first I assumed it might be the wrong element I was refering so tried top=$('body').scrollTop();, html, etc, I even tried using div wrapper elements but to no avail.
I am using jquery 1.11.0 and with 1.9.1 I had the same issue.
Am I trying to return the screen top in the wrong way or have all my browsers gone loopy?
EDIT:
Weirdly I've found an issue which may explain things a little, when I typed $(document).scrollTop() into a console it gave me the correct screen height however if I make a var top; outside of the function I get this error 'window.webkitStorageInfo' is deprecated. Please use 'navigator.webkitTemporaryStorage' or 'navigator.webkitPersistentStorage' instead..
I am using a webkit borrowed from html5up and this is somehow interfering with the code. Now to find out what it is....
Sorry for the confusion, without this script everything works fine grr...
Try this way
JS CODE:
$(window).scrollTop(0); // this will scroll to top of the page
LIVE DEMO:
http://jsfiddle.net/dreamweiver/fZrz7/6/
Happy Coding :)
What about $(document).scrollTop()? It always worked for me.
Try smth like this..
if($(window).scrollTop()>500){
elm.html(jdesc[id].d.substring(0,347)+'...<br><div class="readmore"><span id="'+id+'">Show More</span></div>');}
else{
elm.html(jdesc[id].d+'<br><div class="readmore"><span id="'+id+'">Show Less</span></div>');
}
If work try next with
var ofs=elm.offset().top;
Try this:
$(document).height(); //returns window height
$(document).scrollTop(); //returns scroll position from top of document
$(selector)[0].scrollHeight;
$(document).prop('scrollHeight');
I recently found the perfect mini-script for the pictures section of the site I've been working on non-stop for the last half year. I had it working but apparently in Firefox it doesn't want to play nice. What's even odder is I've played with it a bit; all my references are fine, but the thing won't do what I say anymore. Another oddity is I searched Google for some of the code, found it again (to examine it), and wouldn't you know: that incarnation runs perfectly on WebKit and even ran flawlessly on Firefox! I am about to pull my hair out, so, any help is appreciated. By the way, the script in question gets dynamically loaded towards the end of the DIV. My site (pictures section): http://www.elemovements.com/pictures and the replica: http://www.gmcbryde.com/. Here is the code, as well, just for good measure (which you can find unminified at http://el.x10.mx/js/logic/pictures.js [you need only concern yourself with the first 40-50 lines or so]):
if ( $('div.highslide-gallery').length ) {
$( function() {
var $Div = $('div.highslide-gallery'),
$Ul = $('ul.horiz-list'),
$UlPadding = 0;
$Ul.width(9000);
$Div.width( $Div.parent().parent().width() - 26 );
var $DivWidth = $Div.width();
$Div.css( {overflow: 'hidden'} );
var lastLi = $Ul.find('li:last-child');
$Div.mousemove(function(e){
var $UlWidth = lastLi[0].offsetLeft + lastLi.outerWidth() + $UlPadding;
var left = (e.pageX - $Div.offset().left) * ($UlWidth-$DivWidth) / $DivWidth;
$Div.scrollLeft(left);
} );
} );
}
The issue I am experiencing is that the DIV just won't move in Firefox. In WebKit, it works as expected but all that happens in good ol' Mozilla is the mousemove() event gets fired. I appreciate anyone's help. Thank you.
I just remembered that Firefox requires an initial width for elements, and I had forgotten to again include the CSS I had for it after I first scrapped it. That made all the difference. Thanks anyway!
Ahoy!
I've built a little script to check the size of the left-hand margin on page load, resize a div there to fill it, and change the header div to float next to it.
Here's the code:
function buildHeader() {
var containerMarginLeft = $(".container_16:not(:first)").css("margin-left");
var headerHeight = $("#header").height();
$("#stripe").width(containerMarginLeft).height(headerHeight).css("float", "left");
$(".container_16:first").css("float", "left");
$("#header").css("margin-left", 0).width(950);
}
$(document).ready(function(){
// Manipulate layout for the first time
buildHeader();
// Manipulate layout when window is resized
var resizeTimer = null;
$(window).bind('resize', function() {
if (resizeTimer) clearTimeout(resizeTimer);
resizeTimer = setTimeout(buildHeader, 100);
});
});
And the demonstration is here: http://robertmay.me.uk/mockups/plane.html (it creates the line that stretches on the left).
Now, it works in webkit browsers. It doesn't work in Mozilla, and I've not even tried it in IE.
Anyone have any ideas as to why it doesn't seem to work in Mozilla? I have a feeling it might have something to do with the CSS.
$(".container_16:not(:first)").css("margin-left");
This line gives a result of '0px' in Firefox regardless of how wide the window gets. However, Firebug Lite in Safari shows this value as changing depending on the width of the window.
The problem seems to be with the .css('margin-left') part of the statement, since $(".container_16:not(:first)") returns the same element in both browsers. Indeed, Firebug in Firefox shows the Computed Style for this element as having '0px' for marginLeft and marginRight, but this is non-zero in Safari.
As expected, changing from 'margin-left' to 'marginLeft' makes no difference, nor does accessing the attribute directly, like $(".container_16:not(:first)")[0].style.marginLeft, because Firefox is computing it wrong in the first place.
Sorry I don't have an answer, but hopefully this will lead you in the right direction. For me though I would try to align the layout using just CSS, resorting to JavaScript fixes only as a last resort.