How to detect scroll direction when content changes height on scroll - javascript

It's quite straightforward to detect the scroll direction when scrolling page with static size. But if one of the elements is a sticky header and changes the height while scrolling it keeps changes pageYOffset and enters into infinite loop jumping up and down.
Example sandbox where if you scroll to the point were it starts shrinking it starts jumping.
Some possible solution I've came up with was to add a spacer which would compensate when the sticky navigation gets smaller. But that requires doing it in the actual component. Wondering if there is a way to do it with js only in the useScrollDirection hook.
One of the other things I've tried was to use document.documentElement.scrollHeight and check for the size change, that didn't help as well.

Just a suggestion. I think you are underutilizing position: sticky. You don't need an event listener to achieve the behavior you want. You can do this entirely with CSS and let the browser handle everything for you.
.app {
font-family: sans-serif;
text-align: center;
height: 300vh;
}
.nav {
position: sticky;
top: -120px;
height: 150px;
background: aquamarine
}
.nav_item {
position: sticky;
top: 0px;
margin: 0;
}
<div class="app">
<h1>Hello CodeSandbox</h1>
<nav class="nav">
<p class="nav_item">Hello</p>
</nav>
<h2>Start editing to see some magic happen!</h2>
</div>

I encountered the same problem and a co-worker recommended me to listen to the wheel event. So I implemented the following react hook:
const useLastMouseWheelDirection = () => {
const [lastMouseWheelDirection, setLastMouseWheelDirection] = useState(
undefined
)
useEffect(() => {
const handler = (event) => {
setLastMouseWheelDirection(event.deltaY >= 0 ? 'down' : 'up')
}
window.addEventListener('wheel', handler)
return () => window.removeEventListener('wheel', handler)
}, [])
return lastMouseWheelDirection
}
This solution has some serious limitations:
Obviously touch events are ignored
Clicking and dragging the scroll bar will not fire the event
Also a side effect to the desired behavior would be that it wouldn't take into consideration if the element is even overflowing or not, although the hook could be extended to catch this case.
Further more the MDN Web Docs state:
Note: Don't confuse the wheel event with the scroll event. The default action of a wheel event is implementation-specific, and doesn't necessarily dispatch a scroll event. Even when it does, the delta* values in the wheel event don't necessarily reflect the content's scrolling direction. Therefore, do not rely on the wheel event's delta* properties to get the scrolling direction. Instead, detect value changes of scrollLeft and scrollTop of the target in the scroll event.
So please take this answer with a grain of salt.

Related

How to change button color based on background?

I write in React. On the page I have a scroll up button.
When scrolling on some blocks, it is not visible due to the fact that the colors match.
How to make it so that when it touches certain blocks of the same color as the button, it turns white.
How to track the contact of a button with a specific block? What listeners to put?
Since the button is probably position: fixed or position: absolute, the easiest solution would be to give CSS property mix-blend-mode a try, instead of listeners, as there is no accurate way of telling the position w.r.t to background.
Check this
Try to give mix-blend-mode: difference; for the scroll to top button.
Although I think in this case you will have the color yellow for the button when it overlaps blue.
Although Sanjay's answer "works", you really don't have much control over the styles you get, unless that blend-mode:difference is the look you're going for.
For more fine grained control, you need to use the IntersectionObserver API.
There's really three steps to this process:
1. Get the required options for IntersectionObserver constructor
This means you need to find out the negative margins to set as the rootMargin key. This key is part of the configuration object of your IntersectionObserver instance.
In practice you would have to find the distance of your trigger element(in your case the floating action button) to the edges of the viewport. In the code snippet below, this is done using the getDistanceToEdge() function.
It's better to do it this way instead of statically setting your margins, since it dynamically infers the margins from the position set from your styles.
2. Tell the observer what you wish to when triggered
This is the callback which will trigger the new styles on your floating button. You need to check whether your elements are intersecting with the button using the entry.isIntersecting key, and then conditionally render the style.
3. Setup the observer with elements you wish to cause the trigger
The elements that scroll up causing your floating button to change color, should be passed to the observer, using the observer.observe() function.
The following code snippet really does all the setup you need. It won't trigger unless the element is actually underneath the button (the API internally checks vertical and horizontal overlaps).
For some reason I can't get it to work on iframes embedded in browsers. It could be something to do with the negative margins and multiple viewports.
It works perfectly on normal full page websites, as shown in this hosted link.
One little caveat is that consecutive elements that trigger the observer, will cause each other to cancel out, since the button enters the second area before fully leaving the first one. I'll leave it to someone else to figure out the specifics there.
// get the element that reacts to background elements
const fabElement = document.getElementById("fab");
// what do you want to do when it overlaps?
function reactToOverlap(entries) {
entries.forEach((entry) => {
if (entry.isIntersecting) fabElement.classList.add("triggered");
else fabElement.classList.remove("triggered");
});
}
const observerOptions = {
rootMargin: getDistanceToEdge(fabElement)
.map((val) => `-${val}px`)
.join(" "), // https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API#rootmargin for syntax
};
const observerInstance = new IntersectionObserver(
reactToOverlap,
observerOptions
);
// what elements do you want to trigger the change?
const elementsToTriggerFab = document.querySelectorAll(".triggeringContent");
elementsToTriggerFab.forEach((el) => observerInstance.observe(el));
/* Represents how far the element is from the edge of the browser, in all directions. */
function getDistanceToEdge(element) {
const elementBounds = element.getBoundingClientRect();
// top and left margins are identical to the pixel coordinates
const top = elementBounds.top;
const left = elementBounds.left;
// bottom and right need to be subtracted from the viewport bounds
const bottom = window.innerHeight - elementBounds.bottom;
const right = window.innerWidth - elementBounds.right;
return [top, right, bottom, left];
}
body {
font-size: 3rem;
background-color: white;
margin: 0;
padding: 0;
}
#fab {
background-color: blue;
color: white;
border-radius: 50%;
position: fixed;
padding: 1rem;
bottom: 50px;
right: 50px;
transition-property: background-color, color;
transition-duration: 0.5s
}
#fab.triggered {
background-color: white;
color: blue;
}
.normalContent {
color: green;
border: 10px solid green;
height: 100vh;
}
.triggeringContent {
height: 300px;
background-color: blue;
color: white;
}
.triggeringContent.avoidFab {
margin-right: 200px;
}
<div id="fab">Up</div>
<div class="normalContent">Other Content</div>
<div class="triggeringContent">Triggerring Content</div>
<div class="triggeringContent avoidFab">Triggerring Content</div>
<div class="normalContent">Problems coming up</div>
<div class="triggeringContent">Triggerring Content</div>
<div class="triggeringContent">Triggerring Content(Error)</div>
<div class="normalContent">Other Content</div>
<div class="triggeringContent avoidFab">Triggerring Content</div>
<script type="module" src="/main.js"></script>
Shoutout to cloned's comment for giving the idea for the solution.

Don't allow horizontal scroll when scrolling vertically (and vice versa)

I have a list, with the overflow-x and overflow-y set to auto. In addition, I've set up momentum scroll, so the touch scrolling works nice in mobile, using webkit-overflow-scrolling: true.
The issue, however, is that I cannot figure out how to disable the horizontal scroll when scrolling vertically. It leads to really bad user experience, as the swiping towards the top left or top right will cause the table to scroll diagonally. When the user is scrolling vertically, I absolutely do NOT want any scrolling horizontally until the user has stopped scrolling vertically.
I've tried the following:
JS:
offsetX: number;
offsetY: number;
isScrollingHorizontally = false;
isScrollingVertically = false;
//Detect the scrolling events
ngOnInit() {
this.scrollListener = this.renderer.listen(
this.taskRows.nativeElement,
'scroll',
evt => {
this.didScroll();
}
);
fromEvent(this.taskRows.nativeElement, 'scroll')
.pipe(
debounceTime(100),
takeUntil(this.destroy$)
)
.subscribe(() => {
this.endScroll();
});
}
didScroll() {
if ((this.taskRows.nativeElement.scrollLeft != this.offsetX) && (!this.isScrollingHorizontally)){
console.log("Scrolling horizontally")
this.isScrollingHorizontally = true;
this.isScrollingVertically = false;
this.changeDetectorRef.markForCheck();
}else if ((this.taskRows.nativeElement.scrollTop != this.offsetY) && (!this.isScrollingVertically)) {
console.log("Scrolling Vertically")
this.isScrollingHorizontally = false;
this.isScrollingVertically = true;
this.changeDetectorRef.markForCheck();
}
}
endScroll() {
console.log("Ended scroll")
this.isScrollingVertically = false;
this.isScrollingHorizontally = false;
this.changeDetectorRef.markForCheck();
}
HTML:
<div
class="cu-dashboard-table__scroll"
[class.cu-dashboard-table__scroll_disable-x]="isScrollingVertically"
[class.cu-dashboard-table__scroll_disable-y]="isScrollingHorizontally"
>
CSS:
&__scroll {
display: flex;
width: 100%;
height: 100%;
overflow-y: auto;
overflow-x: auto;
will-change: transform;
-webkit-overflow-scrolling: touch;
&_disable-x {
overflow-x: hidden;
}
&_disable-y {
overflow-y: hidden;
}
}
But the everytime I set overflow-x or overflow-y to hidden when its been scrolled, scrolling will glitch and jump back to the top. I've also noticed that webkit-overflow-scrolling: true is the reason why this occurs, when I remove it, the behavior seems to stop, but I absolutely need this for momentum scrolling in mobile devices.
How do I disable horizontal scroll when scrolling vertically?
It's generally a bad practice for your design to need multiaxis scrolling on mobile, unless maybe you're showing big tables of data. That being said, why do you want to prevent it? If a user wants to scroll diagonally, that doesn't seem like the end of the world to me. Some browsers, like Chrome on OSX, already do what you're describing by default.
If you must have single-axis scrolling, a possible solution might be to keep track of the scroll position yourself via touchstart and touchmove events. If you set your drag threshold lower than the browser's, you may be able to do your css stuff before it starts scrolling, avoiding the perceived glitch. Also, even if it does still glitch, you have the touch start and the touch's current location. From these, if you record your div's starting scroll position, you can manually scroll the div to the correct place to counteract it jumping to the top if you have to. A possible algorithm might look like this:
// Touchstart handler
if (scrollState === ScrollState.Default) {
// Record position and id of touch
touchStart = touch.location
touchStartId = touch.id.
scrollState = ScrollState.Touching
// If you have to manually scroll the div, first store its starting scroll position:
containerTop = $('.myContainer').scrollTop();
containerLeft = $('.myContainer').scrollLeft();
}
// Touchmove handler - If the user has dragged beyond a distance threshold,
// do the css classes swap.
if (touch.id === touchStartId && distance(touchStart, touch.location > threshold) {
scrollState = ScrollState.Scrolling;
swapCssClasses();
// If you have to manually scroll the div to prevent jump:
$('.myContainer').scrollTop(containerTop + (touch.location.y - touchStart.y));
// Do the same for horizontal scroll.
}
// Then, listen for debounced scroll events, like you're already doing,
// to reset your state back to default.
Second idea: in your scroll handler, instead of changing the css classes, set the scroll position of the div directly for the axis you want locked. IE, if you're scrolling horizontally, always set the scrollTop to its starting value. This might also cancel scrolling, not sure. You'd have to try it to see if it works.
Try this
HTML
<div
class="cu-dashboard-table__scroll-vertical"
>
<div
class="cu-dashboard-table__scroll-horizontal"
>
<!-- Scroll content here -->
</div>
</div>
CSS
&__scroll {
&-horizontal {
overflow-x: auto;
width: 100%;
-webkit-overflow-scrolling: touch;
}
&-vertical {
overflow-y: auto;
height: 100%;
-webkit-overflow-scrolling: touch;
}
}
Instead of using one div for scrolling, why dont you use two? Have one for X and one for Y
Need to use three containers.
In the first container I enable vertical scrolling and disallow horizontal.
In the second, vice versa, I enable horizontal scrolling and disallow vertical.
Be sure to use overflow-x: hidden; and overflow-y: hidden;, otherwise child containers may go beyond the current container.
Also need to use min-width: 100%; min-height: 100%;.
For the third container we need to use display: inline-block; and then the internal content will stretch this container and the corresponding scroll bars will appear on the two parent blocks.
HTML
<div class="scroll-y">
<div class="scroll-x">
<div class="content-container">
<!-- scrollable content here -->
</div>
</div>
</div>
CSS
.scroll-y {
position: absolute;
overflow-x: hidden;
overflow-y: auto;
width: 100%;
height: 100%;
min-width: 100%;
min-height: 100%;
}
.scroll-x {
overflow-y: hidden;
overflow-x: auto;
width: auto;
min-width: 100%;
min-height: 100%;
}
.content-container {
min-width: 100%;
min-height: 100%;
display: inline-block;
}
You can test it here in Safari on iPhone.
Good luck!! 😉
There are numerous ways to try to solve this. Some good ideas are offered here.
However, as others have alluded, relying on (or trying to avoid) multi-dimensional scrolling is a bad UX smell - indicative of the UX being a problem. I don't think this is a legitimate dev issue. It would be better to take a step back and reevaluate what you're trying to accomplish. One of the issues might be that in an effort to make the UI more usable, you'll be confusing users. The usability described here would likely cause confusion.
Why can't I scroll horizontally?
Why when I stop scrolling vertically, only then can I scroll horizontally?
These are some questions that may be asked (inaudible).
If you're trying to allow for additional information of the vertical data list to be browsable only when the user has selected the row, it would likely be much better to simply have a flat list by default only scrollable vertically, and only toggle the vertical information when the "row" has been selected/activated. Collapsing the details would get you back to the flat vertical list.
If you're having to jump through hoops to solve such a fringe technical challenge, it's a good indication that the user experience has not been designed well to begin with.
this looks like fun ;)
I won't argue about if it's reasonable.
I tried it with RxJS:
ngAfterViewInit() {
const table = document.getElementById("table");
const touchstart$ = fromEvent(table, "touchstart");
const touchmove$ = fromEvent(table, "touchmove");
const touchend$ = fromEvent(table, "touchend");
touchstart$
.pipe(
switchMapTo(
touchmove$.pipe(
// tap(console.log),
map((e: TouchEvent) => ({
x: e.touches[0].clientX,
y: e.touches[0].clientY
})),
bufferCount(4),
map(calculateDirection),
tap(direction => this.setScrollingStyles(direction)),
takeUntil(touchend$)
)
)
)
.subscribe();
}
We buffer every 4th touchemove event and then make some highly sophisticated calculation with the coordinates of the four events (map(calculateDirection)) which outputs RIGHT, LEFT, UP or DOWN and based on that I try to disable vertical or horicontal scrolling. On my android phone in chrome it kind of works ;)
I'v created a little playground, which could be enhanced, rewritten, whatsoever ...
Cheers Chris

Dispatch mouse wheel event on another DOM element

I have a web page with scrollable div on it.
On top of scrollable div I have absolutely positioned div that overlaps half of scrollable div.
When I put mouse cursor over scrollable div I can scroll it with mouse wheel. But when I move cursor over overlapping div then mouse wheel stops scroll that div (and this is correct behavior because absolute positioned div is not inside scrollable div).
Question: how to pass or dispatch scroll event received by absolute positioned div to this underlying scrollable div to make this absolute positioned div 'transparent' for mouse wheel events.
I could get it work in Chrome, but not in IE and Firefox. How to rewrite this code to get it work in IE and Firefox?
if ($.browser.webkit) {
$(".overlap-container").bind("mousewheel", function (e) {
var origEvent = e.originalEvent;
var evt = document.createEvent("WheelEvent");
evt.initWebKitWheelEvent(
origEvent.wheelDeltaX,
origEvent.wheelDeltaY,
window,
0,
0,
0,
0,
origEvent.ctrlKey,
origEvent.altKey,
origEvent.shiftKey,
origEvent.metaKey);
$(".scroll-container").get(0).dispatchEvent(evt);
});
}
See example here:
http://jsfiddle.net/HAc4K/5
EDITED: This issue originally is from jqGrid - frozen columns don't react mouse wheel scrolling.
In Chrome and Firefox awesome CSS property is supported: pointer-events:none
Looks like a known issue with jQuery: OriginalEvent not supported in IE
The short answer: you use wrong parameters of initWheelEvent in the demo in case of usage Internet Explorer. The method should have 16 parameters described in the documentation. Yo use currently only 11 parameters the same which have initWebKitWheelEvent, but the meaning of all parameters of initWheelEvent is absolutely another. You have to fix the parameters of initWheelEvent.
Use RetargetMouseScroll(overlap container, scroll container).
I realize this isn't exactly what you're looking for, but at least in Chrome, IE7+, and Firefox 3.5+ this does what you ask - scroll the underlying div when the div overlaying it receives scroll events:
http://jsfiddle.net/b9chris/yM3qs/
It's doing so simply because the overlapping div is a child of the div it overlaps - no jquery passing on any mousewheel events (although it is listening to scroll to ensure the overlapping div stays where it needs to be).
Implementing that kind of workaround in jqGrid might require upending a fair bit of code there, however.
HTML:
<div id=under>
(content goes here)
<div id=over></div>
</div>
CSS:
#under {
position: absolute;
left: 0; top: 0;
width: 220px; height: 200px;
overflow-y: scroll;
}
#over {
position: absolute;
left: 1px; top: 100px;
width: 200px; height: 100px;
z-index: 2;
}
JS:
(function() {
$('#under').on('scroll', function() {
$('#over').css('top', $(this).scrollTop() + 100);
});
})();
Here's the 2019 solution for overlapped container to get wheel event:
document.querySelector('.overlap').on('wheel', (e) => {
const overlap = e.target
overlap.style.pointerEvents = 'none'
setTimeout(() => {overlap.style.pointerEvents = 'auto'}, 0)
})
This way the overlapped element gets wheel event from the overlapping element called .overlap.

jQuery Mobile prevent scroll-to-top before page transition?

When I click on a list-item, to go to another page, the current page jumps to the top of the screen before transitioning to the next page.
This problem occured in jQM 1.2, and is still not fixed in the newly released 1.3 version.
Does anybody know how to prevent the scroll-to-top, and remember the scroll position when using the back button?
This annoying behaviour is unacceptable, and breaks the whole app experience.
I'm using it as a webapp, on an iPhone 4S, with iOS 6.1.2.
Before I describe your available solutions you need to understand, this is not an error nor is there a perfect solution. The issue is that to animate the transition to another page the viewport has to be at the top of the page so that the current page and the page transitioning in are vertically lined-up.
If you were half-way down a long list on one page (say 1000px) and the page you are transferring to is only a few hundred pixels tall then the current page would animate off the screen properly but the new page would not be visible as it would be above the viewport.
There are 2 viable solutions:
1. iScroll and its jQuery Mobile derivate iScrollview
iScroll homepage: http://cubiq.org/iscroll-4
iScrollview homepage: https://github.com/watusi/jquery-mobile-iscrollview
iScroll is a javascript that can scroll content in a window within a web browser with very similar behaviour to native scrolling on mobile devices such as iPhone and Android. This means you can scroll a window within the browser using native-like scrollbars and physics.
That is also a solution for our current problem. Because of iScroll implementation pages will occupy 100% of page height, no matter how far listview is scrolled. This is also a reason why on return listview will still stay at a same position.
Of course in case you want to implement this solution you should pick iScrollview implementation. You would still be able to implement iScroll, but it would take you much more time.
2. Silent scroll
Official documentation: http://jquerymobile.com/demos/1.1.0-rc.1/docs/api/methods.html
This jQuery Mobile functionality is also the same reason why we have this problem at the first place. Before a page transition is triggered original page is silently scrolled to the top.
In our case, when listview is selected, its position must be remembered (here you will find solutions of data/parameteres storing during the page transition, just search for the chapter: Data/Parameters manipulation between page transitions) before page is changed. In that case, when we return to the previous page we could use pagebefpreshow event to silently scroll to the bottom before page is shown.
//scroll to Y 100px
$.mobile.silentScroll(100);
And here's a working example of silent scroll: http://jsfiddle.net/Gajotres/5zZzz/
More info
If you want to find out more about this topic take a look at this article, you will also find working examples.
I was able to fix this (for iOS) in the following way:
Add a extra container div for the scrolling part. Usually surrounding the scrolling part of your page. In my case right after the header and before the footer code.
Add the following CSS:
.extracontainer {
width: 100%;
height: 100%;
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
margin: 0;
padding: 0;
overflow: auto;
overflow-y: scroll;
-webkit-overflow-scrolling: touch;
}
Some of the CSS might be extra but in my case it was to avoid any issues with some other styles that I have using negative margins, paddings, etc.
Also make sure to have the -webkit-overflow-scrolling: touch; to have smooth scrolling.
I hope this helps.
$( document ).on( "mobileinit", function() {
var silentScroll = $.mobile.silentScroll;
$.mobile.silentScroll = function( ypos ) {
if ( $.type( ypos ) !== "number" ) {
// FIX : prevent auto scroll to top after page load
return;
} else {
silentScroll.apply(this, arguments);
}
}
}
For Jquery Mobile 1.4.5 i fixed that by changing this line in jquery.mobile-1.4.5.min.js:
a.mobile.hideUrlBar&&g.load(a.mobile.silentScroll)
to this:
a.mobile.hideUrlBar
Solution to prevent scrool to top is:
body onload="$.mobile.silentScroll(window.scrollY);"
try to use scrollstart to detect window scroll event in jquery mobile, in case you need :)

How can I disable a browser or element scrollbar, but still allow scrolling with wheel or arrow keys?

I want to hide any scrollbars from my div elements and my whole body, but still let the user scroll with the mouse wheel or arrow keys. How can this be achieved with raw JavaScript or jQuery? Any ideas?
Like the previous answers, you would use overflow:hidden to disable the scrollbars on the body/div.
Then you'd bind the mousewheel event to a function that would change the scrollTop of the div to emulate scrolling.
For arrow keys, you would bind the keydown event to recognize an arrow key, and then change scrollTop and scrollLeft of the div as appropriate to emulate scrolling.
(Note: you use keydown instead of keypress since IE doesn't recognize keypress for arrow keys.)
Edit: I couldn't get FF/Chrome to recognize keydown on a div, but it works in IE8. Depending on what you needed this for, you can set a keydown listener on the document to scroll the div. (Check out the keyCode reference as an example.)
For example, scrolling with the mouse wheel (using jQuery and a mousewheel plugin):
<div id="example" style="width:300px;height:200px;overflow:hidden">
insert enough text to overflow div here
</div>
<script>
$("#example").bind("mousewheel",function(ev, delta) {
var scrollTop = $(this).scrollTop();
$(this).scrollTop(scrollTop-Math.round(delta));
});
</script>
(This is a quick mockup, you'd have to adjust the numbers since for me, this scrolls a bit slowly.)
keyCode reference
mousewheel plugin
keydown, keypress # quirksmode
Update 12/19/2012:
The updated location of the mousewheel plugin is at: https://github.com/brandonaaron/jquery-mousewheel
What about a purely CSS solution?
Solution 1 (cross browser but more hacky)
#div {
position: fixed;
right: -20px;
left: 20px;
background-color: black;
color: white;
height: 5em;
overflow-y: scroll;
overflow-x: hidden;
}
<html>
<body>
<div id="div">
Scrolling div with hidden scrollbars!<br/>
On overflow, this div will scroll with the mousewheel but scrollbars won't be visible.<br/>
Scrollable<br>Scrollable<br>Scrollable<br>Scrollable<br>Scrollable<br>Scrollable<br>Scrollable<br>Scrollable<br>Scrollable<br>Scrollable<br>Scrollable<br>Scrollable<br>Scrollable<br>Scrollable<br>Scrollable<br>Scrollable<br>Scrollable<br>Scrollable<br>Scrollable<br>Scrollable<br>Scrollable<br>Scrollable<br>Scrollable<br>Scrollable<br>Scrollable<br>Scrollable<br>Scrollable<br>Scrollable<br>Scrollable<br>Scrollable<br>Scrollable<br>Scrollable<br>Scrollable<br>Scrollable<br>Scrollable<br>Scrollable<br>Scrollable<br>Scrollable<br>Scrollable<br>Scrollable<br>Scrollable<br>Scrollable<br>
</div>
</body>
</html>
Solution 2 (uses experimental features, may not support some browsers)
Just add the nobars class to any element you want to hide the scrollbars on.
.nobars {
/* Firefox: https://developer.mozilla.org/en-US/docs/Web/CSS/scrollbar-width */
scrollbar-width: none;
/* IE: https://msdn.microsoft.com/en-us/library/hh771902(v=vs.85).aspx */
-ms-overflow-style: none;
}
.nobars::-webkit-scrollbar {
/* Chrome/Edge/Opera/Safari: https://css-tricks.com/custom-scrollbars-in-webkit/ */
display: none;
}
Solution 3 (cross browser javascript)
Perfect Scrollbar doesn't require jQuery (although it can utilise jQuery if installed) and has a demo available here. The components can be styled with css such as in the following example:
.ps__rail-y {
display: none !important;
}
Here is a complete example including the implementation of Perfect Scrollbar:
<link rel="stylesheet" href="css/perfect-scrollbar.css">
<style>
#container {
position: relative; /* can be absolute or fixed if required */
height: 200px; /* any value will do */
overflow: auto;
}
.ps__rail-y {
display: none !important;
}
</style>
<script src='dist/perfect-scrollbar.min.js'></script>
<div id="container">
Scrollable<br>Scrollable<br>Scrollable<br>Scrollable<br>Scrollable<br>Scrollable<br>Scrollable<br>Scrollable<br>Scrollable<br>Scrollable<br>Scrollable<br>Scrollable<br>Scrollable<br>Scrollable<br>Scrollable<br>Scrollable<br>Scrollable<br>Scrollable<br>Scrollable<br>Scrollable<br>Scrollable<br>Scrollable<br>Scrollable<br>Scrollable<br>Scrollable<br>Scrollable<br>Scrollable<br>Scrollable<br>Scrollable<br>Scrollable<br>Scrollable<br>Scrollable<br>Scrollable<br>Scrollable<br>Scrollable<br>Scrollable<br>Scrollable<br>Scrollable<br>Scrollable<br>Scrollable<br>Scrollable<br>Scrollable<br>
</div>
<script>
// on dom ready...
var container = document.getElementById("container");
var ps = new PerfectScrollbar(container);
//ps.update(container);
//ps.destroy(container);
</script>
You dont have to use jquery or js to make this. Its more performant with simple webkit.
Just add the code below to your css file.
::-webkit-scrollbar {
display: none;
}
Caution !
This will disable all the scrollbar so be sure to put it in a specific class or id if you just want one to be hidden.
I much prefer SamGoody's answer provided to a duplicate of this question. It leaves native scrolling effects intact, instead of trying to manually re-implement for a few particular input devices:
A better solution is to set the target div to overflow:scroll, and wrap it inside a second element that is 8px narrower, who's overflow:hidden.
See the original comment for a fleshed-out example. You may want to use JavaScript to determine the actual size of scrollbars rather than assuming they are always 8px wide as his example does.
To get this working for me, I used this CSS:
html { overflow-y: hidden; }
But I had problems using $(this).scrollTop(), so I bound to my #id, but adjusted the scrollTop of window. Also, my smooth scrolling mouse would fire lots of 1 or -1 deltas, so I multiplied that by 20.
$("#example").bind("mousewheel", function (ev, delta) {
var scrollTop = $(window).scrollTop();
$(window).scrollTop(scrollTop - Math.round(delta * 20));
});
As Baldráni said above
::-webkit-scrollbar { display: none; }
Or you can do
::-webkit-scrollbar{ width: 0px; }
(posted for other people that stumble on this from google search!)
Well, perhaps not the most intuitive in my opinion, but I can imagine you being able to make it a decent experience, give this a try.
overflow:hidden;
make sure the parent object has a height and width, and displays as block

Categories