Responsive jQuery menu, collapsing last elements into separate menu - javascript

I have a single level navigation list. What I want to do is, on window resize, add a dropdown at the end to display elements that do not fit the window width.
Below an image representation:
var base = this,
container = $(base.selector),
items = container.find('>li:not(.smallmenu):visible'),
count = container.find('>li:not(.smallmenu):visible').length,
listWidth = [],
added;
items.each(function() {
listWidth.push($(this).width());
});
function getWidth() {
var width = 0;
container.find('>li:not(.smallmenu):visible').each(function() {
width += $(this).outerWidth();
});
return width + 100;
}
function hideLast() {
var i = container.find('>li:not(.smallmenu):visible').last().index()
if( $(window).width() < (getWidth()) ) {
items.eq(i).hide();
if(!added) {
$('<li class="smallmenu"><i class="fa fa-plus"></i></li>').appendTo(container);
added = true;
}
}
}
function showLast() {
var i = container.find('>li:not(.smallmenu):visible').last().index();
if( (getWidth() + listWidth[i+1]) < $(window).width() ) {
container.find('>li:not(.smallmenu)').eq(i+1).show();
if((i+2) === count) {
container.find('.smallmenu').remove();
added = false;
}
}
}
$(window).resize(function() {
showLast();
hideLast();
});
However this is not working as expected and half-done. I feel like I am heading in the wrong direction.
EDIT: Here is an updated jsFiddle: http://jsfiddle.net/anteksiler/zyv8f/1/ Resize your browser to get the effect.

Related

adding class to position:sticky but is adding class to every sticky element

Added this code to my sticky element using position:sticky
var $sticky = $('.grid-container .sticky'),
$stickyTo = $('.grid-container .stickyTo'),
stickyToTop = $stickyTo.offset().top,
stickyToBottom = stickyToTop + $stickyTo.outerHeight();
$(window).on('scroll', function() {
var scroll = $(window).scrollTop(),
stickyTop = $sticky.offset().top,
stickyBottom = $sticky.offset().top + $sticky.outerHeight();
if (stickyBottom >= stickyToBottom) {
if (scroll < stickyTop) {
//$sticky.addClass('fixed').removeClass('abs');
} else {
//$sticky.addClass('abs');
}
} else if (scroll > stickyToTop) {
$sticky.addClass('stuck');
} else if (scroll < stickyToTop) {
$sticky.removeClass('stuck');
}
});
and I have two sticky elements see image attached but when I scroll to the first section it adds a class "stuck" on the second section, how can I make that only on that section jquery is triggered and not affect the second/other section unless scrolled on
Here is My FIDDLE
Because $sticky in your case is a jQuery collection with two elements in it you have to use .each() loop to check each element separately. Then you probably don't need $stickyTo, because you have to check for each 'sticky' element's own .parent(). Something like this:
var $sticky = $('.grid-container .sticky'),
$(window).on('scroll', function() {
var scroll = $(window).scrollTop()
$sticky.each(function(){
const $this = $(this)
const stickyTop = $this.offset().top,
const stickyBottom = stickyTop + $sticky.outerHeight();
const $stickyTo = $this.parent()
const stickyToTop = $stickyTo.offset().top,
const stickyToBottom = stickyToTop + $stickyTo.outerHeight();
if (stickyBottom >= stickyToBottom) {
if (scroll < stickyTop) {
//$sticky.addClass('fixed').removeClass('abs');
} else {
//$sticky.addClass('abs');
}
} else if (scroll > stickyToTop) {
$sticky.addClass('stuck');
} else if (scroll < stickyToTop) {
$sticky.removeClass('stuck');
}
})
});
Please note though, this function is not really optimized. It would be better to use native javascript during the scroll. Or even better check native CSS position: sticky.

Scrolling sidebar inside a div with scrollbar - $(window).on('scroll', function()?

I want my social sidebar make scroll only within the gray div. I have already put the sidebar within the gray div does not exceed the footer or the content above. My difficulty is to sidebar scroll accompanying the scroll without going gray div.
http://test.eae.pt/beautyacademy/angebot/
JS:
beautyAcademy.sharer = {
element: void 0,
elementToScroll: void 0,
init:function() {
this.element = $('.js-sharer-ref');
console.log(this.element.length);
if(this.element.length != 1) {
return;
}
this.build();
},
build: function() {
this.binds();
},
binds: function() {
var _this = this;
// Element that's gonna scroll
this.$elementToScroll = $('.fixed-social');
// Element that's gonna scroll height
this.elementToScrollHeight = this.$elementToScroll.outerHeight();
// Element where scroll is gonna happen Height
this.elementHeight = this.element.outerHeight();
// Element where scroll is gonna happen distance to top
this.elementOffsetTop = this.element.offset().top;
// Scroll that was done on the page
this.windowScrollTop = $(window).scrollTop();
this.elementOffsetBottom = this.elementOffsetTop + this.elementHeight - this.elementToScrollHeight;
this.$elementToScroll.css('top', (_this.elementOffsetTop+80) + "px");
$(window).on('scroll', function() {
if(this.windowScrollTop + this.elementToScrollHeight < this.elementHeight )
this.$elementToScroll.css('margin-top', this.windowScrollTop );
});
}
};
You need to try like below :
$(function(){
if ($('#container').length) {
var el = $('#container');
var stickyTop = $('#container').offset().top; // returns number
var stickyHeight = $('#container').height();
$(window).scroll(function(){ // scroll event
var limit = $('#footer').offset().top - stickyHeight - 20;
var windowTop = $(window).scrollTop(); // returns number
if (stickyTop < windowTop){
el.css({ position: 'fixed', top: 0 });
}
else {
el.css('position','static');
}
if (limit < windowTop) {
var diff = limit - windowTop;
el.css({top: diff});
}
});
}
});
DEMO

jQuery - sticky element is overlapping the footer, how to avoid it?

I have a sticky sidebar working on my project, but when you go to the bottom of the page, the sticky sidebar is overlapping my footer.
What I want is that when the sticky element reach the footer, then stop just right there so the user can see the entire footer.
here is a demonstration of what I have so far.
or a jsfiddle in case it is easier for you
this is the code:
var stickySidebar = $('.sticky');
if (stickySidebar.length > 0) {
var stickyHeight = stickySidebar.height(),
sidebarTop = stickySidebar.offset().top;
}
// on scroll move the sidebar
$(window).scroll(function () {
if (stickySidebar.length > 0) {
var scrollTop = $(window).scrollTop() + 70;
if (sidebarTop < scrollTop) {
stickySidebar.stop(true, false).animate({top: scrollTop - sidebarTop});
// stop the sticky sidebar at the footer to avoid overlapping
var sidebarBottom = stickySidebar.offset().top + stickyHeight,
stickyStop = $('.main-content').offset().top + $('.main-content').height();
if (stickyStop < sidebarBottom) {
var stopPosition = $('.main-content').height() - stickyHeight;
stickySidebar.stop(true, true).animate({top: stopPosition});
}
}
else {
stickySidebar.stop().animate({top: 0});
}
}
});
$(window).resize(function () {
if (stickySidebar.length > 0) {
stickyHeight = stickySidebar.height();
}
});
This is maybe not perfect, but I think it gives you the right idea, how to solve this problem. You just have to check, if the bottom of the sidebar is below the top position of the footer. Than stop the animation.
http://jsfiddle.net/hdj99b21/1/
[...]
var stickyTopPos = stickySidebar.offset().top;
var stickyBottomPos = stickyHeight + stickyTopPos;
var footerTopPos = $('footer').offset().top;
if(stickyBottomPos >= footerTopPos) {
var stopPosition = footerTopPos - stickyHeight;
stickySidebar.stop(true, true).css({top: stopPosition});
}
[...]

JavaScript is being triggered before its time, *only on Chrome & IE

I have a gallery of three Grids with images. The grid sizes changes depending on the screen size, and I have achieved that using Media-Query - ie, on desktop the grid's width will be 33% to make three columns view next to each other, and on tablet it will be 50% to make two columns view, and on phone it will be a 100% for each grid making one column view.
The reason I did this is to create a tiled gallery with images of different heights - and if I did it the normal way it will generate White-empty-spaces when floating.
So to fix this problem, and with the help of few members on this website, we have created a JavaScrip function that will MOVE all of the images that are inside Grid3 equally to Grid1 & Grid2 when screen size is tablet, so we get rid of the third grid making a view of fine two columns. Everything is working great!
Now, the problem is - on Chrome & IE - The function is being fired before its time for some reason that I need your help to help me find it! Please try it your self here: [http://90.195.175.51:93/portfolio.html][2]
Slowly on Chrome or IE - (try it on Firefox as well) - try to re-size the window from large to small, you will notice that BEFORE the top header changes to be a responsive Header (which indicate that you are on a small screen) the images have been sent to Grid1 and Grid 2! but a few px before the time. As on the function it says to fire it on <770.
Hope my question is clear enough for you to help me solve this issue which is stopping me from launching my website. Thanks.
Here is the JavaScrip:
//Gallery Grid System//
var testimonial = $(".testimonial, .galleryItem", "#grid3");
(function () {
$(document).ready(GalleryGrid);
$(window).resize(GalleryGrid);
})(jQuery);
function GalleryGrid() {
var grid3 = $('#grid3');
var width = $(window).width();
if (width < 1030 && width > 770) {
var grid1 = $('#grid1');
var grid2 = $('#grid2');
for (var i = 0; i < testimonial.length; i++) {
if (i < testimonial.length / 2) {
grid1.append(testimonial[i]);
} else {
grid2.append(testimonial[i]);
}
}
} else {
grid3.append(testimonial);
}
}
Note: The following is the whole page with all the functions:
$(document).ready(function () {
//Prevent clicking on .active links
$('.active').click(function (a) {
a.preventDefault();
});
//Allow :active on touch screens
document.addEventListener("touchstart", function () {}, true);
//Hide toolbar by default
window.addEventListener('load', function () {
setTimeout(scrollTo, 0, 0, 0);
}, false);
//Scroll-up button
$(window).scroll(function () {
if ($(this).scrollTop() > 100) {
$('.scrollup').fadeIn();
} else {
$('.scrollup').fadeOut();
}
});
$('.scrollup').click(function () {
$("html, body").animate({
scrollTop: 0
}, 600);
return false;
});
//StickyBox
$(function () {
$.fn.scrollBottom = function () {
return $(document).height() - this.scrollTop() - this.height();
};
var $StickyBox = $('.detailsBox');
var $window = $(window);
$window.bind("scroll resize", function () {
var gap = $window.height() - $StickyBox.height() - 10;
var footer = 288 - $window.scrollBottom();
var scrollTop = $window.scrollTop();
$StickyBox.css({
top: 'auto',
bottom: 'auto'
});
if ($window.width() <= 770) {
return;
$StickyBox.css({
top: '0',
bottom: 'auto'
});
}
if (scrollTop < 50) {
$StickyBox.css({
bottom: "auto"
});
} else if (footer > gap - 100) {
$StickyBox.css({
top: "auto",
bottom: footer + "px"
});
} else {
$StickyBox.css({
top: 80,
bottom: "auto"
});
}
});
});
//Change items location depending on the width of the screen//
$(function () { //Load Ready
function myFunction() {
var insert = $(window).width() <= 770 ? 'insertBefore' : 'insertAfter';
$('#home-sectionB img')[insert]($('#home-sectionB div'));
$('#home-sectionD img')[insert]($('#home-sectionD div'));
}
myFunction(); //For When Load
$(window).resize(myFunction); //For When Resize
});
//Contact Form//
$(".input").addClass('notSelected');
$(".input").focus(function () {
$(this).addClass('selected');
});
$(".input").focusout(function () {
$(this).removeClass('selected');
});
$(document).ready(function () {
GalleryGrid();
$(window).resize(GalleryGrid);
});
//Gallery Grid System//
var testimonial = $(".testimonial, .galleryItem", "#grid3");
(function () {
$(document).ready(GalleryGrid);
$(window).resize(GalleryGrid);
})(jQuery);
function GalleryGrid() {
var grid3 = $('#grid3');
var width = $(window).width();
if (width < 1030 && width > 770) {
var grid1 = $('#grid1');
var grid2 = $('#grid2');
for (var i = 0; i < testimonial.length; i++) {
if (i < testimonial.length / 2) {
grid1.append(testimonial[i]);
} else {
grid2.append(testimonial[i]);
}
}
} else {
grid3.append(testimonial);
}
}
//Testimonials Animation//
$(".testimonial").hover(function () {
$(".testimonial").addClass('testimonialNotActive');
$(this).removeClass('testimonialNotActive').addClass('testimonialActive');
},
function () {
$(".testimonial").removeClass('testimonialNotActive');
$(this).removeClass('testimonialActive');
});
//Portfolio Gallery Filter//
(function () {
var $portfolioGallerySection = $('#portfolio-sectionB'),
$filterbuttons = $('#portfolio-sectionA a');
$filterbuttons.on('click', function () {
var filter = $(this).data('filter');
$filterbuttons.removeClass('portfolio-sectionAClicked');
$(this).addClass('portfolio-sectionAClicked');
$portfolioGallerySection.attr('class', filter);
$('.galleryItem').removeClass('selectedFilter');
$('.galleryItem.' + filter).addClass('selectedFilter');
});
}());
});
Your problem is that CSS media queries and jQuery's $(window).width() do not always align.
function getCSSWidth() {
var e = window, a = 'inner';
if (!('innerWidth' in window )) {
a = 'client';
e = document.documentElement || document.body;
}
return e[ a+'Width' ];
}
Use this instead of $(window).width()
modified from http://andylangton.co.uk/articles/javascript/get-viewport-size-javascript/
I think this could solve your problem (but I'm not quite sure)
//Put that before the document ready event
(function($,sr){
// debouncing function from John Hann
// http://unscriptable.com/index.php/2009/03/20/debouncing-javascript-methods/
var debounce = function (func, threshold, execAsap) {
var timeout;
return function debounced () {
var obj = this, args = arguments;
function delayed () {
if (!execAsap)
func.apply(obj, args);
timeout = null;
};
if (timeout)
clearTimeout(timeout);
else if (execAsap)
func.apply(obj, args);
timeout = setTimeout(delayed, threshold || 100);
};
}
// smartresize
jQuery.fn[sr] = function(fn){ return fn ? this.bind('resize', debounce(fn)) : this.trigger(sr); };
})(jQuery,'smartresize');
// Here you call GalleryGrid (replace $(window).resize(GalleryGrid) with that):
$(window).smartresize(GalleryGrid);
http://www.paulirish.com/2009/throttled-smartresize-jquery-event-handler/
The reason is your vertical scrollbar. Your content is fixed at width=1030, but when the window size is 1030, the size of the viewport is actually: window size (1030) - vertical scroll bar
Try setting
<body style="overflow:hidden">
You will see that it works correctly when the scrollbar is removed. Or try setting:
<link href="assets/css/tablets-landscape.css" rel="stylesheet" type="text/css" media="screen and (max-width : 1045px)"/>
Set max-width:1045px to make up for scrollbar, you will see that it works correctly.
Your javascript should be like this:
var width = $(window).width() + verticalscrollbarWidth;

Jquery resizeable auto resize parent

I've got a couple of nested resizable div's that need to resize to accommodation the child size.
Everything works fine until i try to resize one of the outer div's (vertically) then it gets stuck.
Here's a fiddle.
$(function () {
$('.block').resizable();
$('.block').resize(resize_handler);
});
function checkChildren(object) {
$(object).children(".block").each(function (index, item) {
var itemH = $(item).position().top + $(item).height();
var itemW = $(item).position().left + $(item).width();
if ($(object).width() < itemW) {
$(item).width($(object).width());
checkChildren($(item));
}
if ($(object).height() < itemH) {
$(item).height($(object).height());
checkChildren($(item));
}
});
}
function checkParent(e) {
var object = $(e);
var par = object.parent();
var totalW = object.width() + object.position().left;
var totalH = object.height() + object.position().top;
if (totalH > par.height()) {
par.height(totalH);
checkParent(par);
}
if (totalW > par.width()) {
par.width(totalW);
checkParent(par);
}
}
function resize_handler(e, ui) {
e.stopPropagation();
var object = $(this);
var par = object.parent();
if (par.hasClass("block")) {
checkParent(object);
}
if (object.children('.block').length > 0) {
checkChildren(object);
}
}
Sure you've already thought of this but could you try limiting the resizeability of the parent div if its height is too close to the height of its child. Meaning when it is about to come in contact with the edge of a child then don't allow it to come any closer. Maybe maintain a buffer around the children of a few pixels which would force the user to adjust the child first before they could adjust the parent any smaller.
Just a thought.

Categories

Resources