ReactJS: element.ScrollLeft does not change value after resizing window - javascript

I have a state called scrollStatus, where I track the current scroll position of a div, and I set its value using a ref and element.scrollLeft when scrolling:
const scrollHandle = () => {
setScrollStatus(container.current?.scrollLeft);
console.log(scrollStatus);
}
So when doing console.log I get a different value of scrollStatus, which is what I want:
When I resize the window by a large margin (let's say from desktop to mobile view), the scroll value will change drastically, which I expected for it to happen since my container's width is percentage based.
Here in the console, you can see the value changed to 375 after I resize the window to mobile view:
However, when I try to scroll again after resizing the window, the value of scrollStatus doesn't change. It retains the current position value after I resize the window:
(The value still won't change even if I resize the window again)
Any idea what's going on here and how to fix it?

Related

wheel Event Reliability

I'm working on a web project that has animations and page changes on the scroll ( specifically, scroll direction ) and I've been looking for multiple possible good and reliable solutions.
I've been detecting the scroll direction by detected the window's scrollY with the user's previously saved scrollY that I have saved in a variable. The only problem is that the scroll event doesn't fire when at the top or the bottom of page, even though the content is all absolute/fixed positioned.
I want to turn to the wheel event because of its deltaY values from the event, and it still fires when at the top of bottom of the page so I can remove the scrollbar and keep the body of the page 100vh.
The Mozilla dev docs say:
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.
(https://developer.mozilla.org/en-US/docs/Web/API/Element/wheel_event)
And I'm also curious if the wheel event will work correctly on mobile with touch?
Here's a good example of what I'm trying to replicate: https://reed.be
There is no scrollbar, yet things still happen based on your scrolling.
CanIuse shows full compatibility of the wheel event with modern browsers, and some older versions.
see here -> https://caniuse.com/#feat=mdn-api_wheelevent
I've found a solution that references the wheel event (How to determine scroll direction without actually scrolling), though my question still applies -
How reliable is the wheel event across devices and browsers, including mobile?
I am limited to my own current version browsers and android devices for testing.
You can fool the browser by setting the additional height on the body to match the content width and setting the overflow to scroll. Then use some basic script, to set the scrollLeft property of your container to equal the window scrollY.
You will need to set the height of the body equal to the total width of the panels.
body {
height: 400vh; // 4 panels of 100vw each
...
}
.panel {
width: 100vw;
...
}
JS
const viewPort = document.querySelector('#viewport');
let lastScroll = 0;
window.addEventListener('scroll', (e) => {
let scrollY = window.scrollY;
// scroll the container by and equal amount of your window scroll
viewPort.scrollLeft = scrollY;
lastScroll = scrollY;
});
Rough JSFiddle Demo

How to set scrollTop properly when scrolling with keys in div to keep selected item at same position

I'm trying to create my own input+dropdown control from scratch (in vue.js, though not relevant). I want to use mouse or keyboard for scrolling down the list of items.
For that I'm using a div with a fixed height and overflow-y and in that div, for each item, I use another div. When scrolling with the keyboard, I keep track of the selected item and use that to set the scrollTop position of the div, so that the scroll bar moves with the keyboard input and the selected item stays visible in the middle of the div. Here is the sample in fiddle https://jsfiddle.net/ce6k2a3j/11/
But the part I'm having issues with is setting the .scrollTop property when there are a lot of items in the list and there is some kind of scaling.
setScrollPosition () {
if(+this.keyIndex >= 6){
this.$refs.testMainDiv.scrollTop = (+this.keyIndex - 6) * +this.$refs.testItemDiv[+this.keyIndex].clientHeight;
}
else{
this.$refs.testMainDiv.scrollTop = 0;
}
},
My problem is that, in Windows 10, if I change the scaling of my display to 125% (since I use a 4k monitor), scrolling all the way down the list will move the selected item slightly up each time the key.down fires. Is there a way to make this scale proof ? It also happens when using page zoom.
this is what happens:
In case of transforms, the offsetWidth and offsetHeight returns the element's layout width and height, while getBoundingClientRect() returns the rendering width and height.
MDN: Determining the dimensions of elements
So, in this case clientHeight has the same result as offsetHeight. You neeed to use getBoundingClientRect().
setScrollPosition () {
if(+this.keyIndex >= 6){
this.$refs.testMainDiv.scrollTop = (+this.keyIndex - 6) * this.$refs.testItemDiv[+this.keyIndex].getBoundingClientRect().height;
}
else{
this.$refs.testMainDiv.scrollTop = 0;
}
}
I tested it with the browser scaling and it works, you try it with your display scaling and let's see.

How to get parent window scrollTop in Chrome?

Inside the iframe scope, this works in other browsers:
$(parent.document.documentElement).scrollTop()
In Chrome it returns zero (always). Anyone knows the catch?
In backstage: I need to center modal dialog on screen (fixed position), but I cannot set correct margin top without parent window scrollTop.
In Chrome, document.documentElement.scrollTop is always 0. The actual scroll value is in document.body. Discussed here: https://code.google.com/p/chromium/issues/detail?id=157855
You should use:
var parentScrollTop = $(parent.document.documentElement).scrollTop() || $(parent.document.body).scrollTop();

Update div height calculated with js on window resize

The code to make a div height equal to its width below:
$('div').height($('div').width());
However if you manually resize the browser window the height will not update - you need to refresh the page. Any idea how to correct it?
You need to bind your code on the window.onresize event :
window.onresize=function(){
$('div').height($('div').width());
};
The doc : http://www.w3schools.com/jsref/event_onresize.asp

Using Javascript to resize a div to screen height causes flickering when shrinking the browser window

The Background:
I tried to solve the StackOverflow question yet another HTML/CSS layout challenge - full height sidebar with sticky footer on my own using jQuery. Because the sidebar in my case may be longer than the main content it matches the case of comment 8128008. That makes it impossible to have a sidebar longer than the main content and having a sticky footer without getting problems when shrinking the browser window.
The status quo:
I have a html page with a div, which is automatically stretched to fill the screen. So if there is empty space below the element, I stretch it downwards:
But if the browser viewport is smaller than the div itself, no stretching is done but the scrollbar shows up:
I've attached jQuery to the window's resize event to resize the div, if the browser window is not to small and remove any resizing in the other case. This is done by checking if the viewport is higher or smaller than the document. If the viewport is smaller than the document, it seems like the content is larger than the browser window, why no resizing is done; in the other case we resize the div to fill the page.
if ($(document).height() > $(window).height()) {
// Scrolling needed, page content extends browser window
// --> No need to resize the div
// --> Custom height is removed
// [...]
} else {
// Window is larger than the page content
// --> Div is resized using jQuery:
$('#div').height($(window).height());
}
The Problem:
Up to now, everything runs well. But if I shrink the browser window, there are cases, where the div should be resized but the document is larger than the window's height, why my script assumes, that no resizing is needed and the div's resizing is removed.
The point is actually, that if I check the document's height using Firebug after the bug appeared, the height has just the value is was meant to have. So I thought, the document's height is set with a little delay. I tried to run the resize code delayed a bit but it did not help.
I have set up a demonstration on jsFiddle. Just shrink the browser window slowly and you'll see the div "flickering". Also you can watch the console.log() output and you will notice, that in the case of "flickering" the document's height and the window's height are different instead of being equal.
I've noticed this behavior in Firefox 7, IE 9, Chrome 10 and Safari 5.1. Can you confirm it?
Do you know if there is a fix? Or is the approach totally wrong? Please help me.
Ok -- wiping my old answer and replacing...
Here's your problem:
You are taking and comparing window and document height, without first taking into consideration the order of events here..
Window loads
Div grows to window height
Window shrinks
Document height remains at div height
Window height is less than div height
At this point, the previously set height of the div is keeping document height greater than the window height, and this logic is misinterpreted:
"Scrolling needed, no need to extend the sidebar" fires, erroneously
Hence the twitch.
To prevent it, just resize your div along with the window before making the comparison:
(function () {
var resizeContentWrapper = function () {
console.group('resizing');
var target = {
content: $('#resizeme')
};
//resize target content to window size, assuming that last time around it was set to document height, and might be pushing document height beyond window after resize
//TODO: for performance, insert flags to only do this if the window is shrinking, and the div has already been resized
target.content.css('height', $(window).height());
var height = {
document: $(document).height(),
window: $(window).height()
};
console.log('height: ', height);
if (height.document > height.window) {
// Scrolling needed, no need to externd the sidebar
target.content.css('height', '');
console.info('custom height removed');
} else {
// Set the new content height
height['content'] = height.window;
target.content.css('height', height['content']);
console.log('new height: ', height);
}
console.groupEnd();
}
resizeContentWrapper();
$(window).bind('resize orientationchange', resizeContentWrapper);
})(jQuery);
Per pmvdb's comment, i renamed your $$ to "target"
$(window).bind('resize',function(){
$("#resizeme").css("height","");
if($("#resizeme").outerHeight() < $(window).height()){
$("#resizeme").height($(window).height());
$("body").css("overflow-y","hidden");
}else{
$("body").css("overflow-y","scroll");
}
});
Maybe I am misunderstanding the problem, but why are you using Javascript? This seems like a layout (CSS) issue. My solution without JS: http://jsfiddle.net/2yKgQ/27/

Categories