Preventing cursor change on link click in Chrome - javascript

Clicking on a link in Chrome (not Safari or Firefox) changes the cursor from pointer to arrow. Can this behavior be prevented? I.e., is it possible to still have the pointer after clicking, but while the cursor is still hovering over the link?
EDIT: Okay so I've done a little more testing. First of all, the only reason anyone would want the cursor to remain as a pointer after clicking on a link is if the link does not actually load another page but rather fires a JS event instead.
Test
// JQuery
$("a").click(function(event) { event.preventDefault(); }
With the above code, event.preventDefault (or returning false) will allow the cursor to remain a pointer after click. This will suffice for most uses, namely triggering a DOM manipulation and/or AJAX request.
The problem is with history.pushState():
Test
// JQuery
$("a").click(function(event) {
history.pushState(arg1, arg2, url);
event.preventDefault(); return false;
}
Here the pointer DOES change to an arrow. Any ideas on how to stop that from happening?

This sounds like a CSS issue. Look for code like the following:
::-webkit-any-link:hover,
::-webkit-any-link:active { cursor: pointer; }
This will affect all links (like a[href]) but only in WebKit. Perhaps something else is preventing Safari from doing this.
UPDATE GIVEN EXPANDED QUESTION:
Now that we know more about the problem, namely that the cursor changes back to a pointer after clicking on an element fires off a javascript, I would say that this is a Chrome bug.
Please file a report at http://bugs.chromium.org/

You could explicitly set your target element's CSS to include --
#element {
cursor: pointer;
}
See http://www.quirksmode.org/css/cursor.html#note if you have to support IE 5.5.

In the meantime I'm thinking this desperate workaround:
Browser detect Chrome
Apply this tutorial

Related

Trigger native browser behavior for (middle) click on a link

Question
I want to trigger a (middle) mouse click on a link, in a way that triggers the native browser behavior for this event.
E.g. in those browsers I work with, middle-click will cause the linked page to open in a new tab in the background.
But if other browsers have a different behavior, that should be triggered instead.
I know there is the element.click(); method, but how do I tell it which mouse button should be clicked?
Background
The background is that I want to make a div behave as much as possible like a regular link. The idea was that I would create a hidden link tag and trigger the native browser behavior.
Requirements for the div-as-a-link:
href can come from a data-href attribute.
Native browser behavior for left-click, middle-click and possibly right-click.
respect of the target attribute, which could come from a data-target attribute.
tabindex
activation with the keyboard?
possibility to select text snippets within the div. This means we cannot just use an overlay.
Why not use a native link tag? Because the div contains inner <a> tags. So making the div box an a-tag would cause nested a-tags which would cause some browsers to restructure the DOM tree.
Obviously I could just set document.location.href on click. But this is only 20% of the browser's native behavior.
I could also try to detect the mouse button, and use js to open the tab in the background, if it was the middle button.
But maybe some browsers have a different behavior for middle-click. I would rather let the browser do its thing, than trying to replicate a specific browser behavior with js.
The idea I had was to create a hidden <a> tag with the same href, and delegate click events from the <div> to this hidden <a> tag. For this, I need to trigger the event with the same mouse button. I am not sure how to do this.
js or jQuery?
jQuery is ok for my personal use case. But to make this useful to a wider audience, maybe also post how to do it without jQuery, if you know.
See also
There are some question which deal with this kind of problem, but each of them looks at a different angle or has different constraints.
This is what I come up with thanks to #JonUleis in the comments and #MikeWillis in https://stackoverflow.com/a/32868971/246724
$('.linkbox', context).once('linkbox').each(function(e){
var $linkbox = $(this);
var href = $linkbox.data('href');
if (!href) {
return;
}
var $hiddenLink = $('<a>').attr('href', href).hide().appendTo('body');
$linkbox.click(function(e){
$hiddenLink[0].dispatchEvent(new MouseEvent('click', {button: e.button, which: e.which}));
e.preventDefault();
});
});
Note that I put the hidden link outside of the clicked div, to prevent recursion.
The right-click menu does not give me "copy link url", but I imagine this would be really hard to replicate.
UPDATE: I found that I don't really need to append the link to anything, and it still works. But I only tested this in Chromium on Linux so far.
This is the code to achieve left click and middle click functionality.
tabindex works with any html element so you can use it not the div
$("#link").on('click', function(e) {
const hasTargetBlank = $(this).data('target') === '_blank';
const href = $(this).data('href');
switch(e.which) {
// left click
case 1: {
if (hasTargetBlank) {
window.open(href);
} else {
window.location = href;
}
break;
}
// middle click
case 2: {
window.open(href);
break;
}
// right click
case 3: {
// do what you want to do
}
}
});

Disable Double Tap To Click On Touchscreen iOS Devices

So, quite recently I've been working on a website that was given me to improve and make responsive, and one of the issues that I've been faced with is that there are many elements that are clickable, with a mixture of CSS and jQuery effects for hover states.
Now, firstly I'd prefer all of these hover states to be CSS, but the main issue I'm having is that on these hover states, certain elements are changing display and visibility css properties. I did some reading, and apparently if this is the case, on touchscreen iOS devices, this causes the first 'touch' to force the hover state, and then a second click is needed to actually click the element.
I'm trying to find a solution that doesn't require lots of markup and styling changes. Preferably a fix harnessing jQuery/JavaScript would be good.
I've tried the following:
$(document).ready(function() {
$('a').on('click touchend', function(e) {
var el = $(this);
var link = el.attr('href');
window.location = link;
});
});
However, this has issues when the user holds their finger down on a clickable element, and drags the page to scroll. When they release their finger after dragging, the window.location is still changed.
I'll add a jsFiddle later if necessary.
Thanks in advance.
EDIT:
Here's a jsFiddle that shows the issue. http://jsfiddle.net/0bj3uxap/4/
If you tap one of the blocks, you'll see it shows the hover state, you then need to tap again to actually fire the click event.
It seems to happen when an element is hidden, and then the hover state shows the element.
Looks like I found a solution.
https://github.com/ftlabs/fastclick
FastClick fixes this issue, and removes the 300ms delay issue with some mobile browsers.
Just include the library in <script> tags, and then initiate it using jQuery, or whatever you prefer:
$(document).ready(function() {
FastClick.attach(document.body);
});
Just to explain briefly why the issue occurs:
When an element is hidden, for example when it has a CSS property of any of the following:
display: none;
opacity: 0;
visibility: hidden;
And the hover state of the hidden element then shows the element, iOS doesn't fire a click event on the first touch, it forces the hover state (to show the element). The user then needs to touch the element again for a click event to fire.
I see why this has been added, but I think I'd rather iOS didn't do this, and then developers would just need to tailor their websites to not hide content that coud be vital.
If it helps anyone else: In my case I had a very similar problem, however it wasn't simply due to a :hover style on it's own. Instead, it was due to the fact that I was using JavaScript event listeners (touchstart, touchmove and touchend) to change visibility of elements on the page (no matter where).
In my case, I was simply adding a touch class to the <html> tag in order to detect that the device was capable of touch and should always display certain elements that typically only show on hover. My fix was two fold:
Move to a >300ms delay (i.e. the amount of time mobile browsers may typically wait before determining if this was a single vs. double click). In my case, I just settled on 500ms (see #2 below for why).
I then used a cookie to temporarily retain this setting so that these elements would be visible immediately and no touch event listeners would be required on subsequent page loads (thus a delay of 500ms on the first occasion shouldn't be a deal breaker).
Example code:
In this case, using jQuery + https://github.com/carhartl/jquery-cookie (modified to support maxAge).
function initTouchSupport() {
// See if touch was already detected and, if so, immediately toggle the touch classes.
if ($.cookie('touch-device')) {
toggleTouch();
return;
}
// Be efficient and listen once and, if ever detected, flag capability and stop listening (for efficiency).
var events = 'touchstart touchmove touchend';
$body.on(events, detectTouch);
function detectTouch() {
// Detected; retain for a short while (e.g. in case this is a laptop with touch capability and they switch
// to mouse control). That way there's no delay on the next several page loads and no chance of a double-touch bug.
$body.off(events, detectTouch);
$.cookie('touch-device', true, {
path: '/',
domain: getDomain(),
maxAge: 86400 // 86400 seconds = 1 day
});
setTimeout(toggleTouch, 500);
}
function toggleTouch() {
// Swap out classes now
$html.toggleClass('no-touch', false);
$html.toggleClass('touch', true);
}
}
I had a very similar issue in IOS having to double tab buttons etc I removed all the desktop styles which included some hover styles this made no difference. I put the hover styles back in which are not used in the mobile UI. In then end the issue was a css class called
.error-message
Correction it turns out this css has been used in our UI and it was linked to a mouseover event

How to unbind() .hover() but not .click()?

I'm creating a site using Bootstrap 3, and also using a script that makes the dropdown-menu appear on hover using the .hover() function. I'm trying to prevent this on small devices by using enquire.js. I'm trying to unbind the .hover() event on the element using this code:
$('.dropdown').unbind('mouseenter mouseleave');
This unbinds the .hover of that script but apparently it also removes the .click() event(or whatever bootstrap uses), and now when I hover or click on the element, nothing happens.
So I just want to how I can remove the .hover() on that element, that is originating from that script, but not change anything else.
Would really appreciate any help.
Thanks!
Edit: Here is how I'm calling the handlers for the hover functions:
$('.dropdown').hover(handlerIn, handlerOut);
function handlerIn(){
// mouseenter code
}
function hideMenu() {
// mouseleave code
}
I'm trying to unbind them with this code.
$('.dropdown').unbind('mouseenter', showMenu);
$('.dropdown').unbind('mouseleave', hideMenu);
But its not working.
Please help!
**Edit2: ** Based on the answer of Tieson T.:
function dropdownOnHover(){
if (window.matchMedia("(min-width: 800px)").matches) {
/* the view port is at least 800 pixels wide */
$('.dropdown').hover(handlerIn, handlerOut);
function handlerIn(){
// mouseenter code
}
function hideMenu() {
// mouseleave code
}
}
}
$(window).load(function() {
dropdownOnHover();
});
$(window).resize(function() {
dropdownOnHover();
});
The code that Tieson T. provided worked the best; however, when I resize the window, until I reach the breakpoint from any direction, the effect doesn't change. That is, if the window is loaded above 800px, the hover effect will be there, but if I make the window smaller it still remains. I tried to invoke the functions with window.load and window.resize but it is still the same.
Edit 3: I'm actually trying to create Bootstrap dropdown on hover instead of click. Here is the updated jsFiddle: http://jsfiddle.net/CR2Lw/2/
Please note: In the jsFiddle example, I could use css :hover property and set the dropdow-menu to display:block. But because the way I need to style the dropdown, there needs to be some space between the link and the dropdown (it is a must), and so I have to find a javascript solution. or a very tricky css solution, in which the there is abot 50px space between the link and the dropdown, when when the user has hovered over the link and the dropdown has appeared, the dropdown shouldn't disappear when the user tries to reach it. Hope it makes sense and thanks.
Edit 4 - First possible solution: http://jsfiddle.net/g9JJk/6/
Might be easier to selectively apply the hover, rather than try to remove it later. You can use window.matchMedia and only apply your script if the browser has a screen size that implies a desktop browser (or a largish tablet):
if (window.matchMedia("(min-width: 800px)").matches) {
/* the view port is at least 800 pixels wide */
$('.dropdown').on({
mouseenter: function () {
//stuff to do on mouse enter
},
mouseleave: function () {
//stuff to do on mouse leave
}
});
}
else{
$('.dropdown').off('mouseenter, mouseleave');
}
Since it's not 100% supported, you'd want to add a polyfill for those browsers without native support: https://github.com/paulirish/matchMedia.js/
If you're using Moderizr, that polyfill is included in that library already, so you're good-to-go.
I still don't understand how you intend to "dismiss" the dropdown-menu once it is displayed upon mousing over the dropdown element partly because there's not enough code in your question, but that's sort of irrelevant to this answer.
I think a much easier way to approach the mousenter event handling portion is not by using off()/on() to unbind/bind events at a specific breakpoints, but rather to do just do a simple check when the event is triggered. In other words, something like this:
$('.dropdown').on('mouseenter', function() {
if($('.navbar-toggle').css('display') == 'none') {
$(this).children('.dropdown-menu').show();
};
});
$('.dropdown-menu').on('click', function() {
$(this).hide();
});
Here's a working fiddle: http://jsfiddle.net/jme11/g9JJk/
Basically, in the mouseenter event I'm checking if the menu toggle is displayed, but you can check window.width() at that point instead if you prefer. In my mind, the toggle element's display value is easier to follow and it also ensures that if you change your media query breakpoints for the "collapsed" menu, the code will remain in sync without having to update the hardcoded values (e.g. 768px).
The on click to dismiss the menu doesn't need a check, as it has no detrimental effects that I can see when triggered on the "collapsed" menu dropdown.
I still don't like this from a UX perspective. I would much rather have to click to open a menu than click to close a menu that's being opened on a hover event, but maybe you have some magic plan for some other way of triggering the hide method. Maybe you are planning to register a mousemove event that checks if the mouse is anywhere within the bounds of the .dropdown + 50px + .dropdown-menu or something like that... I would really like to know how you intend to do this (curiosity is sort of killing me). Maybe you can update your code to show the final result.
EDIT: Thanks for posting your solution!

How do I show a div, but make it completely un-interactive, in Chrome

I have a <div> overlayed onto my page, and that tracks the mouse. However, on occasion the user is able to move the mouse at the appropriate speed to enter the tracking <div>. Also, this <div> will sometimes prevent the user from clicking something else, that is below/behind.
What is the correct way to visually show this <div>, without it 'blocking' or interfering with the underlying DOM, or any of them for that matter? In particular, to stop it interfering with mouse events.
Good answers to this already, one you can consider also is the css:
pointer-events: none;
Which effectively makes events act on the items below the div, not the div itself.
Support for this on IE isn't great, but it's a nice way if you either don't need IE support, or if you have the time to do it properly and include a conditional fallback.
Check out this for support info: http://caniuse.com/pointer-events
you can place above it (with higher z-index) an absolute positioned div element, with an opacity value of 0
OR
you can use jQuery:
$(function(){
$('#divId').click(function(e){
e.preventDefault();
e.stopImmediatePropagation();
e.stopPropagation();
});
});
i personally prefer the opacity approach. but that's me.
hope that helped
Yuo can try to capture the event and prevent its default behavior using
event.preventDefault();
here a pseudo code, it works without jquery
var el = document.getElementById("yourdiv");
el.addEventListener("click", action, false);
function action() {
event.preventDefault();
return false;
}

Mobile Safari Event Issue

I have designed a website with a menu that is initially invisible. When the user clicks on a button, the menu becomes visible. There are two ways for the user to hide the now visible menu:
Click the button that caused the menu to become visible
Click anywhere on the web page that isn't the menu
The way I have coded the second option is to tie an onclick event to the window element, and have it compare where the user clicked to the menu's position to determine if the menu should be hidden. This works great in Firefox and Safari, but it fails in Mobile Safari.
I noticed that the window onclick event only fires when I click on another element with an onclick event already assigned. If I click on an element with no event(s) assigned, the window's onclick event never fires. If I click on the button which displays the menu, it fires along with the event tied to the button.
Is it possible to assign events to the window element in Mobile Safari?
I'v been encountering this same problem. Here is what worked for me. (Note: I am working within a Modernizr and jQuery context)
First, I add a custom Modernizr class using Modernizr's addTest Plugin API to test for iOS, which will add the class appleios or no-appleios accordingly.
Because in my research the body seems to fire events on it's own agenda, I am taking a little precaution by wrapping all the document's content with an element in an iOS context. Then I add an event handler to this element.
$(".appleios body").wrapInner('<div id="appleios-helper" />');
$("#appleios-helper").bind("mouseup", function(){return;});
What was suggested earlier in this thread is using void(0). I did some quick testing, and found that void(0) as the event just wasn't causing touches on the body to be recognized. When I plugged in my own "empty" function in the form of function(){return;} things started working.
This all hinges on the fact that no events are fired in Mobile Safari unless the element explicitly has events to fire (Safari Web Content Guide.) By inserting this empty event on the wrapper, things will bubble up to the body.
If you're doing strait JavaScript with none of these libraries, the same effect could be achieved in the HTML markup
<html>
...
<body>
<div id="appleios-helper" onmouseup="function(){return;}">
...
</div>
</body>
</html>
This worked for me to hide tooltips when touching anywhere on the document's body. Your mileage may vary.
Simply adding the dummy onclick handler to the html body works for me:
<body onclick="void(0)">
Note that I am using usual live event handlers as shown below:
function liveHandler( event ) {
var target = event.target; ...}
window.addEventListener(evtype, liveHandler, true);
// evtype such as 'mousedown' or 'click'
// we use the capturing mode here (third parameter true)
This is an old question, but I struggled with the same thing today.
I found that using touchstart event works.
I solved it like this:
var isTouchDevice = 'ontouchstart' in document.documentElement;
if (isTouchDevice) {
// Do touch related stuff
$(document).on('touchstart', function (event) {
// Do stuff
});
} else {
// Do non-touch related stuff
$(document).on('click', function () {
// Do stuff
});
}
You could just add onclick="void(0);" to some <div> that covers the whole page so that no matter what, you are always clicking on an element that has an onclick event. Not a great solution, though.
I'd prefer not having the onclick event be tied to the window. Why don't you create a container <div> that has that event on it. Then handle it just like you currently are.
You can also:
$('body').css('cursor', 'pointer');
No idea what those "engineers" at Apple are doing. LOL.
This has problems though. You wouldn't want to do this on every touch device. Only touch devices that don't also have a pointing device (Laptops with Touch Screens, for example).
Source: http://www.quirksmode.org/blog/archives/2014/02/mouse_event_bub.html
The conclusion of the article is this:
So I don’t understand why all this is the case, but it most certainly is the case. If you’re having bubbling problems, just add an empty-function event handler anywhere between the body and the element, and you’re set to go. But it shouldn’t be necessary.

Categories

Resources