Recently I've been working on building a tree-view component library for Angular, as ngx-tree.
Problem
Soon after I figured out how to implement a virtual-scroll feature for this library for performance with large data set, and got it to run properly in Firefox, I am trapped by a weird scrolling behavior in Blink-included browsers(like Chromium, Chrome, Opera).
Demo link
Here is the demo plunkr -- https://embed.plnkr.co/xMpmK5EBC46tDKpYFpw8 see Update #1 below
Situation
In Firefox, Edge and IE 11, my library with virtual scroll feature works in expectation with smooth scrolling.
However, in Chrome and Opera, when I scroll to some positions inside the tree-view, the position of the scrollbar(which is the scrollTop property of scroll area) jump up and down, causes a flickering tree-view and break down the virtual-scroll feature.
browser detail version
Chrome - 59.0.3071.115
Firefox - 54.0
Edge - 40.15063.0.0
other browsers
In China, there are some shelled browsers derived from Chromium project(like 360se, QQ browser, Sogou browser, UC browser) with older version of V8 and blink. And they don't have that weird scroll behavior.
Some Assumption
Is it caused by some optimization on the scroll implementation(like smooth scrolling) by the Chromium team?
Hope to get some guides!!! (≧﹏ ≦)
Update #1
Demo link update with event log: https://embed.plnkr.co/GpQBZsguhZZOQWWbZnqI/
One must test the scrolling before opening devtool to see the logs
I have to explain a little more how the virtual-scrolling works and what's causing the flickering.
First, see the design of Virtual Scrolling.
A key point of virtual scrolling is, we create a fake scroll area the same size as that area without virtual scrolling instrumented. So in an optimal situation, the scrollbar position of the scroll area ought not to change until some expected events trigger its changes. For scroll event, we update the view for every animation frame.
Within a height-fixed scrolling area, we assume a truth that the scrollTop property will not change with a large percentage, if we simulate the those unrendered elements' height properly(there could be a bit of deviation for the calculation accuracy) within an animation frame.
However, based on my observed results, the blink-series browsers seems to perform a different strategy to update the scrollTop of the scrollable element. Its timing to update the scrollTop is different than none-blink-series browsers. That all I've figured out so far.
Sample gifs
Here I made some gifs to show the output of Chrome, Firefox, and Edge.
Chrome
Firefox
Edge
You're pulling the library from the virtual-scroll-demo-branch branch:
'ngx-tree': 'https://rawgit.com/e-cloud/ngx-tree/virtual-scroll-demo-branch/src/lib',
That branch is 105 commits behind master. It incorrectly sets margin-top on one of the inner elements. This is fixed in newer versions.
Edit: The developer actually referenced this Stack Overflow question in their commit message.
Related
I am using HTML5 Drag and Drop API to reorganize elements in a vertical list. The list is an overflow-y: scroll div. On macOS Chrome and macOS Firefox, if an item is dragged very close (~20px) to the inside edge of the container, the container is scrolled. This behaviour is not present on macOS Safari.
JSFiddle Demo
I am interested in how to implement a modified version of this behaviour for all modern browsers:
How to have a larger scroll activation region. On macOS Chrome it must be inside the container and is relatively small (20px). Preferably it could be increased to something like 15% of the container height.
Preferably the region would remain inside the list (so if you scroll outside the list the container is not scrolled)
How to disable the apparently undocumented Chrome scrolling behaviour. (Assuming it isn't possible to "enable" this feature on Safari, Edge).
Constraints:
A raw JavaScript / html / css solution is acceptable
I am using React, so a React library that works with raw JS HTML5 Drag n Drop would also be acceptable
No jQuery
Edit: Updated browser support description, updated JSFiddle to support macOS Firefox.
I have an issue with drag and drop on Chrome (v69.0.3497.100). Specifically, some of the drag and drop events are getting fired when Windows scaling is other than 100% even though they shouldn't be firing.
Check out stackblitz example, and try to drag "blue" rectangle over itself (just drag, move a little bit downwards and drop). If Windows scaling is set to 100% (browser zoom is 100% as well) then one event is fired (dragEnter) as expected (check the console). But, if Windows scaling is set to 125% (but browser zoom is still 100%) then three events are fired (two dragEnter and one dragLeave), and I expected only one event to be fired since the element was dragged and dropped on itself (as it was the case with 100% scale level).
It could be that since this is Windows zoom (and not browser's zoom) the left ("lightred") rectangle is larger that it appears, and it goes below right rectangle, and events are propagated to it, although I couldn't prove that since all elements have correct size in the inspector.
This doesn't seem to be happening in latest Firefox, IE or Edge.
Does anyone know why is this happening and how to fix it?
The more I look at this problem, the more it seems the Chromium issue. Some days ago I posted a question, then I wanted to set up a bounty for it, and then I found your one, and I believe they are interrelated: Subpixel scroll issue, can't set scrollTop properly on Chrome 69.
There are some bug reports in Chromium issue tracker related to scale-rounding problem: link 1, link 2... I also created my own bug: link 3. There should be more information but it takes too much time to research. I think we may join efforts and draw more attention to the problem, and for example if it's Chromium responsibility, to help them with clarification and prioritisation.
I have the same problem with Version 76.0.3809.100 (64-Bit).
And I offset the image to compensate for the strange offset that I get in your stackbliz example too.
But with scaling 200% I need to multiply my calculated dragImage offset by 4 !!!
On 300% it's at 9
On 350% it's at 12.25
Do you see the pattern ???!
I'm afraid of my hack/fix for this problem. Not sure if it's just on windows, if it's just desktop. But for now I guess I will have to do window.devicePixelRatio^2 so I can continue my work.
There are instances where a website has drag-and-drop features that will not work inside the Google Chrome browser.
Fixing Drag-and-Drop
Enter the following into the Google Chrome Top search bar.
Chrome Flags: chrome://flags/
Type Touch into the search bar and set the following options to Enabled.
In the following fiddle, there is significant jitter while scrolling. The jitter is noticed only in Safari on Mac, while Chrome and Firefox scrolls the page smoothly.
https://jsfiddle.net/saptarshi17/akxuLL9x/
The jitter is a result of applying parallax effect on the first paragraph. The parallax is implemented by dynamically calculating the top css property triggered by scroll events. I am noticing this on Mac OSX El Capitan, not sure about Windows.
So far, I tried:
Added a mousewheel event-listener in addition to scroll as per this accepted answer on SO.
Tried wrapping the css("top", ...) function call within requestAnimationFrame()
Changed div from relative to absolute to avoid costly reflows.
Added preserve3d property to "hardware accelerate" position calculation as per some comments somewhere on SO.
Since 2 and 3 haven't helped, I assume the core issue has much to do with Safari's scroll implementation and less about frame-rate optimizations. There is a delay Safari's predictive rendering and the subsequent handler call which offsets the position. This results in 2 renders causing the jitter. While I understand Safari's intention behind the first render which works in most cases, this seems to be wrong in cases when the developer wants to override positioning. Maybe there is a way to tell Safari to disable the predictive rendering.
I noticed that Safari is way slower at updating CSS element positions when they are changed in javascript.
For instance, we can fix an element's position to scrolling in 2 ways: via javascript and via the position: fixed CSS value, as illustrated in this Fiddle: http://jsfiddle.net/76tnuwmp/4/
In browsers like Chrome and Firefox, the user can't visibly see a difference in the 2 methods while scrolling.
However, in Safari, users can visibly see the lag in updating for the box fixed with javascript.
Is there something fundamentally different about how Safari updates element positions? Does it perhaps perform compositing and layering at a slower rate than other browsers do? Or is it just slow at one or more of these steps?
Chrome used to improperly exclude the scroll bar in its media queries. This means that with 1000px of visible space and a 17px scroll bar, other browsers would report 1017px as a width so far as Media Query is concerned, but webkit browsers (such as Chrome and Safari) did not do this.
These browsers could hit a specific size where a scroll bar would appear in one resolution, then change resolutions to another where it would appear, then it would go back to when it didn't... the solution caused an ugly blank space to appear where the scroll bar should, but it did not. It came out looking like a glitch, and the DOM resize events did not fire properly so it was not something you could react to properly in JS.
However, now in Chrome 29, this appears to have changed. Now they are going off of how the specification works and including the scroll bar in their media query calculations... just like Firefox and Internet Explorer (and how the specification says they should have all along). This fixes the bugs, but causes another problem in that the JS to try to detect the Chrome/Safari issue now will have false positives, because it is not a concern with newer versions of Chrome and I assume eventually Opera and Safari as well.
In light of all of this, I cannot find any information anywhere on when this was fixed in either Chrome or Webkit. I hate having to resort to browser version testing in my JS to work around these flaws, but I am just guessing blindly on Chrome 29+ for the moment as a temporary patch and would love an authoritative answer... I have tested in Safari 6.0.5, but the old method is still being used...
Does anybody know in what version of Chrome and/or Webkit this was fixed?
Chrome is no longer using the webkit engine as of Chrome v. 28 it now uses the Blink Rendering Engine. So no need to be detecting this for chrome unless you need it for previous versions.
For more on Blink: Blink Documnetation
For more on the Release: Next Web Article on Webkit/Blink Switch