Remove scrollbars from sidebar - javascript

I'm trying to emulate a nice scrollbar that i saw on the website https://doughellmann.com/blog/. (You must be on a screen bigger than 955px to view the sidebar) However, my sidebar is fixed and if it overflows in the y direction a side bar appears so on the screen you have two scroll bars - One for the sidebar and the other for the page. However, I don't want that. I want the user to go the bottom of the sidebar and then fix it self like it did on this webiste. Here's how my code looks right now
.sidebar{
display: block;
background-color: #1056b1;
width: 30%;
height: 100%;
position: fixed;
display: flex;
flex-direction: column;
align-items: center;
overflow-y: scroll;
}
.content-on-the-right{
margin-left: 31%;
}
Does anybody know how i could solve this problem using vanilla javascript or reactjs or even css if that's possible?

I'm sure there's a more efficient way to do this but I believe this will get you started on getting what you want. For this example, let's say your sidebar has an id of sidebar.
When the window loads, you can add an EventListener that will call a function that will check the elements offsets. You can take it from there:
window.addEventListener("scroll", DoScroll, false);
function DoScroll() {
var sidebar = document.getElementById('sidebar');
var sidebarHeight = document.getElementById('sidebar').offsetHeight;
var winHeight = window.innerHeight;
var offset = sidebarHeight - window.pageYOffset;
if (offset < winHeight) {
sidebar.style.position = "fixed";
sidebar.style.bottom = 0;
} else {
sidebar.style.position = "static";
}
}
Here's my JSFiddle that demos this.
P.S. I know the name of the function kinda sucks but am a bit burned out... you can give it a more descriptive name.

Related

How to update sticky menu's CSS positioning on window resize

I've built a sticky navbar based on an example from W3 schools. It's working very well — except when I resize the window, the alignment of the nav menu to the page content is incorrect.
You'll see that I've got some code that finds the correct offset for left side of menu, by checking another element on the page. It then adds some left padding to align it properly. (Without this, the position:fixed value just sends the sticky nav to the far left of the page).
This works great on scroll! However, if the window is resized horizontally, that left padding value doesn't update.
I've tried a few iterations of $(window).resize but haven't been able to get it to work. I'm sure it's an easy line of code I'm just not figuring out. Thanks in advance!
setTimeout(function () {
// When the user scrolls the page, execute myFunction
window.onscroll = function() {myFunction()};
// Get the navbar
var navbar = document.getElementById("app");
// Get the offset position of the navbar
var sticky = $("#app").offset().top
// Find correct offset for left side of menu (by checking #title element)
var element = document.getElementById('title');
var leftPos = element.getBoundingClientRect().left + window.scrollX;
var roundLeft = (Math.round(leftPos)) - 5;
// Add the sticky class to the navbar when you reach its scroll position. Remove "sticky" when you leave the scroll position
function myFunction() {
if (window.pageYOffset >= sticky) {
navbar.classList.add("sticky")
navbar.style.cssText = "padding-left:" + roundLeft + "px!important";
} else {
navbar.classList.remove("sticky");
navbar.style.cssText = "padding-left:inherit";
}
}
}, 4000);
.sticky {
position: fixed;
top: 0;
width: 100%;
background: rgba(255, 255, 255, 0.99);
z-index: 9 !important;
max-width: none !important;
box-shadow: 0px 1px 10px #999;
}
(I'm using setTimeout because our Shiny app takes a few seconds to load and for the content to populate.)
You should use pure CSS solution with position: sticky
It does have acceptable percentage of browser support:
https://caniuse.com/#feat=css-sticky
Since it's just the styling, it may be fine to show it static in the old browsers.

Pinning Elements with Debounced Scroll Event for Performance

What is the right way to smoothly pin an element according to scroll position?
I tried debouncing a scroll listener for performance but the pinning is not accurate. Even with debouncing set to 10ms it's not smooth and the element doesn't snap cleanly to its initial position.
var scrolling = false;
var stickPosY = 100;
var heights = [];
$(".element").each( function(index) {
heights[index] = $(".element[data-trigger=" + index + "]").offset().top;
});
function pin() {
if ( !$("#aside").hasClass("fixed") ) {
var stickyLeft = $("#aside").offset().left;
var stickyWidth = $("#aside").outerWidth();
var stickyTop = $("#aside").offset().top - stickPosY;
$("#aside").addClass("fixed");
$("#aside").css({"left": stickyLeft, "top": stickyTop, "width": stickyWidth});
}
}
function unpin() {
$("#aside").css({"left": "", "top": "", "width": ""});
$("#aside").removeClass("fixed")
}
$( window ).scroll( function() {
scrolling = true;
});
setInterval( function() {
if ( scrolling ) {
scrolling = false;
var y = window.scrollY;
console.log(y);
// PIN SIDEBAR
y > stickPosY ? pin() : unpin();
//TRIGGERS
for (var i=0; i < heights.length; i++) {
if (y >= heights[i]) {
$('.element[data-trigger="' + i + '"]').addClass("blue");
}
else {
$('.element[data-trigger="' + i + '"]').removeClass("blue");
}
}
}
}, 250 );
Here's my Pen
I tried to use scrollMagic for the project on a scene with a pin and additional triggers but the scrolling wasn't very smooth. So I'm trying to rebuild it with a stripped-down version and debounced listeners. Is this approach possible, or should I rather try to optimize my scrollMagic scene?
As James points out, you can just use position: sticky as one option, but that doesn't work in older browsers and its uses are limited to simpler situations in newer browsers, so I'll continue with the JS solution assuming you want to go that route.
There is a lot going on in your JS, and I think you are probably overcomplicating things, so I will give you a few basics to consider.
When you are toggling things based on scroll, either toggle inline styles or a class, but not both. I would recommend toggling a class because it allows you to have one function that can work on multiple screen sizes (i.e., you can use media queries to change the behavior of your toggled class based on screen size). Also it keeps all your styles in one place instead of having them split between your JS and your stylesheet.
Try to keep the work you're doing while scrolling as minimal as possible. For example, cache references to elements in variables outside your scroll function so you're not continually looking them up every time you scroll a pixel. Avoid loops inside scroll functions.
Using setInterval is not generally the recommended approach for increasing performance on scroll functions. All that is going to do is run a function every X amount of time, all the time, whether you're scrolling or not. What you really want to do is rate-limit your scroll function directly. That way, if you scroll a long ways real fast your function will only be called a fraction of the total times it would otherwise be called, but if you scroll a short distance slowly it will still be called a minimum number of times to keep things looking smooth, and if you don't scroll at all then you're not calling your function at all. Also, you probably want to throttle your function in this case, not debounce it.
Consider using the throttle function from Underscore.js or Lodash.js instead of inventing your own because those ones are highly performant and guaranteed to work across a wide variety of browsers.
Here is a simple example of sticking an element to the top of the screen on scroll, throttled with Lodash. I'm using a 25ms throttle, which is about the maximum amount I'd recommend for keeping things looking smooth where you won't really notice the delay in the element sticking/unsticking as you scroll past your threshold. You could go down to as little as 10ms.
$(function() {
$(window).on('scroll', _.throttle(toggleClass, 25));
const myThing = $('#my-thing');
const threshold = $('#dummy-1').height();
function toggleClass() {
const y = window.scrollY;
if (y > threshold) {
myThing.addClass('stuck')
} else {
myThing.removeClass('stuck');
}
}
});
#dummy-1 {
height: 150px;
background-color: steelblue;
}
#dummy-2 {
height: 150px;
background-color: gold;
}
#my-thing {
width: 300px;
height: 75px;
background-color: firebrick;
position: absolute;
top: 150px;
left: 0;
}
#my-thing.stuck {
position: fixed;
top: 0;
}
body {
margin: 0;
height: 2000px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.0.0/lodash.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="dummy-1"></div>
<div id="dummy-2"></div>
<div id="my-thing"></div>
You could try fixed or sticky CSS positioning:
#element {
position: fixed;
top: 80px;
left: 10px;
}
Position: fixed would keep the element always at 80px from the top and 10px from the left edge regardless of scroll position.
#element{
position: sticky;
top: 0;
right: 0;
left: 0;
}
This is from a project of mine. The element is a nav bar. It sits below a header bar, so when you are at the top of the page, you see the header then the nav below it, and as you scroll down, the header moves off screen but the nav sticks at the top and is always visible.

make div scoll untill it reaches top of page then fixed

let's get straight to the point:
My code looks like the following:
<div id="keep_up">
<div id="thread_menu">
<div id="new_thread">
</div>
</div>
</div>
And my css:
#keep_up {
position: fixed;
width: 13%;
}
#thread_menu{
height: 80vh;
width: 100%;
float: left;
position: relative;
}
Now i use this for a forum. and this is basically to show the active and new threads on the side of the screen.
However. When watching a thread, the header disappears (Wich makes sense because we are scrolling down).
but i want the thread menu to stay on my side (So that it is always visible). In this case that is happening because my keep_up div has position: fixed. But i only see half of the thread menu becuase it is too long and won't scroll up.
My question:
I want the thread menu to scroll up, untill it reaches the top of my window. From then on i want it to stay there.
How do i do this?
I saw a few examples but none of them worked for me.
EDIT: Code i tried:
<script src="jquery.min.js">
$(window).scroll(function () {
var margin = null;
$(window).on("scroll", function () {
var scrollHeight = $(document).height(),
scrollTop = $(window).scrollTop(),
offsetBottom = 110, // Offset depending on the height of the footer
offsetTop = 100, // Offset depending on the height of the header
positionTop = $(".keep_up").offset().top,
affix;
if (margin != null && (scrollTop + margin <= positionTop)) {
// The sidebar has reached the bottom and is still on the bottom
affix = false;
} else if (positionTop + $(".keep_up").height() >= scrollHeight - offsetBottom) {
// The sidebar has reached the bottom
affix = 'bottom';
} else if (scrollTop <= offsetTop) {
// The sidebar has reached the top
affix = 'top';
} else {
// The sidebar is midway
affix = false;
}
// If the sidebar hasnot changed his state, return;
if ($(".keep_up").hasClass('at' + (affix ? '-' + affix : ''))) return;
if (affix == 'bottom') {
margin = positionTop - scrollTop;
} else {
margin = null;
}
// If the related class is added to the div
$(".keep_up").removeClass('at at-top at-bottom').addClass('at' + (affix ? '-' + affix : ''))
});
});
</script>
And the CSS:
.keep_up{
/*position: fixed;*/
width: 13%;
}
.keep_up.at {
top: 1px;
position: fixed;
}
.keep_up.at-top{
}
.keep_up.at-bottom {
top: 438px;
position: absolute;
}
modify this on HTML:
<div id="prevent"></div>
<div id="keep_up" data-spy="affix" data-offset-top="200">
Add this CSS:
.affix{position: fixed !important; top:0px; z-index:999;}
.affixpatch{margin-top:100px !important;}
this will fix the div when you scroll down 200px. Change data-offset-top value to reach it on different break point.
.affixpatch is a class that will be loaded with next jquery function. it prevents to hide content behind top fixed div. Change margin-top to another value if this don't solves the "hide content" problem that always generate affixing divs.
<script>
$(function() {
//caches a jQuery object containing the header element
var header = $(".affix");
$(window).scroll(function() {
var scroll = $(window).scrollTop();
if (scroll >= 200) {
$('#prevent').addClass("affixpatch");
} else {
$('#prevent').removeClass("affixpatch");
}
});
});
</script>
Hope it helps. If not, you may have some class that rewrite or impede the correct function of this affix.
I've tested this hundreds of times, usually to fix navbars.
SCROLL:
Using overflow to scroll content:
#keep_up{
max-height:400px;
width: auto;
overflow:auto;}
This will scroll the content inside #keep_up div (or use it in another one)
NOTE: you must declare a fixed max height for this div. Set max-width only if you need.
You can use %, em, rem... no need to be px for fix the max witdth. (to get a responsive effect, use responsive measurements)
If I understand your scenario correctly, the way to do this might be to use jQuery (or native JS, but you've tagged jQuery so I'm assuming that's in play).
There's a plugin that handles this kind of thing: http://leafo.net/sticky-kit/
I'd suggest you look at the plugin source code to see how it works - an event handler function on $(window).scroll() which then toggles classes on your #thread_menu to fix it in place. To keep your code lightweight, you probably don't need everything the plugin provides.

Mobile - overflow-y: hidden does not stop the body element from scrolling

This is a common issue I have found on Mobile. I have been unable to find a solid answer yet.
I won't accept the following as they don't work completely (tested):
Adding the following to the body and html tags
This does work but causes the page to jump to the top. You can break it in Safari if you turn landscape and get the browser toolbar to show on scroll
.noScroll {
height: 100%;
overflow-y: hidden;
}
Adding the following to the body tag
This does work but causes the page to jump to the top.
.noScroll {
height: 100%;
overflow-y: hidden;
position: fixed;
}
A combination of JS and CSS
You can break it in Safari if you turn landscape and get the browser toolbar to show on scroll. This method solves the jump issue
.noScroll {
height: 100%;
overflow-y: hidden;
position: fixed;
}
var body = document.body,
lastTop = 0,
startScroll,
stopScroll;
startScroll = function () {
body.style.top = '';
body.scrollTop = lastTop;
};
stopScroll = function () {
lastTop = document.body.scrollTop;
body.className = 'noScroll';
body.style.top = '-' + lastTop.toString() + 'px';
}
I have tried other methods but they don't work either. You can disable touchmove on the body tag but it does not allow you to scroll anywhere e.g.
document.body.addEventListener('touchmove', function () { return false; });
Is there anything I can do.
A JS scrollbar is the only proper fix at the moment.
Cheers

Re-sizing the webpage content

In my project I have a webpage which has 2 div areas right and left. The left div takes almost 60% of the whole page width and the right one takes around 36% of the page. I wanted to resize the both div areas in a proper ratio when I shrink the browser from the right side or left side. The UI is getting generated from Javascript. This is the code.
boardHolderPadding = $board.outerHeight() - $board.height();
$board.height(viewportHeight - siblingsHeight - boardHolderPadding);
this.$('#board .droptarget').setWidthAsRatioOfHeight(this.options.ratio);
$('#sidebar').width($(window).width() - $board.find('#board').width() - 50);
I tried with JQuery resize plugin but couldnt get the proper result I'm looking for. Anyone have suggestion?
Thanks
See jsfiddle example but I think you just need to set your widths as percentages rather than trying to calculate them - note display is set to inline-block
<div>
<div class="small-left-column">this is the left column</div>
<div class="large-right-column">this is the right column</div>
</div>
<style>
.small-left-column {
width: 30%;
background-color: #aeaeae;
display: inline-block;
}
.large-right-column {
width: 60%;
background-color: #aeaeae;
display: inline-block;
}
</style>
So I think for your example your would have something like this
$(document).ready(function () {
$('#sidebar').addClass('small-left-column');
$('#board').addClass('large-right-column');
});
Maybe you're looking for the pure-Javascript version of the above:
$(document).ready(function () {
$('#sidebar').css( {
width: '30%'
backgroundColor: '#aeaeae',
display: 'inline-block'
});
$('#board').css({
width: '60%',
backgroundColor: '#aeaeae',
display: 'inline-block'
});
});
I did it in a different way in Javascript and I hope this will help someone to fix if they come across an issue like that
relativeSize : function(width, height){
var boardWidth = this.$("#board").width(),
boardHeight = this.$("#board").height(),
newcard = this.$("#newCard").width(),
space = width - boardWidth - newcard;
ratio = space / width * 3; //used to increment the ratio with 3 as the ratio is very tiny value, this will help to increase minimizing size
bheight = boardHeight - 25; // used to reduce the height by 25px, u can use any amount to match ur ratio
var relHeight = (space < ratio) ? bheight : height;
return relHeight;
}
Thanks

Categories

Resources