How to prevent hard jumping and what is alternative to position: sticky? - javascript

Two questions:
Focus on the part of 'Get early access' bar. It is positioned with position:relative and I want to have it sticky once you move to the 2nd section. I've tried to add helper with the same height in order to get smooth transition when I change the .class to fixed. But not working.
This with helper in previous websites helped me but now it doesn't work and it really bothers me.
What would be alternative to position sticky which works in all browsers? In this particular case, how needs jquery to look like?
Thanks in advance.
/**
* Zirelco
* Custom JS functions
*/
jQuery(document).ready(function ( $ ) {
var mn = $("#sticky-wrapper");
mns = "nav--scrolled";
hdr = $("#top-wrapper-v1").height();
$(window).scroll(function() {
if( $(this).scrollTop() > hdr ) {
mn.addClass(mns);
} else {
mn.removeClass(mns);
}
});
$('.cookies .btn').on('click', function() {
if ($('.cookies').css('opacity') == 0) {
$('.cookies').css('opacity', 1);
}
else {
$('.cookies').addClass('none');
}
});
});

Edit V3
Try this Code instead of yours:
(function(selector) {
selector = selector || '#sticky-wrapper';
var stickyWrapper = document.querySelector(selector)
var stickyTrigger = document.createElement('div')
stickyTrigger.classList.add('sticky-trigger')
stickyWrapper.parentElement.insertBefore(stickyTrigger, stickyWrapper)
var listener = function (e) {
if (stickyTrigger.getBoundingClientRect().top < 0) {
stickyWrapper.classList.add('sticky');
} else {
stickyWrapper.classList.remove('sticky');
}
}
var onScroll = document.addEventListener('scroll', listener);
}('#sticky-wrapper'))
What this does is:
create a .sticky-trigger element
insert this right before #sticky-wrapper
watch for scroll event of document
check the top property of getBoundingClientRect of the .sticky-trigger element
toggle the sticky class of #sticky-wrapper depending on the sign (positive or negative) of that top value
You don't have to change your HTML output at all
Old V1
You use the height of the #top-wrapper-v1 <section> as trigger for the class toggle. But you totally forget the to calc the <header> height as well.
To prevent such mistakes just go for the top edge of the '#sticky-wrapper' as a trigger
// $(window).scroll(function(e) {
// if( $(this).scrollTop() > mn.offset().top ) {
// mn.addClass('sticky');
// } else {
// mn.removeClass('sticky');
// }
//});
Old V2
Because of the comment of the asker, this is an improved way of doing it.
In the previous example, the measurement of the offset().top of #sticky-wrapper is immediately set to 0 caused by position: fixed. In order to break this issue, we wrap the #sticky-wrapper in a trigger element, measure the offset().top of that element as trigger. This trigger element will remain in the document flow and will not be fixed
HTML
<!--
<section id="sticky-trigger">
<section id="sticky-wrapper" class="">
<div class="container" style="position: fixed;top: 0;">
Other content
</div>
</section>
</section>
-->
JavaScript
// var trigger = document.querySelector('#sticky-trigger')
// $(window).scroll(function(e) {
//
// if( $(this).scrollTop() > trigger.offset().top ) {
// mn.addClass('sticky');
// } else {
// mn.removeClass('sticky');
// }
// });

Related

How do I code JQuery so that when I scroll to a certain element, Nav bar appears at top, when I scroll back up past that element, nav bar disappears

I have a div called #menu which I want to display when I scroll past the element #section3, if I scroll up past that element again, I want #menu to disappear
How would I code this?
Maybe something like this?
scrolled = "no"
$(window).scroll(function(){
scr = $("body").scrollTop();
if (scr > 100 && scrolled == "no"){
$("#menu").css({"display:block"})
displayed = "yes"
}
if (displayed == "yes" && scrolled = "yes"){
$("#menu").css({"display:none"})
}
});
The above assumes that #section3 is 100 pixels down the page. If you do not know where its going to be on the page then you could use the method outlined here:
Trigger event when user scroll to specific element - with jQuery
With jQuery you can get the scroll position with $("body").scrollTop();.
Expanding on what #Ned Hulton said, I recommend comparing the scroll position to the top of a "container element" (or 'row') in your page like this:
if ($('body').scrollTop() > $('#someRow').offset().top){
//do something
}
That way you can account for your container appearing at a variable distance down the page (which will come in handy for mobile browsing or cases where your text wraps to additional lines)
I just whipped this up in jsfiddle
https://jsfiddle.net/rb56j0yu/
it uses jQuery, and checks the scroll position against the target div. Css sets the menu as position: fixed, and defaults to hidden.
$(window).scroll(function(){
var yPos = $("body").scrollTop();
var yCheck = $("#c3").position().top;
if (yPos > yCheck && !$("#menu").is(":visible"))
{
$("#menu").show();
}
if (yPos <= yCheck && $("#menu").is(":visible"))
{
$("#menu").hide();
}
});
First, get your #section3 top offset and height. Which will be used as the threshold whether #section3 is actually on the window screen.
var top = $('#section3').offset().top;
var bot = topOffset + $('#section3').height();
Then, detect it on your scroll event.
$(window).on('scroll', function () {
var scrollTop = $(window).scrollTop();
if (scrollTop >= top && scrollTop <= bot) {
// #section3 is within the screen.
$('#menu').show();
}
else {
// #section3 is out of screen.
$('#menu').hide();
}
});
This is a common use case, I wrote following code:
// what does "Auto Header" mean, goto https://www.yahoo.com/
// scroll down and you will see the purple part auto fixed to top,
// while when scroll up, it restores and does not be fixed.
// 1. multiple auto header elements handled
// 2. dynamically create/remove elements issue handled
// 3. no unnecessary dom operation, high performance
// usage: just add 'class="auto-header"' to any element you want to auto header
// suggest set each auto-header element specific width and height
// do not guarantee it works when resize or scroll left/right
$(document).ready(function() {
var rawTops = [],
rawLefts = [],
rawStyles = [],
$locations = [], // record next sibling so that element easily find where to restore
fixed = []; // mark whether this element is fixed
$(".auto-header").each(function() {
var $this = $(this),
offset = $this.offset();
rawTops.push(offset.top);
rawLefts.push(offset.left);
rawStyles.push($this.attr("style"));
$locations.push($this.siblings().eq($this.index()));
fixed.push(false);
});
$(window).on("scroll", function() {
$(".auto-header").each(function(i, e) {
if(!fixed[i] && $(window).scrollTop() > rawTops[i]) {
var $te = $(this).clone(true);
$(this).remove();
$locations[i].before($te);
$te.css({
"position": "fixed",
"top": 0,
"left": rawLefts[i],
"z-index": 100
});
fixed[i] = true;
} else if(fixed[i] && $(window).scrollTop() < rawTops[i]) {
$(this).removeAttr("style").attr("style", rawStyles[i]);
fixed[i] = false;
}
});
});
});

Allow more scroll (slack) before firing actual scroll further event

I have a box which has an overflow scroll on it. When you reach the end of the box; I want to fire an event (scroll to the next section of the page).
Below code works, however, I want some "slack" in it. So it does not needs to fire directly when you reach the end of your box, but only when you persist on scrolling downwards.
Any help on improving below code to reach this effect?
function whiteboxscroll (){
$('.white-box-inner').on("DOMContentLoaded scroll",function(){
var myDiv = $('.white-box-inner');
myDiv.each(function(){
el = this;
if(isElementInViewport(el) === true) { // current white box is in view
if (this.offsetHeight + this.scrollTop >= this.scrollHeight ) { //current box is at end of scroll
//define the current section 'this' belongs to
var current_section = $(this).parents().eq(1);
// define the next section
var next_section = $(current_section).next('.cd-section');
// smoothscroll to this next section
if(next_section.attr('id') !== undefined){ // only perform scroll if next section is defined
smoothScroll($('#' + next_section.attr('id')));
}
}
else if(this.scrollTop === 0){ // current box is at top of scroll
//define the current section 'this' belongs to
var current_section = $(this).parents().eq(1);
// define the prev section
var prev_section = $(current_section).prev('.cd-section');
// smoothscroll to this next section
if(prev_section.attr('id') !== undefined) { // only perform scroll if prev section is defined
smoothScroll($('#' + prev_section.attr('id')));
}
}
}
});
});
}
I tried to add a buffer of 50 pixels ie, but then the events never fires, since we will never reach that point.
You can set a variable to true when you reach the end of scrolling and check if that variable is true on mousewheel.
var enable_scroll = false;
$(".container").scroll(function(e){
$('p.info').html(this.scrollTop);
if(this.offsetHeight + this.scrollTop >= this.scrollHeight ) {
$('p.info').html("End of scroll. Flag enabled.");
enable_scroll = true;
}
})
.on('mousewheel DOMMouseScroll',function(e){ //DOMMouseScroll for FF
if(enable_scroll){
$('p.info').html("<strong>Event fired</strong>");
}
});
.container { height: 250px; overflow:auto;}
.inner {height: 1000px;}
p.info{ padding: 10px; color: #fff; background: orange;}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<p class="info">Start scrolling</p>
<div class="container">
<div class="inner">Scroll down</div>
</div>
<p class="bottom"></p>

Get divs within viewport inside a wrapper div

Is there a way to get elements which is:
Inside a div with overflow: scroll
Is in viewport
Just like the following picture, where active div (5,6,7,8,9) is orange, and the others is green (1-4 and >10) :
I just want the mousewheel event to add "active" class to div 5,6,7,8,9 (currently in viewport). View my JSFiddle
$('.wrapper').bind('mousewheel', function (e) {
//addClass 'active' here
});
You could do something like this. I would have re-factored it, but only to show the concept.
Firstly I would attach this to scroll event and not mousewheel. There are those among us that likes to use keyboard for scrolling, and you also have the case of dragging the scrollbar. ;) You also have the case of touch devices.
Note that with this I have set overflow:auto; on wrapper, thus no bottom scroll-bar.
With bottom scrollbar you would either have to live with it becoming tagged as in-view a tad to early, or tumble into the world of doing a cross-browser calculating of IE's clientHeight. But the code should hopefully be OK as a starter.
»»Fiddle««
function isView(wrp, elm)
{
var wrpH = $(wrp).height(),
elmH = $(elm).height(),
elmT = $(elm).offset().top;
return elmT >= 0 &&
elmT + elmH < wrpH;
}
$('.wrapper').bind('scroll', function (e) {
$('div.box').each(function(i, e) {
if (isView(".wrapper", this)) {
$(this).addClass('active');
} else {
$(this).removeClass('active');
}
});
});
Note that you should likely refactor in such a way that .wrapper height is only retrieved once per invocation, or if it is static, at page load etc.
Update; a modified version of isView(). Taking position of container into account. This time looking at dolphins in the pool.
»»Fiddle««
function isView(pool, dolphin) {
var poolT = pool.offset().top,
poolH = pool.height(),
dolpH = dolphin.height(),
dolpT = dolphin.offset().top - poolT;
return dolpT >= 0 && dolpT + dolpH <= poolH;
}

How can I check if a scrollbar is visible?

Is it possible to check the overflow:auto of a div?
For example:
HTML
<div id="my_div" style="width: 100px; height:100px; overflow:auto;" class="my_class">
* content
</div>
JQUERY
$('.my_class').live('hover', function (event)
{
if (event.type == 'mouseenter')
{
if( ... if scrollbar visible ? ... )
{
alert('true'):
}
else
{
alert('false'):
}
}
});
Sometimes is the content short (no scrollbar) and sometimes long (scrollbar visible).
a little plugin for it.
(function($) {
$.fn.hasScrollBar = function() {
return this.get(0).scrollHeight > this.height();
}
})(jQuery);
use it like this,
$('#my_div1').hasScrollBar(); // returns true if there's a `vertical` scrollbar, false otherwise..
tested working on Firefox, Chrome, IE6,7,8
but not working properly on body tag selector
demo
Edit
I found out that when you have horizontal scrollbar that causes vertical scrollbar to appear, this function does not work....
I found out another solution... use clientHeight
return this.get(0).scrollHeight > this.get(0).clientHeight;
You can do this using a combination of the Element.scrollHeight and Element.clientHeight attributes.
According to MDN:
The Element.scrollHeight read-only attribute is a measurement of the height of an element's content, including content not visible on the screen due to overflow. The scrollHeight value is equal to the minimum clientHeight the element would require in order to fit all the content in the viewpoint without using a vertical scrollbar. It includes the element padding but not its margin.
And:
The Element.clientHeight read-only property returns the inner height of an element in pixels, including padding but not the horizontal scrollbar height, border, or margin.
clientHeight can be calculated as CSS height + CSS padding - height of horizontal scrollbar (if present).
Therefore, the element will display a scrollbar if the scroll height is greater than the client height, so the answer to your question is:
function scrollbarVisible(element) {
return element.scrollHeight > element.clientHeight;
}
Maybe a more simple solution.
if ($(document).height() > $(window).height()) {
// scrollbar
}
I should change a little thing of what Reigel said:
(function($) {
$.fn.hasScrollBar = function() {
return this[0] ? this[0].scrollHeight > this.innerHeight() : false;
}
})(jQuery);
innerHeight counts control's height and its top and bottom paddings
This expands on #Reigel's answer. It will return an answer for horizontal or vertical scrollbars.
(function($) {
$.fn.hasScrollBar = function() {
var e = this.get(0);
return {
vertical: e.scrollHeight > e.clientHeight,
horizontal: e.scrollWidth > e.clientWidth
};
}
})(jQuery);
Example:
element.hasScrollBar() // Returns { vertical: true/false, horizontal: true/false }
element.hasScrollBar().vertical // Returns true/false
element.hasScrollBar().horizontal // Returns true/false
You need element.scrollHeight. Compare it with $(element).height().
I made a new custom :pseudo selector for jQuery to test whether an item has one of the following css properties:
overflow: [scroll|auto]
overflow-x: [scroll|auto]
overflow-y: [scroll|auto]
I wanted to find the closest scrollable parent of another element so I also wrote another little jQuery plugin to find the closest parent with overflow.
This solution probably doesn't perform the best, but it does appear to work. I used it in conjunction with the $.scrollTo plugin. Sometimes I need to know whether an element is inside another scrollable container. In that case I want to scroll the parent scrollable element vs the window.
I probably should have wrapped this up in a single plugin and added the psuedo selector as a part of the plugin, as well as exposing a 'closest' method to find the closest (parent) scrollable container.
Anywho....here it is.
$.isScrollable jQuery plugin:
$.fn.isScrollable = function(){
var elem = $(this);
return (
elem.css('overflow') == 'scroll'
|| elem.css('overflow') == 'auto'
|| elem.css('overflow-x') == 'scroll'
|| elem.css('overflow-x') == 'auto'
|| elem.css('overflow-y') == 'scroll'
|| elem.css('overflow-y') == 'auto'
);
};
$(':scrollable') jQuery pseudo selector:
$.expr[":"].scrollable = function(a) {
var elem = $(a);
return elem.isScrollable();
};
$.scrollableparent() jQuery plugin:
$.fn.scrollableparent = function(){
return $(this).closest(':scrollable') || $(window); //default to $('html') instead?
};
Implementation is pretty simple
//does a specific element have overflow scroll?
var somedivIsScrollable = $(this).isScrollable();
//use :scrollable psuedo selector to find a collection of child scrollable elements
var scrollableChildren = $(this).find(':scrollable');
//use $.scrollableparent to find closest scrollable container
var scrollableparent = $(this).scrollableparent();
UPDATE: I found that Robert Koritnik already came up with a much more powerful :scrollable pseudo selector that will identify the scrollable axes and height of scrollable containers, as a part of his $.scrollintoview() jQuery plugin. scrollintoview plugin
Here is his fancy pseudo selector (props):
$.extend($.expr[":"], {
scrollable: function (element, index, meta, stack) {
var direction = converter[typeof (meta[3]) === "string" && meta[3].toLowerCase()] || converter.both;
var styles = (document.defaultView && document.defaultView.getComputedStyle ? document.defaultView.getComputedStyle(element, null) : element.currentStyle);
var overflow = {
x: scrollValue[styles.overflowX.toLowerCase()] || false,
y: scrollValue[styles.overflowY.toLowerCase()] || false,
isRoot: rootrx.test(element.nodeName)
};
// check if completely unscrollable (exclude HTML element because it's special)
if (!overflow.x && !overflow.y && !overflow.isRoot)
{
return false;
}
var size = {
height: {
scroll: element.scrollHeight,
client: element.clientHeight
},
width: {
scroll: element.scrollWidth,
client: element.clientWidth
},
// check overflow.x/y because iPad (and possibly other tablets) don't dislay scrollbars
scrollableX: function () {
return (overflow.x || overflow.isRoot) && this.width.scroll > this.width.client;
},
scrollableY: function () {
return (overflow.y || overflow.isRoot) && this.height.scroll > this.height.client;
}
};
return direction.y && size.scrollableY() || direction.x && size.scrollableX();
}
});
(scrollWidth/Height - clientWidth/Height) is a good indicator for the presence of a scrollbar, but it will give you a "false positive" answer on many occasions.
if you need to be accurate i would suggest using the following function.
instead of trying to guess if the element is scrollable - you can scroll it...
function isScrollable( el ){
var y1 = el.scrollTop;
el.scrollTop += 1;
var y2 = el.scrollTop;
el.scrollTop -= 1;
var y3 = el.scrollTop;
el.scrollTop = y1;
var x1 = el.scrollLeft;
el.scrollLeft += 1;
var x2 = el.scrollLeft;
el.scrollLeft -= 1;
var x3 = el.scrollLeft;
el.scrollLeft = x1;
return {
horizontallyScrollable: x1 !== x2 || x2 !== x3,
verticallyScrollable: y1 !== y2 || y2 !== y3
}
}
function check( id ){
alert( JSON.stringify( isScrollable( document.getElementById( id ))));
}
#outer1, #outer2, #outer3 {
background-color: pink;
overflow: auto;
float: left;
}
#inner {
width: 150px;
height: 150px;
}
button { margin: 2em 0 0 1em; }
<div id="outer1" style="width: 100px; height: 100px;">
<div id="inner">
<button onclick="check('outer1')">check if<br>scrollable</button>
</div>
</div>
<div id="outer2" style="width: 200px; height: 100px;">
<div id="inner">
<button onclick="check('outer2')">check if<br>scrollable</button>
</div>
</div>
<div id="outer3" style="width: 100px; height: 180px;">
<div id="inner">
<button onclick="check('outer3')">check if<br>scrollable</button>
</div>
</div>
Ugh everyone's answers on here are incomplete, and lets stop using jquery in SO answers already please. Check jquery's documentation if you want info on jquery.
Here's a generalized pure-javascript function for testing whether or not an element has scrollbars in a complete way:
// dimension - Either 'y' or 'x'
// computedStyles - (Optional) Pass in the domNodes computed styles if you already have it (since I hear its somewhat expensive)
function hasScrollBars(domNode, dimension, computedStyles) {
dimension = dimension.toUpperCase()
if(dimension === 'Y') {
var length = 'Height'
} else {
var length = 'Width'
}
var scrollLength = 'scroll'+length
var clientLength = 'client'+length
var overflowDimension = 'overflow'+dimension
var hasVScroll = domNode[scrollLength] > domNode[clientLength]
// Check the overflow and overflowY properties for "auto" and "visible" values
var cStyle = computedStyles || getComputedStyle(domNode)
return hasVScroll && (cStyle[overflowDimension] == "visible"
|| cStyle[overflowDimension] == "auto"
)
|| cStyle[overflowDimension] == "scroll"
}
The first solution above works only in IE
The second solution above works only in FF
This combination of both functions works in both browsers:
//Firefox Only!!
if ($(document).height() > $(window).height()) {
// has scrollbar
$("#mtc").addClass("AdjustOverflowWidth");
alert('scrollbar present - Firefox');
} else {
$("#mtc").removeClass("AdjustOverflowWidth");
}
//Internet Explorer Only!!
(function($) {
$.fn.hasScrollBar = function() {
return this.get(0).scrollHeight > this.innerHeight();
}
})(jQuery);
if ($('#monitorWidth1').hasScrollBar()) {
// has scrollbar
$("#mtc").addClass("AdjustOverflowWidth");
alert('scrollbar present - Internet Exploder');
} else {
$("#mtc").removeClass("AdjustOverflowWidth");
}​
Wrap in a document ready
monitorWidth1 : the div where the overflow is set to auto
mtc : a container div inside monitorWidth1
AdjustOverflowWidth : a css class applied to the #mtc div when the Scrollbar is active
*Use the alert to test cross browser, and then comment out for final production code.
HTH
I'm going to extend on this even further for those poor souls who, like me, use one of the modern js frameworks and not JQuery and have been wholly abandoned by the people of this thread :
this was written in Angular 6 but if you write React 16, Vue 2, Polymer, Ionic, React-Native, you'll know what to do to adapt it. And it's the whole component so it should be easy.
import {ElementRef, AfterViewInit} from '#angular/core';
#Component({
selector: 'app',
templateUrl: './app.html',
styleUrls: ['./app.scss']
})
export class App implements AfterViewInit {
scrollAmount;
constructor(
private fb: FormBuilder,
private element: ElementRef
) {}
ngAfterViewInit(){
this.scrollAmount = this.element.nativeElement.querySelector('.elem-list');
this.scrollAmount.addEventListener('wheel', e => { //you can put () instead of e
// but e is usefull if you require the deltaY amount.
if(this.scrollAmount.scrollHeight > this.scrollAmount.offsetHeight){
// there is a scroll bar, do something!
}else{
// there is NO scroll bar, do something!
}
});
}
}
in the html there would be a div with class "elem-list" which is stylized in the css or scss to have a height and an overflow value that isn't hidden. (so auto or sroll )
I trigger this eval upon a scroll event because my end goal was to have "automatic focus scrolls" which decide whether they are scrolling the whole set of components horizontally if said components have no vertical scroll available and otherwise only scroll the innards of one of the components vertically.
but you can place the eval elsewhere to have it be triggered by something else.
the important thing to remember here, is you're never Forced back into using JQuery, there's always a way to access the same functionalities it has without using it.
The solutions provided above will work in the most cases, but checking the scrollHeight and overflow is sometimes not enough and can fail for body and html elements as seen here:
https://codepen.io/anon/pen/EvzXZw
1. Solution - Check if the element is scrollable:
function isScrollableY (element) {
return !!(element.scrollTop || (++element.scrollTop && element.scrollTop--));
}
Note: elements with overflow: hidden are also treated as scrollable (more info), so you might add a condition against that too if needed:
function isScrollableY (element) {
let style = window.getComputedStyle(element);
return !!(element.scrollTop || (++element.scrollTop && element.scrollTop--))
&& style["overflow"] !== "hidden" && style["overflow-y"] !== "hidden";
}
As far as I know this method only fails if the element has scroll-behavior: smooth.
Explanation: The trick is, that the attempt of scrolling down and reverting it won't be rendered by the browser. The topmost function can also be written like the following:
function isScrollableY (element) {
// if scrollTop is not 0 / larger than 0, then the element is scrolled and therefore must be scrollable
// -> true
if (element.scrollTop === 0) {
// if the element is zero it may be scrollable
// -> try scrolling about 1 pixel
element.scrollTop++;
// if the element is zero then scrolling did not succeed and therefore it is not scrollable
// -> false
if (element.scrollTop === 0) return false;
// else the element is scrollable; reset the scrollTop property
// -> true
element.scrollTop--;
}
return true;
}
2. Solution - Do all the necessary checks:
function isScrollableY (element) {
const style = window.getComputedStyle(element);
if (element.scrollHeight > element.clientHeight &&
style["overflow"] !== "hidden" && style["overflow-y"] !== "hidden" &&
style["overflow"] !== "clip" && style["overflow-y"] !== "clip"
) {
if (element === document.scrollingElement) return true;
else if (style["overflow"] !== "visible" && style["overflow-y"] !== "visible") {
// special check for body element (https://drafts.csswg.org/cssom-view/#potentially-scrollable)
if (element === document.body) {
const parentStyle = window.getComputedStyle(element.parentElement);
if (parentStyle["overflow"] !== "visible" && parentStyle["overflow-y"] !== "visible" &&
parentStyle["overflow"] !== "clip" && parentStyle["overflow-y"] !== "clip"
) {
return true;
}
}
else return true;
}
}
return false;
}
Here's an improved version of Evan's answer which seems to properly account for overflow logic.
function element_scrollbars(node) {
var element = $(node);
var overflow_x = element.css("overflow-x");
var overflow_y = element.css("overflow-y");
var overflow = element.css("overflow");
if (overflow_x == "undefined") overflow_x == "";
if (overflow_y == "undefined") overflow_y == "";
if (overflow == "undefined") overflow == "";
if (overflow_x == "") overflow_x = overflow;
if (overflow_y == "") overflow_y = overflow;
var scrollbar_vertical = (
(overflow_y == "scroll")
|| (
(
(overflow_y == "hidden")
|| (overflow_y == "visible")
)
&& (
(node.scrollHeight > node.clientHeight)
)
)
);
var scrollbar_horizontal = (
(overflow_x == "scroll")
|| (
(
(overflow_x == "hidden")
|| (overflow_x == "visible")
)
&& (
(node.scrollWidth > node.clientWidth)
)
)
);
return {
vertical: scrollbar_vertical,
horizontal: scrollbar_horizontal
};
}
Most of the answers presented got me close to where I needed to be, but not quite there.
We basically wanted to assess if the scroll bars -would- be visible in a normal situation, by that definition meaning that the size of the body element is larger than the view port. This was not a presented solution, which is why I am submitting it.
Hopefully it helps someone!
(function($) {
$.fn.hasScrollBar = function() {
return this.get(0).scrollHeight > $(window).height();
}
})(jQuery);
Essentially, we have the hasScrollbar function, but returning if the requested element is larger than the view port. For view port size, we just used $(window).height(). A quick compare of that against the element size, yields the correct results and desirable behavior.
Here's my improvement: added parseInt. for some weird reason it didn't work without it.
// usage: jQuery('#my_div1').hasVerticalScrollBar();
// Credit: http://stackoverflow.com/questions/4814398/how-can-i-check-if-a-scrollbar-is-visible
(function($) {
$.fn.hasVerticalScrollBar = function() {
return this.get(0) ? parseInt( this.get(0).scrollHeight ) > parseInt( this.innerHeight() ) : false;
};
})(jQuery);
Works on Chrome, Edge, Firefox and Opera, at least in the newer versions.
Using JQuery...
Setup this function to fix the footer:
function fixFooterCaller()
{
const body = $('body');
const footer = $('body footer');
return function ()
{
// If the scroll bar is visible
if ($(document).height() > $(window).height())
{
// Reset
footer.css('position', 'inherit');
// Erase the padding added in the above code
body.css('padding-bottom', '0');
}
// If the scrollbar is NOT visible
else
{
// Make it fixed at the bottom
footer.css('position', 'fixed');
// And put a padding to the body as the size of the footer
// This makes the footer do not cover the content and when
// it does, this event fix it
body.css('padding-bottom', footer.outerHeight());
}
}
}
It returns a function. Made this way just to set the body and footer once.
And then, set this when the document is ready.
$(document).ready(function ()
{
const fixFooter = fixFooterCaller();
// Put in a timeout call instead of just call the fixFooter function
// to prevent the page elements needed don't be ready at this time
setTimeout(fixFooter, 0);
// The function must be called every time the window is resized
$(window).resize(fixFooter);
});
Add this to your footer css:
footer {
bottom: 0;
}
Find a parent of current element that has vertical scrolling or body.
$.fn.scrollableParent = function() {
var $parents = this.parents();
var $scrollable = $parents.filter(function(idx) {
return this.scrollHeight > this.offsetHeight && this.offsetWidth !== this.clientWidth;
}).first();
if ($scrollable.length === 0) {
$scrollable = $('html, body');
}
return $scrollable;
};
It may be used to autoscroll to current element via:
var $scrollable = $elem.scrollableParent();
$scrollable.scrollTop($elem.position().top);
A No Framework JavaScript Approach, checks for both vertical and horizontal
/*
* hasScrollBars
*
* Checks to see if an element has scrollbars
*
* #returns {object}
*/
Element.prototype.hasScrollBars = function() {
return {"vertical": this.scrollHeight > this.style.height, "horizontal": this.scrollWidth > this.style.width};
}
Use it like this
if(document.getElementsByTagName("body")[0].hasScrollBars().vertical){
alert("vertical");
}
if(document.getElementsByTagName("body")[0].hasScrollBars().horizontal){
alert("horizontal");
}
There's two area sizes to consider, the window and the html. If the html width, for example, is greater than window width then a scroll bar may be present on the user interface. So it's a matter of reading the window proportions and the html proportions and doing the basic math.
As for displaying an arrow overlaid atop the page, that's done with a simple classlist toggle, e.g. .hidden{display:none}
Here's a crossbrowser method for getting these proportions. (credit W3 Schools)
|| document.body.clientWidth;
var h = window.innerHeight || document.documentElement.clientHeight ||
document.body.clientHeight; ```
I had the problem, that I needed to check, if the scrollbar is visible on the whole screen (body) or not. Chrome has the ability to hide the scrollbar despite the fact that there is an overflow happening, hence the body is scrollable.
Therefore the solutions above did not work for me. I now check, if there is a scrollbar the following way:
const isScrollbarPresent = () => {
const beforeScrollbarHidden = document.body.clientWidth;
const overflowState = document.body?.style.overflow;
document.body.style.overflow = 'hidden';
const afterScrollbarHidden = document.body.clientWidth;
document.body.style.overflow = overflowState;
return beforeScrollbarHidden !== afterScrollbarHidden;
};
I get the width of the body, with or without the scrollbar and save the current overflow state of the body. Then I hide the scrollbar. If there was a scrollbar, the width of the body is now bigger. If not, the width is the same. After that I revert the overflow state.
Another easy answer is the following:
export const isScrollbarPresent = (element?: HTMLElement) => {
const testedElement = element ?? document.body;
return testedElement.scrollHeight > testedElement.clientHeight; }
I check if the scrollHeight of the element is bigger then the clientHeight. The scrollHeight returns the absolute height of an element including all elements, that are not visible. The clientHeight returns the visible height on the screen.

JQuery If condition (specific for a content slider)

I am new at JQuery and I have a specific question about the IF-THEN-ELSE fork.
The big problem for me is the syntax of this (I suck at Javascript). It would help me if anyone can "translate" the pseudo code into a JQuery (or Javascript) valide code.
The pseudo code:
IF "#Contentshowroom" css "left" is NOT > 1960px
THEN
On Click "#Forwardbutton" DO
animate "#Contentshowroom" css "left" =+980px
ELSE You can not click on the "#Forwardbutton"
Place the if() statement in the click handler for #Forwardbutton to test the left position of #Contentshowroom.
If you're using jQuery:
$('#Forwardbutton').click(function() {
var $Content = $('#Contentshowroom');
if( $Content.offset().left <= 1960 ) {
$Content.animate({ left: '+= 980' });
}
});
So now when you click the Forwardbutton, it will check the left .offset() position of the Contentshowroom to see if it is less than or equal to 1960px. And if so, it will animate the left position an additional 980px.
jQuery's .offset() method gives you the top/left positions relative to the body. If you want it relative to its parent container, then use jQuery's .position() method.
click doc
animate doc
offset doc
$("#Forwardbutton").click( function( e ){
// lookup is safe, no noticable performance cost.
// though a reference makes it more losely coupled.
// I'll leave it at your discretion.
var target = $("#Contentshowroom")
// NOTE: the offset parent should have position relative or absolute.
, leftPos = target.offset().left;
if ( leftPos < 1960 ) {
target.animate({
left : leftPos + 980
}); // see docs to tweak animation
} // else do nothing.
} );
Could also use e.preventDefault(); , but don't if it's not needed, it will safe you headaches if you add more listeners to your buttons and find out they're not working.
// first store contentShowroom and it's left property to save getting > 1
var contentShowroom = $('#Contentshowroom');
var showroomLeft = contentShowroom.css('left');
var forwardButton = $('#Forwardbutton');
if (showroomLeft <= 1960){
forwardButton.click(function(){
contentShowroom.animate({left: showroomLeft + 980);
}
}
else {
forwardButton.unbind('click');
}
if this is to be run once at the beginning then
if ( $('#Contentshowroom').offset().left > 1960 )
{
$('#Forwardbutton').click( function(){
$('#Contentshowroom').animate({left:'+=980'});
} );
}
else
{
// if the #Contentshowroom is a link then
$('#Contentshowroom').removeAttr('href');
// if the #Contentshowroom is a button then
// $('#Contentshowroom').attr('disabled',true);
}

Categories