My web page (with vanilla Javascript) accepts files dropped on to it from the native desktop. I want to change the cursor's appearance while dragging, to give users feedback about the progress of their drag (when they're on the drop zone, etc). This is easy if you're dragging an HTML element from within the same page, but I haven't found how to do it when dragging a file or image from elsewhere on the desktop.
I have tried setting a class on the body element and all its descendants (and there are no other cursor styles anywhere) but as you can see (from the attached edited screenshot)
it has no effect - the class and style are applied correctly (see debug tools view in the lower half of the image) but the cursor nevertheless takes its default appearance.
Relevant snippet of CSS:
.no-drop-cursor, .no-drop-cursor * {
cursor: no-drop;
}
and Javascript applies the class to the body element whenever the cursor is on my web page but outside the drop zone.
Is this in fact impossible - or is there some neat way to make it happen?
A couple of things to avoid unnecessary suggestions:
All relevant drag/drop event handlers already do preventDefault();
The actual drag/drop code works just fine, exactly as intended;
I already give visual feedback to users by highlighting the drop zone appropriately as the cursor moves into and out of it, but I would also like the cursor's appearance to change.
Any ideas appreciated, even if it's only a clear explanation of why I can't do that!
Edit 2022-08-16: This earlier question seems to be a duplicate, but received no useful responses.
Related
I know that this is not a 'good question' to poseābut I'm desperate by now and need to find some inspiration.
I have a questionnaire page/web-app that uses CSS transitions to slide to the next page of questions/options.
It is well-tested and the transitions in question aren't complex.
But the transition to one special page went out of control recently. And although I consider myself well versed in CSS and JavaScript I'm totally lost with this problem.
The construct in question works like this:
I have a 'window' that is positioned absolutely and has its overflow hidden.
Inside that is a page container positioned relative to no left or top values or transforms given.
The pages inside this container are positioned absolutely according to their status classes positioned on the left: 0 (active), left 100% (not yet shown), and left: -100% (already done)
What happens now is that when I switch classes to show a certain page, the page container 'jumps to the left'. In Chrome nearly -100% in Firefox about -70% same in Safari.
Those values are my guess because when I open the dev-tools, nothing is to be found in the styles, in the computed values anywhere.
When I move back to the previous page the container jumps back to its original position, and if I move again to the critical page it stays.
I do no positioning whatsoever with JavaScript anywhere, I only switch classes on HTML elements.
After hours of experimenting back and forth, I found out that the problem is in some way JavaScript-related anyhow.
Using the exact same CSS and HTML with a slightly older version of JavaScript does not show the strange behavior. The changes in the Script are mostly ES2020-module related, and the new version does nothing even remotely related to DOM manipulation different from the older working version.
When not using transitions, the shift of the container does not occur.
Has anyone come across something similar?
Does anyone know of other tools to deeper analyze the current layout state of a page more than the respective developer tools of the browsers?
Any other ideas?
Today I found a solution and at least some kind of explanation, but I still have to investigate some more to truly understand the why and how. I'll post an update if I find a better explanation.
The problem has to do with a text field and focus.
The page in question has a text (search) as its main component.
[I am aware and always was that browsers try to move focused elements into view, regardless of what the author's CSS says.
Therefore, when I decided to give focus to the text field which it does not have on its own, as every page movement required a button to be clicked, I did so on transitionend. This has never changed.
When the issue first occurred, one of the things I tried first was to disable that (auto) focus behavior. It did not solve the problem.
I cannot say what made that change in behavior happen. I change the construction of the page to include a grid some time before the issue occurred. That in itself was not the reason, however (it worked for quite some time with that system, and removing it did not sole the behavior).]
What solved the issue was to initially fully disable the text field and only enable it on transitionend (then focusing it).
The reason browsers moved the page to different positions likely has to do with this situation, as the text fields width is ch based.
The important takeaway (for now) for me is, that there is no hint to be found in the developer tools when the browsers moves - elements in the (in my case unsuccessful) attempt to keep inputs in the viewport.
I think that this should be changed/fixed.
I will as soon as I have the time try to better understand the things that made the problem occur, If someone has information or experience with similar situations pleas add useful hints and background info.
I am implementing a functionality where I can add, drag, and delete "sticky notes" on a webpage. The app is built in Vue js but it also renders content in an iframe. All the notes that are added to the page have to be on top of the iframe (which is almost 80% of the main .vue page), therefore positioning here is important and I also have to preserve the positions because I must render the notes on the same position on next page reload. The problem is that there's a lot of lag in dragging the "note" element.
The "sticky note" itself is a very lite weight separate component.
I have noticed that this because of the iframe that's present on the vue page because when I inspect the DOM in the browser and delete the iframe and then try dragging the "note" component then it works smoothly.
Things I have tried:
Use throttling: I tried to use loadsh.throttle but that does not make any difference.
Inject "sticky note" code inside the iframe: I tried to inject a sticky note element into the iframe and append it to iframe's body. It actually makes the dragging very smooth. But I don't want to go ahead with this solution because then I will have to write a lot of extra code to maintain the state of multiple notes (which can be done easily with Vue js).
In this solution, instead of using the document of the main page to attach events for dragging, I attached all the events to iframe.contentDocument.
So the question here is how do I make the drag smooth while using vue.js
Sandbox Link: https://codesandbox.io/s/affectionate-jang-3c1hw?file=/src/components/HelloWorld.vue
In this gif, the background is actually the iframe, I have reduced its opacity to hide it.
I could not actually include the iframe in sandbox code because of cross-origin problems but I have included a lot of extra content in that sandbox to make it heavy.
UPDATE:
Using the chrome task manager, I found that the page is only taking max 200MB memory and the GPU process is taking another 200MB. I am running this on a system with 16GB RAM. So I don't think it's a memory issue. But there is a sudden spike in the CPU consumption when I start dragging the element (up to 40%).
UPDATE:
I have found the fix for this problem. The actual problem wasn't lag but it was mouse trailing i.e. the draggable element wasn't able to catch up with the fast moving mouse cursor. And the slowness was due to e.preventDefault in the dragMouseDown method inside Note.vue. Just removing the e.preventDefault fixed all the problems. Also just adding a return false at the end of dragMouseDown method seems to cause the same amount of lag.
function dragMouseDown(e) {
e = e || window.event;
// e.preventDefault(); --> this line causes the mouse trailing issue
document.onmouseup = closeDragElement;
document.onmousemove = elementDrag;
// return false; --> adding this line also causes mouse trailing problem.
}
So for now I have just removed the preventDefault from this function. But I tried searching and could not find any explanation of this behavior. Also I am not sure if not cancelling the event can cause any other issue.
The problem is that you're working with mousemove without using requestAnimationFrame to debounce. Here's a working example using debounce (CodeSandbox link)
Generally, anytime you're trying to animate with javascript, you want to use requestAnimationFrame. Another thing you could try is using transform to change the position of the element instead of absolute positions.
Here's the MDN reference on requestAnimationFrame.
Here's an article by Paul Irish about using transform instead of absolute positioning to speed up a drag/drop.
As your extra description in the comments,
It starts to lag when these a lot of other content on screen. There's
a v-for in the sandbox. make it do more iterations and it will start
to laggy
The problem you met is the Dom elements were too many on your page then caused high memory usage. (Actually I tried <div v-for="i in 10000" :key="i">", then it took around 3GBs of memory), finally, everything works slowly and laggy
If your page has tons of Dom elements, you may have to consider dynamically add only visible items into the Dom tree when scrolling.
Even there are some packages that already implements this feature.
Below is one demo which uses RecycleScroller of vue-virtual-scroller:
100K items in the Codepen
You will see even the number of the items are 100,000, it still works smoothly.
PS: you may notice the below statement in the user guide of the above package=vue-virtual-scroller
The browsers have a size limitation on DOM elements, it means that
currently the virtual scroller can't display more than ~500k items
depending on the browser.
Is there any way to prevent Firefox from rendering a ghost image that is way smaller than the source element when dragging large elements?
I've created a sample page and video, if you do not understand what I'm talking about.
This downsized ghost-image is problematic in applications where the user is dragging a large element to an absolute position; when the user tries to drop the dragged element to an exact location, it doesn't drop where they're trying to drop it. Only after several blind attempts, can they place the dragged element exactly where they want it.
In Chromium 69, the element drops exactly where the user tries to drop it, because the ghost image is exactly the same size as the source element.
If you can think of additional reasons against this default behavior in Firefox, please voice them at the bug I've submitted here.
In the meantime, I'm looking for a work-around.
The ghost image is ideal, because it looks exactly like what's being dragged. I know its possible to have custom drag-images, but I can't think of a way to make that custom image look exactly like the element being dragged (like the ghost image achieves).
I may have to settle for just making a generic image that can at least be sized correctly during drag and drop. Any other ideas?
Perhaps the title isn't great, but I had a little trouble with the wording...
Basically, is it possible to have jQuery's hover only fire over the actual content of a png with an alpha channel.
So in the image below;
http://i.imgur.com/3kO7v.png
Only fire on the rectangle and not the alpha channel which make up the rest of the document bounds...
I've tried the obvious $('obj').hover(function(){stuff}) but this fires on the alpha channel too...
The final implementation of this will be for more complex shapes than just a rotated square, so css3 tricks are out for the primary basis, but could be used with a back-up/shim, plus I need to support IE7 and ipad,iphone,ipod....
If there is a CSS2 solution then that would be suitable too. Also any real guidance on this issue is more than welcome.
My backup for this will be to have an empty div, display block and position it over the shape and then use that. This will obviously not be ideal for the less square objects.
Any hits or tips are more than welcome.
Thank you
Yes it is possible depending on the stacking context of your elements. Keep in mind that when you do a focus over any particular element on a page, that you are actually focusing all other elements within the same stacking context.
So what you could do is either stop the event from bubbling up the stack (if the element you want to "hover" is lower in the stack that the elements you want to prevent hover effects on), or specifically put in prevent default for onhover events for all elements in the stacking context except for the one you want to actually get a hover effect.
is it possible for positioned content to overlap the edge of the document window that contains it? E.g. if I have a popup inside a popup, can the latter overlap the window borders of the former?
I have noticed that very long tool-tip bubbles created using the HTML TITLE attribute do overlap, but never seen a CSS or JavaScript bubble that does that.
E.g. this is a pure CSS bubble demo:
http://trentrichardson.com/examples/csstooltips/
If I resize the window so that it is quite small and then hover on the second link, I get a long tool-tip that gets clipped against the window, not what I want.
Basically, it's not possible. The tooltip generated by the title attribute are created as operating system elements, and are outside of the browser window.
On the other hand, anything you create using Javascript will be part of the web page, and thus contrained by limits of the the browser window.
There is nothing you can do about this. Sorry.
(I note that #easwee's comment links to a question where an answer is given which does provide a solution, however it is an IE-only solution and will break in any other browser)