可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
With some HTML like this:
<p>Some Text</p>
Then some CSS like this:
p {
color:black;
}
p:hover {
color:red;
}
How can I allow a long touch on a touch enabled device to replicate hover? I can change markup/use JS etc, but can\'t think of an easy way to do this.
回答1:
OK, I\'ve worked it out! It involves changing the CSS slightly and adding some JS.
Using jQuery to make it easy:
$(document).ready(function() {
$(\'.hover\').on(\'touchstart touchend\', function(e) {
e.preventDefault();
$(this).toggleClass(\'hover_effect\');
});
});
In english: when you start or end a touch, turn the class hover_effect
on or off.
Then, in your HTML, add a class hover to anything you want this to work with. In your CSS, replace any instance of:
element:hover {
rule:properties;
}
with
element:hover, element.hover_effect {
rule:properties;
}
And just for added usefulness, add this to your CSS as well:
.hover {
-webkit-user-select: none;
-webkit-touch-callout: none;
}
To stop the browser asking you to copy/save/select the image or whatever.
Easy!
回答2:
All you need to do is bind touchstart on a parent. Something like this will work:
$(\'body\').on(\'touchstart\', function() {});
You don\'t need to do anything in the function, leave it empty. This will be enough to get hovers on touch, so a touch behaves more like :hover and less like :active. iOS magic.
回答3:
Try this:
<script>
document.addEventListener(\"touchstart\", function(){}, true);
</script>
And in your CSS:
element:hover, element:active {
-webkit-tap-highlight-color: rgba(0,0,0,0);
-webkit-user-select: none;
-webkit-touch-callout: none /*only to disable context menu on long press*/
}
With this code you don\'t need an extra .hover class!
回答4:
To answer your main question: “How do I simulate a hover with a touch in touch enabled browsers?”
Simply allow ‘clicking’ the element (by tapping the screen), and then trigger the hover
event using JavaScript.
var p = document.getElementsByTagName(\'p\')[0];
p.onclick = function() {
// Trigger the `hover` event on the paragraph
p.onhover.call(p);
};
This should work, as long as there’s a hover
event on your device (even though it normally isn’t used).
Update: I just tested this technique on my iPhone and it seems to work fine. Try it out here: http://jsfiddle.net/mathias/YS7ft/show/light/
If you want to use a ‘long touch’ to trigger hover instead, you can use the above code snippet as a starting point and have fun with timers and stuff ;)
回答5:
Further Improved Solution
First I went with the Rich Bradshaw\'s approach, but then problems started to appear. By doing the e.preventDefault() on \'touchstart\' event, the page no longer scrolls and, neither the long press is able to fire the options menu nor double click zoom is able to finish executing.
A solution could be finding out which event is being called and just e.preventDefault() in the later one, \'touchend\'. Since scroll\'s \'touchmove\' comes before \'touchend\' it stays as by default, and \'click\' is also prevented since it comes afterwords in the event chain applied to mobile, like so:
// Binding to the \'.static_parent\' ensuring dynamic ajaxified content
$(\'.static_parent\').on(\'touchstart touchend\', \'.link\', function (e) {
// If event is \'touchend\' then...
if (e.type == \'touchend\') {
// Ensuring we event prevent default in all major browsers
e.preventDefault ? e.preventDefault() : e.returnValue = false;
}
// Add class responsible for :hover effect
$(this).toggleClass(\'hover_effect\');
});
But then, when options menu appears, it no longer fires \'touchend\' responsible for toggling off the class, and next time the hover behavior will be the other way around, totally mixed up.
A solution then would be, again, conditionally finding out which event we\'re in, or just doing separate ones, and use addClass() and removeClass() respectively on \'touchstart\' and \'touchend\', ensuring it always starts and ends by respectively adding and removing instead of conditionally deciding on it. To finish we will also bind the removing callback to the \'focusout\' event type, staying responsible for clearing any link\'s hover class that might stay on and never revisited again, like so:
$(\'.static_parent\').on(\'touchstart\', \'.link\', function (e) {
$(this).addClass(\'hover_effect\');
});
$(\'.static_parent\').on(\'touchend focusout\', \'.link\', function (e) {
// Think double click zoom still fails here
e.preventDefault ? e.preventDefault() : e.returnValue = false;
$(this).removeClass(\'hover_effect\');
});
Atention: Some bugs still occur in the two previous solutions and, also think (not tested), double click zoom still fails too.
Tidy and Hopefully Bug Free (not :)) Javascript Solution
Now, for a second, cleaner, tidier and responsive, approach just using javascript (no mix between .hover class and pseudo :hover) and from where you could call directly your ajax behavior on the universal (mobile and desktop) \'click\' event, I\'ve found a pretty well answered question from which I finally understood how I could mix touch and mouse events together without several event callbacks inevitably changing each other\'s ones up the event chain. Here\'s how:
$(\'.static_parent\').on(\'touchstart mouseenter\', \'.link\', function (e) {
$(this).addClass(\'hover_effect\');
});
$(\'.static_parent\').on(\'mouseleave touchmove click\', \'.link\', function (e) {
$(this).removeClass(\'hover_effect\');
// As it\'s the chain\'s last event we only prevent it from making HTTP request
if (e.type == \'click\') {
e.preventDefault ? e.preventDefault() : e.returnValue = false;
// Ajax behavior here!
}
});
回答6:
The mouse hover
effect cannot be implemented in touch device . When I\'m appeared with same situation in safari
ios
I used :active
in css to make effect.
ie.
p:active {
color:red;
}
In my case its working .May be this is also the case that can be used with out using javascript. Just give a try.
回答7:
Add this code and then set class \"tapHover\" to elements which you would like to work this way.
First time you tap an element it will gain pseudoclass \":hover\" and class \"tapped\". Click event will be prevented.
Second time you tap the same element - click event will be fired.
// Activate only in devices with touch screen
if(\'ontouchstart\' in window)
{
// this will make touch event add hover pseudoclass
document.addEventListener(\'touchstart\', function(e) {}, true);
// modify click event
document.addEventListener(\'click\', function(e) {
// get .tapHover element under cursor
var el = jQuery(e.target).hasClass(\'tapHover\')
? jQuery(e.target)
: jQuery(e.target).closest(\'.tapHover\');
if(!el.length)
return;
// remove tapped class from old ones
jQuery(\'.tapHover.tapped\').each(function() {
if(this != el.get(0))
jQuery(this).removeClass(\'tapped\');
});
if(!el.hasClass(\'tapped\'))
{
// this is the first tap
el.addClass(\'tapped\');
e.preventDefault();
return false;
}
else
{
// second tap
return true;
}
}, true);
}
.box {
float: left;
display: inline-block;
margin: 50px 0 0 50px;
width: 100px;
height: 100px;
overflow: hidden;
font-size: 20px;
border: solid 1px black;
}
.box.tapHover {
background: yellow;
}
.box.tapped {
border: solid 3px red;
}
.box:hover {
background: red;
}
<div class=\"box\" onclick=\"this.innerHTML = Math.random().toFixed(5)\"></div>
<div class=\"box tapHover\" onclick=\"this.innerHTML = Math.random().toFixed(5)\"></div>
<div class=\"box tapHover\" onclick=\"this.innerHTML = Math.random().toFixed(5)\"></div>
回答8:
Without device (or rather browser) specific JS I\'m pretty sure you\'re out of luck.
Edit: thought you wanted to avoid that until i reread your question. In case of Mobile Safari you can register to get all touch events similar to what you can do with native UIView-s. Can\'t find the documentation right now, will try to though.
回答9:
One way to do it would be to do the hover effect when the touch starts, then remove the hover effect when the touch moves or ends.
This is what Apple has to say about touch handling in general, since you mention iPhone.
回答10:
My personal taste is to attribute the :hover
styles to the :focus
state as well, like:
p {
color: red;
}
p:hover, p:focus {
color: blue;
}
Then with the following HTML:
<p id=\"some-p-tag\" tabindex=\"-1\">WOOOO</p>
And the following JavaScript:
$(\"#some-p-tag\").on(\"touchstart\", function(e){
e.preventDefault();
var $elem = $(this);
if($elem.is(\":focus\")) {
//this can be registered as a \"click\" on a mobile device, as it\'s a double tap
$elem.blur()
}
else {
$elem.focus();
}
});
回答11:
A mix of native Javascript and jQuery:
var gFireEvent = function (oElem,sEvent)
{
try {
if( typeof sEvent == \'string\' && o.isDOM( oElem ))
{
var b = !!(document.createEvent),
evt = b?document.createEvent(\"HTMLEvents\"):document.createEventObject();
if( b )
{ evt.initEvent(sEvent, true, true );
return !oElem.dispatchEvent(evt);
}
return oElem.fireEvent(\'on\'+sEvent,evt);
}
} catch(e) {}
return false;
};
// Next you can do is (bIsMob etc you have to determine yourself):
if( <<< bIsMob || bIsTab || bisTouch >>> )
{
$(document).on(\'mousedown\', function(e)
{
gFireEvent(e.target,\'mouseover\' );
}).on(\'mouseup\', function(e)
{
gFireEvent(e.target,\'mouseout\' );
});
}
回答12:
Easyest solution I found: I had some < span > tags with :hover css rules in them. I switched for < a href=\"javascript:void(0)\" > and voilà. The hover styles in iOS started working.
回答13:
Use can use CSS too, add focus and active (for IE7 and under) to the hidden link. Example of a ul menu inside a div with class menu:
.menu ul ul {display:none; position:absolute; left:100%; top:0; padding:0;}
.menu ul ul ul {display:none; position:absolute; top:0; left:100%;}
.menu ul ul a, .menu ul ul a:focus, .menu ul ul a:active { width:170px; padding:4px 4%; background:#e77776; color:#fff; margin-left:-15px; }
.menu ul li:hover > ul { display:block; }
.menu ul li ul li {margin:0;}
It\'s late and untested, should work ;-)