:active pseudo-class doesn't work in mobile safari - iphone

In Webkit on iPhone/iPad/iPod, specifying styling for an :active pseudo-class for an <a> tag doesn't trigger when you tap on the element. How can I get this to trigger? Example code:
<style>
a:active {
background-color: red;
}
</style>
<!-- snip -->
Click me

<body ontouchstart="">
...
</body>
Applied just once, as opposed to every button element seemed to fix all buttons on the page. Alternatively you could use this small JS library called 'Fastclick'. It speed up click events on touch devices and takes care of this issue too.

As other answers have stated, iOS Safari doesn't trigger the :active pseudo-class unless a touch event is attached to the element, but so far this behaviour has been "magical". I came across this little blurb on the Safari Developer Library that explains it (emphasis mine):
You can also use the -webkit-tap-highlight-color CSS property in combination with setting a touch event to configure buttons to behave similar to the desktop. On iOS, mouse events are sent so quickly that the down or active state is never received. Therefore, the :active pseudo state is triggered only when there is a touch event set on the HTML element—for example, when ontouchstart is set on the element as follows:
<button class="action" ontouchstart=""
style="-webkit-tap-highlight-color: rgba(0,0,0,0);">
Testing Touch on iOS
</button>
Now when the button is tapped and held on iOS, the button changes to the specified color without the surrounding transparent gray color appearing.
In other words, setting an ontouchstart event (even if it's empty) is explicitly telling the browser to react to touch events.
In my opinion, this is flawed behaviour, and probably dates back to the time when the "mobile" web was basically nonexistent (take a look at those screenshots on the linked page to see what I mean), and everything was mouse oriented. It is interesting to note that other, newer mobile browsers, such as on Android, display `:active' pseudo-state on touch just fine, without any hacks like what is needed for iOS.
(Side-note: If you want to use your own custom styles on iOS, you can also disable the default grey translucent box that iOS uses in place of the :active pseudo-state by using the -webkit-tap-highlight-color CSS property, as explained in the same linked page above.)
After some experimentation, the expected solution of setting an ontouchstart event on the <body> element that all touch events then bubble to does not work fully. If the element is visible in the viewport when the page loads, then it works fine, but scrolling down and tapping an element that was out of the viewport does not trigger the :active pseudo-state like it should. So, instead of
<!DOCTYPE html>
<html><body ontouchstart></body></html>
attach the event to all elements instead of relying on the event bubbling up to the body (using jQuery):
$('body *').on('touchstart', function (){});
However, I am not aware of the performance implications of this, so beware.
EDIT: There is one serious flaw with this solution: even touching an element while scrolling the page will activate the :active pseudo state. The sensitivity is too strong. Android solves this by introducing a very small delay before the state is shown, which is cancelled if the page is scrolled. In light of this, I suggest using this only on select elements. In my case, I am developing a web-app for use out in the field which is basically a list of buttons to navigate pages and submit actions. Because the whole page is pretty much buttons in some cases, this won't work for me. You can, however, set the :hover pseudo-state to fill in for this instead. After disabling the default grey box, this works perfectly.

Add an event handler for ontouchstart in your <a> tag. This causes the CSS to magically work.
<a ontouchstart="">Click me</a>

This works for me:
document.addEventListener("touchstart", function() {},false);
Note: if you do this trick it is also worth removing the default tap–highlight colour Mobile Safari applies using the following CSS rule.
html {
-webkit-tap-highlight-color: rgba(0,0,0,0);
}

As of Dec 8, 2016, the accepted answer (<body ontouchstart="">...</body>) does not work for me on Safari 10 (iPhone 5s): That hack only works for those elements that were visible on page load.
However, adding:
<script type='application/javascript'>
document.addEventListener("touchstart", function() {}, false);
</script>
to the head does work the way I want, with the downside that now all touch events during scrolling also trigger the :active pseudo-state on the touched elements. (If this is a problem for you, you might consider FighterJet's :hover workaround.)

//hover for ios
-webkit-tap-highlight-color: #ccc;
This works for me, add to your CSS on the element that you want to highlight

Are you using all of the pseudo-classes or just the one? If you're using at least two, make sure they're in the right order or they all break:
a:link
a:visited
a:hover
a:active
..in that order. Also, If you're just using :active, add a:link, even if you're not styling it.

For those who don't want to use the ontouchstart, you can use this code
<script>
document.addEventListener("touchstart", function(){}, true);
</script>

I've published a tool that should solve this issue for you.
On the surface the problem looks simple, but in reality the touch & click behaviour needs to be customized quite extensively, including timeout functions and things like "what happens when you scroll a list of links" or "what happens when you press link and then move mouse/finger away from active area"
This should solve it all at once: https://www.npmjs.com/package/active-touch
You'll need to either have your :active styles assigned to .active class or choose your own class name. By default the script will work with all link elements, but you can overwrite it with your own array of selectors.
Honest, helpful feedback and contributions much appreciated!

I tried this answer and its variants, but none seemed to work reliably (and I dislike relying on 'magic' for stuff like this). So I did the following instead, which works perfectly on all platforms, not just Apple:
Renamed css declarations that used :active to .active.
Made a list of all the affected elements and added pointerdown/mousedown/touchstart event handlers to apply the .active class and pointerup/mouseup/touchend event handlers to remove it. Using jQuery:
let controlActivationEvents = window.PointerEvent ? "pointerdown" : "touchstart mousedown";
let controlDeactivationEvents = window.PointerEvent ? "pointerup pointerleave" : "touchend mouseup mouseleave";
let clickableThings = '<comma separated list of selectors>';
$(clickableThings).on(controlActivationEvents,function (e) {
$(this).addClass('active');
}).on(controlDeactivationEvents, function (e) {
$(this).removeClass('active');
});
This was a bit tedious, but now I have a solution that is less vulnerable to breakage between Apple OS versions. (And who needs something like this breaking?)

A solution is to rely on :target instead of :active:
<style>
a:target {
background-color: red;
}
</style>
<!-- snip -->
<a id="click-me" href="#click-me">Click me</a>
The style will be triggered when the anchor is targeted by the current url, which is robust even on mobile. The drawback is you need an other link to clear the anchor in the url. Complete example:
a:target {
background-color: red;
}
<a id="click-me" href="#click-me">Click me</a>
<a id="clear" href="#">Clear</a>

No 100% related to this question,
but you can use css sibling hack to achieve this as well
HTML
<input tabindex="0" type="checkbox" id="145"/>
<label for="145"> info</label>
<span> sea</span>
SCSS
input {
&:checked + label {
background-color: red;
}
}
If you would like to use pure html/css tooltip
span {
display: none;
}
input {
&:checked ~ span {
display: block;
}
}

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title></title>
<style>
a{color: red;}
a:hover{color: blue;}
</style>
</head>
<body>
<div class="main" role="main">
Hover
</div>
</body>
</html>

Related

Annotations not working, not even in Dygraphs' own example on jsFiddle, why?

I'm currently trying out Dygraphs (which seems really great btw!), but for some strange reason, the annotations feature won't work for me, AND it also fails in the exact same way on the jsFiddle version of Dygraphs' own gallery example of annotations, so this is most likely a bug/problem the devs really might want to take a look at(!).
To reproduce (same thing happens in both latest Firefox and latest Chrome):
1.
Look at the "annotations" example in the Dygraphs gallery, here:
http://dygraphs.com/gallery/#g/annotations
It works just fine and looks great, like this:
2.
Press the "Edit in jsFiddle" button, for that very example on that very page.
You are now sent to jsFiddle, and if you press the "Run" button there, the chart itself (colored curves etc) is shown just fine, but, only the "stems" of the annotation "signs" are shown, while the text contents of the annotations are all displayed as normal text to the left of the chart?! Like this:
Seems like some kind of CSS problem or similar to me, am I correct?
Since the example is Dygraphs' own example, which also works on their own site but not on jsFiddle, all suspicions of incorrectly formatted data or code can also be let go, I guess. It also happens to all my own Dygraphs charts on my own computer that I try to annotate, but this native Dygraphs gallery example is a much better example to investigate from I guess?
So, my question is of course, why does this happen, and how do I fix it to get the annotations working and displaying correctly?
ADDITION:
Let's make it even simpler, in order to isolate the problem without any hesitation.
Here is a very simple example for Dygraph annotations that I have put together on my own local disk (i.e. as a stand-alone HTML file):
<html>
<head>
<script type="text/javascript" src="dygraph.js"></script>
<link rel="stylesheet" src="dygraph.css" />
</head>
<body>
<div id="test_chart" style="width:750px; height:350px;"></div>
<script type="text/javascript">
var test_annotations = [
{
series: "TestCol1",
x: "2017-05-26",
shortText: "A",
text: "Test annotation",
cssClass: 'annotation'
}
];
testchart = new Dygraph(
document.getElementById('test_chart'),
"Date,TestCol1\n" +
"2017-05-25,110\n" +
"2017-05-26,80\n" +
"2017-05-27,75\n",
{}
);
testchart.setAnnotations(test_annotations);
</script>
</body>
</html>
When I open this file (locally with file:// in Chrome on my computer, having the latest dygraph.js and dygraph.css in the same directory), this is what I get:
As you can see, exactly the same problem as described above appears here, i.e. only the "stem" of the test annotation is visible in the graph itself, while the annotation text ("A") is displayed to the left of the graph.
The Firebug console is empty after having loaded this file, and no attempts (unsuccessful or otherwise) of loading any images are anywhere to be found in the Firebug network tab either.
Again, this very much feels like some kind of CSS positioning problem to me, but I may of course very well be wrong?
The answer to provide to this question would then be:
How, in as few and simple changes/steps as possible, would I get this local example PoC code for Dygraphs annotations to work as intended, i.e. showing the annotation text "A" inside a square at the correct position inside the graph (i.e. at the position where the "annotation stem" is currently just displayed, just as is done in the working example on the Dygraphs page, in my first screendump above in this question)?
Setting
position: absolute
solved the problem for me.
The gallery example loads images from dygraphs.com. When you load the demo on jsfiddle, it tries to load the images from jsfiddle, which doesn't work. dygraphs annotations are working fine, it's just that the image files are missing.
It seems that I was right about the CSS positioning problem after all.
The annotations are rendered by Dygraphs by adding the following HTML to the DOM of the page (this is the exact HTML for my test annotation in my local example code in the question test above, extracted live using Firebug):
<div style="font-size: 14px; left: 392.5px; top: 241.214px; width: 16px; height: 16px; color: rgb(0, 128, 128); border-color: rgb(0, 128, 128);" class="dygraph-annotation dygraphDefaultAnnotation dygraph-default-annotation annotation" title="Test annotation">A</div>
If I (as suggested by this SO question) add the CSS property position: relative to this div (manually, using Firebug), the graph suddenly looks like this:
See, the annotation text is now correctly positioned! It's still missing its opaque background and colored border though, but I guess this is just the result of even more CSS properties missing for some reason?
So, let's focus then on why there is missing CSS for the annotations I guess?
My best guess is that the dygraph.css file isn't properly loaded under certain conditions (apparently both on jsFiddle and locally on my computer, even though it is indeed there in the same directory as the HTML file and dygraph.js)? Or am I wrong?
A Firebug dump of the applied CSS for the annotation div seems to support this. Here is the CSS from Firebug for the annotation div of my local example (and also same in jsFiddle):
And here is the CSS for the same thing in the working instance in the gallery on the Dygraphs site:
See, the classes from dygraph.css is completely missing in my local example and in the jsFiddle example (even though indeed explicitly referenced in the class attribute of the annotation div's html code, as can be seen above), even though the CSS file is indeed there in the same directory as the dygraph.js file?!
#danvk, do you have any idea why this happens, and if Dygraphs could be patched somehow to avoid this from happening, and thus load all the CSS that it is supposed to for the annotations?
The only working hack-solution I can find for the moment is to dump the entire contents of dygraph.css inline in the <head> of the HTML file, as so:
<style>
/**
* Default styles for the dygraphs charting library.
*/
.dygraph-legend {
position: absolute;
font-size: 14px;
z-index: 10;
width: 250px; /* labelsDivWidth */
/*
dygraphs determines these based on the presence of chart labels.
It might make more sense to create a wrapper div around the chart proper.
top: 0px;
right: 2px;
*/
background: white;
line-height: normal;
text-align: left;
overflow: hidden;
}
...
/* For y2-axis label */
.dygraph-label-rotate-right {
text-align: center;
/* See http://caniuse.com/#feat=transforms2d */
transform: rotate(-90deg);
-webkit-transform: rotate(-90deg);
-moz-transform: rotate(-90deg);
-o-transform: rotate(-90deg);
-ms-transform: rotate(-90deg);
}
</style>
After that it's finally working fine:
Addition:
It seems like others too (1) (2) have this general problem regarding the loading of CSS files. No accepted answer to neither that SO question nor Mozilla support thread though, and indeed, none of the suggested answers work for me either. WTF, how can such a huge problem be generally unknown/unanswered? Please do also note that the same thing happens for me in both Chrome and Firefox, and also on multiple computers, out of which some have never opened the file before, so no strange cache-related effects should be involved either. Either way, it would seem like the bug is outside of Dygraphs' scope.
I'm afraid I'm late to the party, but it looks the problem is still valid (or workaround is not well documented). I was able to have better estimation of position by adding in index.html:
<style>
.dygraph-annotation {
position : relative;
display:inline-block;
}
</style>
However still annotations are not following the chart well:
The option attachAtBottom : true added to annotations might help here a bit, but still annotations are jumping on hovering graph (I guess this is because of legend taking some place)
All day trying to solve the same problem as the author at the beginning of this post. Yes, changing the CSN file allows you to somehow solve the problem, but everything worked by itself without dancing with a tambourine when I added this one line:
link rel = "stylesheet" href = "// cdnjs.cloudflare.com/ajax/libs/dygraph/2.1.0/dygraph.min.css" /
As always, you need to be more attentive to the little things)

disable photos & photoset permalinks tumblr

I'm trying to make all picture posts on my homepage not clickable, so they can't link to the permalinks. (I just want them to stay as miniatures with the hover cycle effect already provided by the theme)
I've tried removing {LinkOpenTag} and {LinkCloseTag} from:
{block:Photo}
<div class="wide-sizer">
<div class="image">
{LinkOpenTag}
<img src="{block:PermalinkPage}{PhotoURL-HighRes}{/block:PermalinkPage}{block:IndexPage}{PhotoURL-500}{/block:IndexPage}" alt="{PhotoAlt}"
data-high-res="{PhotoURL-HighRes}"
data-width="{PhotoWidth-HighRes}"
data-height="{PhotoHeight-HighRes}"
/>
{LinkCloseTag}
</div>
But photos and photosets are still clickable.
This is my page: http://woodstudiofr.tumblr.com
I'm using the "Spectator Theme".
UPDATE: ok so i tried removing as data-permalink={Permalink}as lharby suggested, but now all the links redirect to /undefined.
Any ideas?
thanks again for your time !
As mentioned in my comment, the data-permalink attribute has been removed, but there is still some custom javascript which is casing the url to be returned undefined.
Go to the bottom of your template, before the closing <body> tag and add this code:
<script type="text/javascript">
$(document).ready(function(){
$('.post').unbind('click').click(function(){});
});
</script>
(Basically instead of binding the post to a click function which is in the custom javascript we are now attempting to unbind it on click).
I tested it in the browser and it looks to be working (although a couple of other methods I thought would work didn't).
EDIT
In order to change the cursor on the post element. Remove the clickable class from the .post div from the template (if you can, if it is hard coded in).
Alternatively inside the style tags at the bottom, add the following css:
.post-grid .post.photo.clickable a,
.post.clickable {
cursor: default;
}

Weird css behaviour for ui-widget :active on iPhone

Scenario:
Standard recommended iframes for embedding Vimeo and YouTube
Someone discovered that nothing happens on click/touch on iPhone
Disabled css and js, everything works
After some digging found that if disabling css .ui-widget :active { outline: none; } everything works as expected.
No jquery-ui js on these pages so no elements with .ui-* at all.
How can removing a line of css that shouldn't even be parsed cause this behaviour?
This exact scenario is happening to me also.
Embed a youtube video using an iframe.
Example:
<iframe class="media-youtube-player" width="510" height="290" src="{$url to youtube}" frameborder="0" allowfullscreen></iframe>
In safari on ipad, tapping the video nothing happens.
I also bisected through my code and found that removing this line from
the jquery.ui.theme.css:
.ui-widget :active { outline: none; }
fixed the problem.
I also tried modifying the line to:
.ui-widget :active { }
This also causes the issue. Meaning the selector itself breaks the video in the ipad.
I also tried replacing the .ui-widget :active selector with just :active, this also
causes the video to not play.
So, that's the fix... Delete that selector!
And outlines that appear on active elements inside .ui-widget you'll need to target more specifically.

Adding a :hover effect in Mobile Safari when the user "taps"

Is it possible to trigger a :hover event whenever a Mobile Safari user single taps on a div area?
It does not have to be a link. Actually, it can't be a link because the user will go to another webpage.
The hover effect I have applied is actually on a div : #div:hover {color:#ccc;}
I would like for this hover to happen whenever an iPad or iPhone user single taps on the div area.
I know that piece of CSS exists for the background color of a link:
-webkit-tap-highlight-color:rgba(200,0,0,0.4);
But this does not apply to my situation.
If this could apply to the color of the text, for example, then I could use it.
Update: Please see my accepted answer below
Are you talking about this in context with UIWebview? You can inject CSS or Javascript and treat it as any other browser. If you are doing so I would suggest jQuery
If you are not using UIWebView then we need to define gesture recognizers on the UIView and handle the gestures. i.e. in the gesture handlers make a hover uiview and remove it as the user tap is gone...
I have figured out how to trigger :hover when a user taps on a div area without using javascript. This is done using display:none; and display:block;.
For example:
<div class="block">
<p>This content is shown *before* the user hovers over .block or taps .block on an iOS device.</p>
<div class="mask">
<p>This content is shown *after* the user hovers over .block or taps .block on an iOS device.</p>
</div>
</div>
CSS:
.block {
width:300px;
height:300px;
background:black;
}
.mask {
width:300px;
height:300px;
background-color:gray;
display:none;
}
.block:hover .mask {
display:block;
}
I have found that the :hover only triggers on iOS while using display (as opposed to opacity). Also, CSS transitions ignores display so this cannot be transitioned with CSS. If you'd like the transition for desktop users, you can add opacity:0; and opacity:1;
EDIT: CSS visibility also seems to work.
Thanks for the time.

Facebook Like Button Not Showing Up In Firefox

I'm using the following code for my like button
<fb:like id="facebook-like" href="http://mysite.com/index.php" layout="button_count" width="450" show_faces="false" font=""></fb:like>
Some users have experienced the like button not showing up. Noted in 3.6.17 but observed in other versions. I'm somewhat familier with the firefox iframe bug, but I was currious if anyone has any work arounds for the facebook like button.
Like buttons that are rendered with javascript (<div class="fb-like"/> and <fb:like/>) get height=0 if they are initially hidden (display:none).
To work around this, create the element with javascript after the container is displayed, and then run:
FB.XFBML.parse();
Example:
result.show();
var like_box = $(".fb-like-inactive", result);
like_box.removeClass("fb-like-inactive");
like_box.addClass("fb-like");
FB.XFBML.parse();
This CSS solved it for me
.fb-like span, .fb-like iframe { height:25px!important; width:150px!important}
This is still an issue, as can be seen here (also contains fix):
http://codepen.io/wiledal/pen/cGnyq
Firefox does not draw the Facebook-like if the div is hidden at the time of parsing. In the example above I delay the showing of a div after different times. You can see that a like-button shown after 500ms does not get rendered in Firefox.
I managed a work around which does not cut off the comment dialog after liking, simply by using min-height and min-width instead of set values that was previously proposed.
.fb-like span, .fb-like iframe {
min-width: 100px !important;
min-height: 20px !important;
}
I had the same problem on Firefox only (v.29.0.1) and it turned out to be AdBlock plus (v.2.6) blocking the Like and Share buttons from rendering.
Can you try calling the like button like so:
<div id="fb-root"></div><script src="http://connect.facebook.net/en_US/all.js#appId=195243810534550&xfbml=1"></script><fb:like href="http://mysite.com/index.php" send="false" width="450" show_faces="true" font=""></fb:like>
And let me know if you're still seeing issues.
Leaving an answer because I can't leave comments yet...
Oli's nice CSS hack looked like it worked initially:
.fb-like span, .fb-like iframe { height:25px!important; width:150px!important}
but it clipped the comment box that tried to pop up when we actually clicked the like button.
Per's delayed parse solution seems to do the job; here's a bit more detail. In our case we had the like button in a drop down menu, which looked like:
<ul>
<li class="control_menu">
<span>menu name</span>
<ul style="display: none;">
<li><div class="fb-like-inactive" data-href=...></li>
...
</ul>
</li>
...
</ul>
with code that shows the drop down ul when the user hovers over the control_menu element. We used this code to handle the delayed parsing:
$(document).ready(function() {
$('.fb-like-inactive').closest('.control_menu').hover(function() {
var inactive = $(this).find('.fb-like-inactive');
if (inactive.length && (typeof FB != 'undefined')) {
inactive.removeClass('fb-like-inactive').addClass('fb-like');
FB.XFBML.parse(this);
}
});
});
It finds the fb-like-inactive buttons, then looks up the tree to find the containing control_menu elements, then attaches an event to the control_menu elements to detect when the user hovers over them. When it detects a hover for a particular menu element, it looks for inactive like buttons within that element, marks them as normal fb-like, and then parses just the content of that element.
I hope this saves someone some time.
I just spent an hour on this and on a much more basic level, you need to know that the Facebook buttons will not render when testing your page locally.
It may seems obvious but it will only work when rendering from a webserver.
Per's solution is based on the XFBML version of the fb button and I wasn't sure how to do this with the "html5 version" or if it is really possible but I found a CSS/JS solution that doesn't clip content instead so here it is:
html
<button class="like-button">I like this stuff</button>
<!-- This is a hidden like-box -->
<div class="social-share aural">...stuff...</div>
CSS:
html body .aural {
position: absolute;
font-size: 0;
left: -9999px;
}
jQuery:
$('body').on("click", '.like-button', function(e) {
var $socialShare = $('.social-share');
$socialShare.css({'font-size':'1em'});
var sw = $socialShare.width();
$socialShare.animate({left: sw-80}, 400);
});
You may have to use !important rule (in both css and js) or nest the .aural class depending on the rest of your css. If it doesn't work I'd suggest trying to change the default layout so it doesn't override .aural or nest .aural and as a last resort use !important..
I had the same problem but the culprit was setting tracking protection in about:config to true.
This tip turned me on to the idea initially:
Lifehacker: Turn on Tracking Protection in Firefox to Make Pages Load 44% Faster
My solution is completely different to any of the above.
I have a character animation in my page, and one of the elements has the id="body" (which is perfectly reasonable) however this seemed to kill the FB script.
As soon as I renamed my id, the share started working again; I can only presume there was some kind of conflict, as id'ed elements can be referenced as global variables.
I found this out through the usual process of removing elements until things worked, so I'm fairly sure it was this.