First off, this is not a clone of: iPad/iPhone hover problem causes the user to double click a link
because I want an answer that is purely CSS. All of the answers in this link require js or jQuery and the one CSS answer involves background images. I'm trying to change the opacity and that's it.
CSS wants to gear itself towards the mobile revolution yet every solution I see for a simple 'touchDown'(aka touch-hover) creating a hover effect requires javascript or jQuery.
Here's some simple code to illustrate what I mean:
.btn {
border-radius: 5px;
display: block;
opacity: 1; <--from
background: red;
text-align: center;
line-height: 40px;
font-weight: bold;
&:hover {
opacity:.7; <--to
transition: opacity .2s ease-out; <--fun fade animation :)
-moz-transition: opacity .2s ease-out;
-webkit-transition: opacity .2s ease-out;
-o-transition: opacity .2s ease-out;
}
}
Tested in Chrome & Safari
iOS will not trigger a link click event on the first tap if the :hover state either:
Has a CSS transition animation
Reveals child content (such as a submenu, tooltip or ::before/::after element)
In both cases the first tap will trigger the :hover state and a second tap will trigger the link (or click event).
If you remove the animation or the child elements you should get it to trigger within a single tap.
This great article from CSS Tricks digs a bit deeper into the issue:
The Annoying Mobile Double-Tap Link Issue
TL;DR: don't rely on hover to reveal things
From the source recommended in #ihodonald's answer also simply recommends not using hover at all:
It’s probably best to just not rely on hover to reveal anything. The tech to work around it isn’t quite there yet.
And from Trend Walton's article:
Ultimately, I think seeing hover states fade away will make the web a better place. There never has been any substitute for concise content, clear interaction, and simple design. If we focus on core elements that make browsing the web great, our sites will function properly no matter how people use them.
Use the touchstart event instead of click on touchscreen devices. This example fixes the issue for iPhone and iPad.
if (
navigator.userAgent.match(/iPhone/i) ||
navigator.userAgent.match(/iPod/i)
) {
// iPhone double-click polyfill
$(document).on("touchstart", ".btn-that-does-something", function (e) {
e.preventDefault();
doSomething(this);
});
$(document).on("click", ".btn-that-does-something", function (e) {
// no-op
e.preventDefault();
});
} else {
$(document).on("click", ".btn-that-does-something", function (e) {
e.preventDefault();
doSomething(this);
});
}
Related
I'm working on a simple tic-tac-toe application and building it in CodePen. When the user loses or forces a draw (designed to be unbeatable), a jquery UI dialog box pops up informing the user of said result. Issue I'm having, is that when this happens, a large empty space appears causing a scroll bar to appear at the right of the page. This is a small detail - but I'd like to fix. I cannot put overflow: hidden on the body because then users won't be able to scroll on small screens or in resized browser windows. I've already tried the following to no avail:
adjusting position of dialog to very top of screen
putting overflow: hidden rule just on .ui-dialog
adjusting the height of the dialog box
adjusting the margin-bottom of .ui-dialog
messing with other dialog options to see if they were the cause
Some of these seemed far-fetched but I wanted to try everything I could think of before coming here. Research has turned nothing up either. I'm running Chrome and the pen in question can be found here: http://codepen.io/no_stack_dub_sack/pen/YGNRxO.
Any help on this would be much appreciated! Thanks in advance.
Again, this is a small detail, but since the app fits all on one page without scroll on most screens, I'd like to keep it looking as clean as possible.
Here's the code:
// DIALOG BOXES
$('body').append('<div id="draw" class="gameOver"><p>It\'s a Draw!</p></div>');
$('body').append('<div id="loser" class="gameOver"><p>You Lose!</p></div>');
$('.gameOver').dialog({
autoOpen: false,
resizable: false,
height: 120,
dialogClass: 'no-close',
buttons: {
'Play Again?': function() {
$('.gameOver').dialog('close');
setNewGame();
}
}
});
Somewhere in the dialog creation process, the position is set to relative on your dialog, which causes the height of your game to calculate the dialog, which gives the empty gap. You can simply set ui-dialog position to absolute in the css, and it'll solve the problem:
.ui-dialog {
position: absolute;
box-shadow: 1px 1px 30px 5px;
background: #04A777;
border-radius: 10px;
outline: none;
overflow: hidden;
margin-top: none;
}
http://codepen.io/anon/pen/EgmoGZ
Here is plnkr example.
Basically there is a style like that
.hover-block {
-webkit-transition: all 1s linear;
transition: all 1s linear;
}
.hover-block:active {
pointer-events: none;
-webkit-transform: scale(1.5);
transform: scale(1.5);
}
.hover-block:hover {
-webkit-transform: scale(1.5);
transform: scale(1.5);
}
I'm seeking to support evergreen and IE10/11, Chrome for Android (4.4+), Mobile Safari (iOS 7+), and it shouldn't hurt other touch events (swipe scrolling).
It seems to work as intended on Android and Chrome device emulation, non-sticky transform on touch is desired behaviour.
But somehow this plunker doesn't work on iOS webkit (iOS 8, all browsers), it does nothing on touch. I'm quite sure that exactly the same approach (block element, :active with pointer-events: none plus :hover) worked for me in iOS 8 before. How can it be fixed?
It looks like empty touchstart/touchend JS event handler or ontouchstart/ontouchend attribute can activate touch behaviour on iOS (can't be sure but it is possible that it happened to me before). Is it a known fix for the problem or there are less hacky ones, which iOS versions are affected?
In your html, instead of <body>, do <body ontouchstart="">
Or in html5, just <body ontouchstart>
So the issue you're running into is this: "The :active pseudo class matches when an element is being activated by the user". A standalone <div> element cannot be activated by the user and therefore will not be matched by the :active pseudo class.
If you look under Browser Compatibility in the :active MDN article you'll see that:
[1] By default, Safari Mobile does not use the :active state unless there is a touchstart event handler on the relevant element or on the <body>.
MDN has a list of pseudo classes that can be used and you might be able to find one that better fits your situation or adding a touchstart event should do the trick in Safari.
I was able to get your plnkr working really quick by changing the <div class="hover-block"></div> element to <button class="hover-block"></button> and changing .hover-block:active { to .hover-block:focus {. I also added display: block; border: 0; to .hover-block.
You, for obvious reasons, may not want to change your <div> to a <button> to get your effect to work, but by using an element that can be activated, using a different pseudo class, or adding an event that allows activation in your target browser, you should be able to achieve the effect you're looking for on mobile devices.
Hope that helps!
Quite simple, I have a link to a secondary page with data-transition="slideup". That page slides up when opened and down when closed fine, but upon clicking the link itself, the current page fades out before the new page slides up. Similarly, when closing the secondary page, it slides down and then the other page fades in.
Can I disable this fade? I just want the secondary page to slide over the top of the current page.
What you're looking for is the CSS transition definitions. I ran into this same problem. If you edit the CSS transitions (transformations), then you should be able to get the desired effect you're looking for.
The transitions are defined as <transition name>.in or .out. You can find them in the structure CSS file. For jQuery Mobile 1.4.2, they would be defined in jquery.mobile.structure-1.4.2.css.
Here's a definition of the slideup (in and out) definitions:
.slideup.out {
-webkit-animation-name: fadeout;
-webkit-animation-duration: 100ms;
-moz-animation-name: fadeout;
-moz-animation-duration: 100ms;
animation-name: fadeout;
animation-duration: 100ms;
}
.slideup.in {
-webkit-transform: translateY(0);
-webkit-animation-name: slideinfrombottom;
-webkit-animation-duration: 250ms;
-moz-transform: translateY(0);
-moz-animation-name: slideinfrombottom;
-moz-animation-duration: 250ms;
transform: translateY(0);
animation-name: slideinfrombottom;
animation-duration: 250ms;
}
(there are also reverse versions for these definitions).
All you need to do is modify these CSS transformations to get the desired effect. Notice how there are defined animation names: slideinfrombottom? These are pre-defined #keyframes in the same CSS file.
Modifying everything here should give you everything you need to tweak and tune the page transitions in jQuery Mobile.
Important note: jQuery Mobile will not fire the in transition until the out transition is completed. If you'd like to tweak that as well, that's a completely different matter. There is code present in 1.4.2 that I saw directly address concurrent and simultaneous transitions, but I didn't explore it thoroughly.
I am using css3 for "button", It is running well on every browser but it's showing different in iPad. I think it takes the default properties of iPad so I apply
"-webkit-appearance:none;" but it is not working.
My CSS Properties are - background:#1356b4; border:solid 1px #0e4189; border-radius:5px; transition:all 0.3s ease-in-out; -webkit-appearance:none;.
And html code is simple span class button and input.
Please help me if someone having any solutions.
By adding -webkit-appearance: none; we are telling mobile Safari that we explicitly don’t want our button to be styled like a native Apple UI control.
Considering this proof of concept, would it be possible to animate margin-left (both negative and positive values) through JavaScript?.. And how would you go about doing so?
Note: I know this is WebKit-only. And I'm fine with that, seeing as I am developing for iOS Safari.
Update
Thanks for the answers, but jQuery's animate function doesn't support pure CSS animations, which is what I need.
I know that you specifically say "can you do this in JavaScript", but you shouldn't need to use JavaScript. I'm fairly certain that the proof of concept you link to only uses jQuery as a way to make the animations fall back to JavaScript so that all browsers play nice with the animation. Since you're specifically developing for Mobile Safari, you shouldn't need to use jQuery for this except to use a history plugin to push and pop states to make the browser's back button work; this is entirely doable via CSS transition properties and the :target pseudo-selector.
So as an alternative, you should be able to do something like this:
In HTML:
<div id="thing-that-will-transition">
<a href="#thing-that-will-transition>click this to transition the div</a>
</div>
In CSS:
#thing-that-will-transition
{
(bunch of properties)
-webkit-transition: margin-left [the rest of your transition values]
}
#thing-that-will-transition:target
{
margin-left: [your properties]
}
As long as your fragment URL matches up with the name of the element that you want to transition then you should be able to push the fragment in to the URL using JavaScript if you absolutely have to instead of using anchor with a fragment href while still having the transition take place. And if you use a jQuery history plugin or do your own pushing and popping of the history stack then you still get back-button behavior for your app.
I know you specifically asked for a JavaScript solution to trigger the CSS animation, but I'm just not sure why this is what you need. Sorry if this doesn't help you at all.
UPDATE: Here's a jsFiddle demonstrating the above. It uses this jQuery history plugin to manage the history stack, so that you can still get acceptable back/forward button behavior from the fragment URL's. The anchor tag uses the plugin's "push" or "load" method in its onClick with a standard fragment in the href attribute as a fallback for browsers without JS enabled.
UPDATE 2: Here's another jsFiddle that uses transforms/translations instead of transitions.
UPDATE 3 (by roosteronacid):
And as for getting the animations going through JavaScript, you can do:
var element = document.getElementById("...");
setTimeout(function ()
{
element.style.webkitTransitionDuration = "0.3s";
element.style.webkitTransitionTimingFunction = "ease-out";
element.style.webkitTransform = "translate3d(300px, 0, 0)";
}, 0);
You can set a transition in css3, and then subsequent changes to the element will be animated.
.MY_CLASS {
-moz-transition: all 0.3s ease-out; /* FF4+ */
-o-transition: all 0.3s ease-out; /* Opera 10.5+ */
-webkit-transition: all 0.3s ease-out; /* Saf3.2+, Chrome */
-ms-transition: all 0.3s ease-out; /* IE10 */
transition: all 0.3s ease-out;
}
This specifies a nearly cross browser (damn IE) transition that applies to all css changes, lasts 0.3 seconds and eases, so it will slow down towards the end of the transition. Therefore, to animate it to the left/right, simply change the css:
$(".MY_CLASS").css("margin-left", "-300px");
Note this will animate it to a fixed position of 300px, if you want to animate to a position relative to its current location use:
var mleft = $(".MY_CLASS").css("margin-left");
var newleft = mleft.substr(0, mleft.length-2) + 50;
$('.MY_CLASS').css("margin-left", newleft+"px");
See a working example here (jsFiddle)
Better use transitions, that are almost cross-browser supported (except IE), and set the keyframes through JS.
This works using CSS, HTML and WebKit only:
#wrapper {
width: 700px;
text-align: left;
border-radius:10px;
-moz-border-radius:10px;
border-style:solid;
border-width:1px;
border-color:#ccc;
padding:30px 30px;
-moz-box-shadow: 0px 0px 5px #BBB;
-webkit-box-shadow: 0px 0px 5px #BBB;
box-shadow: 0px 0px 5px #BBB;
-webkit-transition-property: -webkit-transform, margin-left;
-webkit-transition-duration: 3s;
-webkit-transition-timing-function: ease-in;
-webkit-transform: translate(100px);
}
Just make a <div id="wrapper">Placeholder text</div> in an HTML file to test it out. Worked for me in Google Chrome 12.0.742.112 and Safari 5.0.5 (6533.21.1). If it doesn't do the animation right away, it may be due to your browser processing the translation too quickly (or caching, perhaps?). You might consider adding a delay somehow. I just pressed the refresh button a few times really fast. Worked for me.
Edit:
Check out the source behind girliemac's test page. Some insightful stuff there. Also see this SO post.
you can use jqueries .animate() - http://api.jquery.com/animate/
Check my example - http://jsfiddle.net/ajthomascouk/jS83H/ - Press the + and -
Animating css margins with jQuery works like this:
$( '#mydiv' ).animate({
'margin-left': 'new margin value'
});
To use webkit's css animations, you'd create a class that has the transform property, then you can use jQuery to add/remove said class as needed.