Prevent :hover on touch in iOS - javascript

I have a menu that needs to pop up when it is hovered over (and collapse when the cursor is moved outside). However, on touch devices I want it to expand and collapse on 'click', since hover events aren't very useful.
To do that, I use :hover selector, and a backup .clicked class that is applied on touch events. The touchstart handler toggles the .clicked class and uses preventDefault to block the default action (which sets the :hover flag).
It works fine in Chrome's mobile simulator, but on my iPhone the menu ends up having both :hover and .clicked. Why is that happening?
Here's a fiddle: http://jsfiddle.net/rgLodhjg/1/
// html
<div class="test">
</div>
// css
.test {
width: 200px;
height: 100px;
border: 1px solid black;
}
.test:hover:before {
content: "hover";
}
.test.clicked:after {
content: "clicked";
}
// js
$(".test").on("touchstart", function(e) {
$(this).toggleClass("clicked");
e.preventDefault();
return false;
});

You can try this and it will work on iOS9 (I'm not sure about iOS8 and older):
#media (hover: hover) {
.test:hover:before {
content: "hover";
}
}
To support older iOS systems you can use mq4-hover-shim.
You can also use the solution provided by #Simon_Weaver in this post.

By default, hovers are activated on first "tap" in safari. Try leaving the default hover functionality and tapping it, the hover behavior should happen.

Related

Hyperlinks not selectable by touch in Three.js demo

Just testing out a recent Three.js tutorial # https://tympanus.net/Tutorials/StickyImageEffect/ and I've discovered a few issues that have stumped me while attempting to debug.
Firstly, while testing on an iPad and a couple Smartphones hyperlinks are seemingly active but unresponsive to touch & tap. It seems the "sticky" effect/three.js has total control over the viewport and will not allow touch based devices access to links.
What would need to be augmented to allow the selecting of links and in the process also ignore the triggering of the "sticky" effect when doing so?
Secondly, when viewing on an iPad in landscape orientation there is a small gap at the top of the viewport.
Would this at all be related to the cursor, which is not in use on touch devices?
I would search through the code looking for 'touchstart' and seeing if preventDefault is called. It is.
One solution might be to add your own touchstart handler for <a> tags
Let's test
document.querySelector('#outer').addEventListener('touchstart', (e) => {
e.preventDefault();
});
#outer {
padding: 2em;
background: #EEE;
}
<div id="outer">
is this link touchable
</div>
The code above seems to prevent the link from working.
Adding our own event handler to the links themselves and tell them not to propagate. That way they won't be passed on to the element containing them, the that is calling preventDefault and preventing the default thing (following the link) from happening
document.querySelector('#outer').addEventListener('touchstart', (e) => {
e.preventDefault();
});
document.querySelectorAll('a').forEach((elem) => {
elem.addEventListener('touchstart', stopPropagation);
elem.addEventListener('touchmove', stopPropagation);
elem.addEventListener('touchend', stopPropagation);
});
function stopPropagation(e) {
e.stopPropagation();
}
#outer {
padding: 2em;
background: #EEE;
}
<div id="outer">
is this link touchable
</div>
It seems to work for me.
No idea about the gap. Don't have an iPad to repo and it doesn't seem to repo in the iPad emulation of the Chrome Devtools

How to stop safari (on ipad) from firing hover event?

I have a button that is fixed on my page and when you start to scroll it appears. I noticed on ipad safari I have to click this button twice to fire the click event once.
After searching around I found this sure enough when I commented out my "display:none" on the button it works.
How can I achieve having it hidden and then changing it to "display:block" without getting this double click issue?
You can use css position instead to place it off screen:
.hide {
position: absolute;
left: -999em;
}
You could also try the visibility property
.hide {
visibility: hidden;
}
w3c example

CSS Styles not being removed after class is removed

I am sitting with an issue where CSS styles don't get removed from an anchor tag when the css class is removed via AJAX, it only happens on a mobile device. This doesn't happen when using a desktop browser.
Have a look here using a mobile device.
You will note that the filters turn red when you select them, but deselecting them doesn't remove the red.
The code that is used there:
$('.tagsContainer .tagsContainerA').click(function () {
vm.alphabet("");
clearAlphabet();
$('.pagination.alphabet .alphabetAll').addClass('currentPage');
if ($(this).hasClass('selected')) {
$(this).removeClass('selected');
}
else {
$(this).addClass('selected');
}
return false;
});
Any ideas what could be causing this on a mobile device?
The problem has to do with the hover, not the click function.
This happens because the hover is triggered in mobile while the element is focused also.
Just add this to your css:
#media screen and (max-width: 768px) {
.places-filter .places-tags li:hover {
background-color: #d1d1d1;
background: #d1d1d1;
}
}
This way you will 'disable' the hover function and only have the click one in mobile.
Another solution is placing the hover effect only in screens bigger than X amount.

Highlight an element on hover

I want to highlight an element on hover, and only that element.
This should mimic the behaviour of hovering over an element with chrome dev tools when you have the magnifying glass selected.
It's for a chrome extension I'm making.
I think I need a JS solution, as the pseudo :hover in css seems to apply to all elements in the background, i.e. container elements, so I'd need to prevent event bubbling in css, which as far as I can tell you can't do.
I have tried
$('body').children().mouseover(function(e){
$(".hova").removeClass("hova");
$(this).addClass("hova");
}).mouseout(function(e) {
$(this).removeClass("hova");
});
-css-
.hova {
background-color: pink;
}
and jquery's hover(), both always selects the container too.
I have also tried with css opacity, incase the background was covered, but it seems it always selects the parent element. I want the furthest child down the DOM that I am hovering over.
I'm sure there's some simple solution out there, maybe its over complicating as its in a chrome extension... I'm not sure
Is this what you need? http://jsbin.com/vidojamece/1/
Instead of adding the class to $(this) inside the handler, add the class to e.target (span) and return false so it doesn't bubble up to the div:
$('body').children().mouseover(function(e){
$(".hova").removeClass("hova");
$(e.target).addClass("hova");
return false;
}).mouseout(function(e) {
$(this).removeClass("hova");
});
You need to use the target element instead of 'this', which is the actual element that you hover over and use stopPropagation in order to not repeat the process for each element behind:
$('body').children().mouseover(function(e){
e.stopPropagation();
$(".hova").removeClass("hova");
$(e.target).addClass("hova");
}).mouseout(function(e) {
$(e.target).removeClass("hova");
});
You can do this with css (and js too):
*:hover {
background-color: pink;
}
or even
div:hover {
background-color: pink;
}
In js:
$('body').children().each(function() {
$(this).hover(function() {
$(".hova").removeClass("hova");
$(this).addClass("hova");
}, function() {
$(this).removeClass("hova");
});
});

Don't show hover state on touch devices

Is this possible? Short of converting all my hover styles into mouseover listeners is it possible to stop a touch device from triggering the CSS hover state?
I have an application that must work on both touch and pointer input, it works great but certain styles applied on hover just don't make sense on touch devices because they tend to retain the hover state indefinitely after a user has tapped an object.
Things to take into account:
Device width bears no correlation with touch enabled devices to me,
the touch screens we are using here are desktop size monitors.
I don't want to force a user to input via touch on a multi-input
device.
I had solved this problem following the approach shared in the link in the comments above. If you're not using it, consider using Modernizr in this scenario. Would like to hear some other approaches as well...
As user, Blender mentions, you can check against touch events like so:
html.touch {
/* Touch Device ~ No Hovers */
}
html.no-touch {
/* Not a Touch is disabled */
}
html.no-touch .element:hover {
opacity:.5;
}
My solution is to add hover-active css class to the HTML tag,
and use it on the beginning of all the CSS selectors with :hover
and remove that class on the first touchstart event.
http://codepen.io/Bnaya/pen/EoJlb
JS:
(function () {
'use strict';
if (!('addEventListener' in window)) {
return;
}
var htmlElement = document.querySelector('html');
function touchStart () {
document.querySelector('html').classList.remove('hover-active');
htmlElement.removeEventListener('touchstart', touchStart);
}
htmlElement.addEventListener('touchstart', touchStart);
}());
HTML:
<html class="hover-active">
CSS:
.hover-active .mybutton:hover {
box-shadow: 1px 1px 1px #000;
}

Categories