jQuery hide/show issue with offset - javascript

I have a navbar on my website that is too wide for all buttons to display on mobiles devices. So I want to hide when the offset of the navigation buttons from the viewport is less than 150px (a drop down will take it's place). If there is more than 150px offset, then the navbar needs to be displayed.
I have made a Fiddle that shows what I want (resize the window). It correctly hides the navbar from view, but it won't make it appear again if there offset is greater than 150.
I know this happens because the element gets width "auto" and so the condition cannot be checked, but I don't know a workaround for this.
How can I fix this issue? Thanks.
HTML
<div>
<div class="container">
<div class="item">Some</div>
<div class="item">Example</div>
<div class="item">Text</div>
</div>
</div>
CSS
div {
background: red;
text-align: center;
}
.container {
display: inline-block;
background: green;
}
.item {
display: inline-block;
background: green;
}
JS
$(window).on('resize', function(){
var offset = $('.container').offset();
if (offset.left < 150) {
$('.container').hide();
} else {
$('.container').show();
}
}).resize();

The reason this is happening is that once you hide something, it is no longer rendered and so it does not know the .offset() of the container.
Maybe try css "visibility" instead?
See: http://jsfiddle.net/hnwacrzq/5/
$(window).on('resize', function(){
var offset = $('.container').offset();
console.log(offset);
if (offset.left < 150) {
$('.container').css("visibility", "hidden");
} else {
$('.container').css("visibility", "visible");
}
}).resize();

Related

Highlight active menu items as page scrolls divs (Sidebar onscroll menu)

This JSFiddle by Gaurav Kalyan works well in Chrome, but in Safari and Firefox it activates the wrong menu item. Instead of highlighting the menu item clicked, it highlights the menu item before. So, for example, if you click on "Punkt 4", "Punkt 3" is highlighted instead. I haven’t been able to fix this. Can someone help? I've been trying to solve this for two weeks.
HTML
<section id="main">
<div class="target" id="1">TARGET 1</div>
<div class="target" id="2">TARGET 2</div>
<div class="target" id="3">TARGET 3</div>
<div class="target" id="4">TARGET 4</div>
</section>
<aside id="nav">
<nav>
Punkt 1
Punkt 2
Punkt 3
Punkt 4
</nav>
</aside>
CSS
* {
margin: 0;
padding: 0;
}
#main {
width: 75%;
float: right;
}
#main div.target {
background: #ccc;
height: 400px;
}
#main div.target:nth-child(even) {
background: #eee;
}
#nav {
width: 25%;
position: relative;
}
#nav nav {
position: fixed;
width: 25%;
}
#nav a {
border-bottom: 1px solid #666;
color: #333;
display: block;
padding: 10px;
text-align: center;
text-decoration: none;
}
#nav a:hover, #nav a.active {
background: #666;
color: #fff;
}
JavaScript
$('#nav nav a').on('click', function(event) {
$(this).parent().find('a').removeClass('active');
$(this).addClass('active');
});
$(window).on('scroll', function() {
$('.target').each(function() {
if($(window).scrollTop() >= $(this).offset().top) {
var id = $(this).attr('id');
$('#nav nav a').removeClass('active');
$('#nav nav a[href=#'+ id +']').addClass('active');
}
});
});
This works fine as is if the viewport height (the inner height of the browser window) is <= 400px. That is because when you click on the a link in the nav element, with an href of #4, the default browser behavior kicks in and the element with id="4" is scrolled to the top (as much as is possible).
When the viewport is the same height or smaller than the element being scrolled to, then when your scroll handler gets triggered, the if($(window).scrollTop() >= $(this).offset().top) condition evaluates as true, because the scrollTop will be exactly equal to the offset().top of the #4 div.
However, when the viewport is bigger than the content div (in your case, > 400px), when the browser tries to scroll the last div into view, it can completely do so whilst still displaying part of the bottom half of the previous div. Which means that the 3rd div will pass your scroll handler if check, not your fourth. (The offset top of the last div will not be <= the scrollTop of the window).
So what's the solution?
I would make it so that each target div is at least the same height as the viewport. You can achieve this on modern browsers using min-height: 100vh; (100% of the viewport height). That means when the last one is scrolled into view, it will completely fill the viewport, and the correct div will pass your scroll logic check correctly.
See here for a working fork.
Bonus tip
There is a number of things you can do to improve performance of this code. Cache the creation of jQuery variables, avoid the repeated work happening 4 times on every scroll event (which can happen very often), etc. It works okay for now, but it may become a bottleneck later.

el.scrollIntoViewIfNeeded() scrolls too far up

el.scrollIntoViewIfNeeded() scrolls to el if it's not inside of the visible browser area. In general it works fine but I'm having problems with using it with a fixed header.
I made an example snippet: (The method doesn't work in Firefox, so neither does the demo) https://jsfiddle.net/ahugp8bq/1/
In the beginning all three colored divs are displayed below the fixed header. But if you click "second" and then "first", the beginning of #first will be behind the header, which I don't want.
The problem seems to be that the position of #otherContainer (its padding-top) is pretty much ignored when scrolling up.
Actually, this is quite simple if you use the consistent and supported getBoundingClientRect().top + body.scrollTop way - all you now have to do is reduce the header from it, so just get it and calculate its height.
var header = document.getElementById('container')
var clicks = document.querySelectorAll('#container li');
var content = document.querySelectorAll('#otherContainer > div');
// Turn the clicks HTML NodeList into an array so we can easily foreach
Array.prototype.slice.call(clicks).forEach(function(element, index){
element.addEventListener('click', function(e){
e.preventDefault();
// Set the scroll to the top of the element (top + scroll) minus the headers height
document.body.scrollTop = content[index].getBoundingClientRect().top + document.body.scrollTop - header.clientHeight;
});
});
#container {
position: fixed;
background: yellow;
width: 100%;
height: 50px;
}
ul li {
display: inline;
cursor: pointer;
}
#otherContainer {
padding-top: 60px
}
#first, #second, #third {
height: 500px
}
#first {
background: red
}
#second {
background: green
}
#third {
background: blue
}
<div id="container">
<ul>
<li id="jumpToFirst">first</li>
<li id="jumpToSecond">second</li>
<li id="jumpToThird">third</li>
</ul>
</div>
<div id="otherContainer">
<div id="first"></div>
<div id="second"></div>
<div id="third"></div>
</div>

jQuery/CSS - Add fixed to element on scroll and remove it when reach end of element

Here is the code that i have so far:
$(window).scroll(function() {
var scroll = $(window).scrollTop();
if (scroll >= 120) {
$("#FixedBox").addClass("fixed");
} else {
$("#FixedBox").removeClass("fixed");
}
});
With this code when the page is scrolled with 120px it add the class fixed to the element with id FixedBox.
What i want?
The element with id FixedBox is contained in element with id Content. So when the page is scrolled with 120 px my script attaches fixed class to FixedBox which makes it fixed.
How can i remove that fixed class when FixedBox reaches the end of Content ?
Here is an image in example:
How i can achieve that?
I hope you can help me!
You could make a function which checks if the scroll height is in between the start and the end of the content and adds the class accordingly. This would even work if you have several blocks of content.
Live Demo (3rd content box is the target)
HTML
<div class="content">
<div class="box">
</div>
</div>
<div class="content" id="target">
<div class="box">
</div>
</div>
CSS
.content{
width: 100%;
height: 400px;
background: red;
margin-bottom: 20px;
position: relative;
}
.fixed{
width: 100px;
height: 100px;
position: fixed;
right: 10px;
top: 10px;
background: blue;
display: block;
}
jQuery
var content = $('#target');
$(window).scroll(function() {
var scroll = $(window).scrollTop();
var offset = content.offset();
var height = content.height();
if (offset.top <= scroll && scroll <= offset.top + height) {
$('.box', content).addClass("fixed");
} else {
$('.box', content).removeClass('fixed');
}
});
You can find the end of your content by finding its position by $('#content').offset() or $('#footer').offset() more in the jQuery API Docs.
When you calculate the height of your elements and positions you can figure out the top threshold where you need to remove the fixed class of the FixedBox. Keep in mind that you also need to alter the non-fixed position of your FixedBox when it returns to the DOM flow, else it will snap back to the starting position.
`
var maxScroll = 120 + document.getElementById('#content').offsetHeight;
if (scroll >= 120 && scroll <= maxScroll) {
$("#FixedBox").addClass("fixed");
} else {
$("#FixedBox").removeClass("fixed");
}
You just need to get #content height.

Header appearence not working when refreshing the page

Well, I have a very simple code, that do something like... when you are at the top of the page, #header have background-color:transparent;, and as you start scrolling down, it has static black color. It works great, but every time, when I refresh the page, the header has the black color instead of transparent.... I tried making the offset in scrolling from the top heigher, but still nothing. (when I refresh it, it has black color, as i scroll down, still black color, but as i scroll to the top again, right at the top it works, and i have the color transparent. [it starts working when i just move with the scroll button, but not from the beginning{landing} on the page])... there is my code:
js:
$(window).scroll(function () {
if ($(window).scrollTop() < 500) {
$('#header').css("background-color", "transparent");
}
else{
$('#header').css("background-color", "black");
}
});
css (for header)
#header {
background-color: black;
height: 75px;
width: 100%;
top:0px;
position: fixed;
z-index: 10;
}
html:
<div class="container">
<!--HEADER-->
<div id="header">
<div id="main">
<img src="images/my_logo.png">
</div>
<div id="menu">
<img name="menu" src="images/my_menu.png">
</div>
</div>
<!--/HEADER-->
At the moment you're only running the function when you scroll the page. You need to also run your function on the page load...
$(function(){
// Run it on page-loaded
setHeaderColour();
// Run it on scroll
$(window).scroll(setHeaderColour);
});
function setHeaderColour() {
if ($(window).scrollTop() < 500) {
$('#header').css("background-color", "transparent");
}
else{
$('#header').css("background-color", "black");
}
});
This is because the changes that you make on the client are not stored after a refresh, and the page is back to how it was before. This will make sure that after the refresh you set the colour correctly
As per the comment by #Quantiastical, this is probably better code, as it will cover more events and keeps your function in one place...
$(function(){
$(window).on('load scroll resize orientationchange', function () {
if ($(window).scrollTop() < 500) {
$('#header').css("background-color", "transparent");
}
else{
$('#header').css("background-color", "black");
}
});
});
Well, i found my solution, which is the best. Simply change the background color of the header in css to transparent, so... when the page loads itself, the header has no appearance, when i start scrolling, the event-handler starts and jQuery do its job :) easy as a pie
#header {
background-color: transparent;
height: 75px;
width: 100%;
top:0px;
position: fixed;
z-index: 10;
}

javascript window scroll issue

I am working on javascript scroll. I have following html code
JSFIDDLE
<div class="wrapper">
<div class="red div current"></div>
<div class="blue div"></div>
<div class="green div"></div>
<div class="yellow div"></div>
</div>
In above code I have four div tags red, blue, green and yellow. All of them are position in following css.
html, body {
height: 100%;
}
.wrapper {
overflow: hidden;
height: 100%;
}
.div {
position: relative;
height: 100%;
}
.red {
background: red;
}
.blue {
background: blue;
}
.green {
background: green;
}
.yellow {
background: yellow;
}
In above html and css the red div tag is the current one which means user is seeing the red div tag on the screen. Now what I am trying to do is when user scroll over window once, then the next div tag i.e. blue will be animated and moved to the top and will become visible to the user whereas the red div tag will be behind the blue one. This same process goes for both green and yellow.
The problem is that when user scroll once then the div tag should animate however my current javascript code is keep reading the scroll and animating the div tags one after another. What I want is when user scroll once then scroll should be disabled until the blue div tag is animated. Then scroll should be enabled. Again when user scroll second time, the scroll should disable until the green div tag completes its animation. Same goes for yellow.
How can I achieve above?
Here is my javascript
$(window).on("scroll", function () {
var next = $('.current').next();
var height = next.outerHeight();
next.animate({top: '-=' + height}, 500, function () {
$(this).prev().removeClass('current');
$(this).addClass('current');
});
});
Please have a look on update JsFiddle
$(window).on("scroll", function () {
var next = $('.current').next();
var height = $('.current').outerHeight();
$('.current').prevAll().each(function(){
height += $(this).outerHeight();
});
next.animate({top: '-=' + height}, 500, function () {
$(this).prev().css('top','');
$(this).prev().toggleClass('current');
$(this).toggleClass('current');
});
});
The main reason your example wasn't working as expected is because you were relatively positioning the divs, and not moving them to the correct spot.
Working JSFiddle:
http://jsfiddle.net/seanjohnson08/rVVuc/6/
.wrapper {
overflow: hidden;
height: 100%;
position: relative;
}
.div {
position: absolute;
height: 100%;
width: 100%;
top: 100%;
}
.current{
top: 0;
}
If you are looking for a way to limit the amount of scroll events fired, try throttling: http://benalman.com/projects/jquery-throttle-debounce-plugin/. My solution doesn't require this, because no matter how many times it is firing the scroll event, it only ever tells jquery to animate to top:0, there's no chance of it animating past that.

Categories