I am pulling my hair out because for some reason when I pass behavior: smooth as a parameter to window.scroll, the function stops working altogether in Chrome. Without behavior:smooth it scrolls as expected. I'm pretty sure this is a Chrome bug, but I've used behavior:smooth elsewhere without issue, so I'm wondering what's special about the config on this page which is causing the problem. Here's the set-up, which will hopefully allow you to reproduce:
I have a document with several viewport-sized divs like so:
html:
<body>
<div class="slide" data-ind="0"></div>
<div class="slide" data-ind="1"></div>
<div class="slide" data-ind="2"></div>
</body>
css:
.slide{
width:100%;
height:100vh;
border-bottom:1px solid black;
box-sizing:border-box;
}
I'm trying to use an event listener to scroll to a slide when you press an arrow key, like so:
window.addEventListener('keydown',function(){
if(event.key=='ArrowRight'){
let el=document.querySelector('.slide[data-ind="1"]');
let dist=el.offsetTop;
window.scroll({
top:dist,
left:0,
behavior:'smooth'
})
}
})
Update: Some more testing has made it clear that the bug only happens when window.scroll is used within a keyboard event.
I was able to resolve this by adding event.preventDefault(); to the keyboard event. Still unclear if this is intended/standard behavior, as Firefox had no such issue even without adding this line.
Related
I have a tooltip which uses 2 event listeners: mouseenter (to open it) and mouseleave (to close it).
In desktop browsers and iPhone iOS 13.2 it works fine, however it wasn't closing for iPhone iOS 12.2.
I found a solution, setting the CSS cursor: pointer; on the background element. So it would seem iOS needs a bit of help detecting the mouseleave event.
Is there another solution? Settings cursor: pointer; feels hacky and could be confusing in some circumstances.
UPDATE: I added the following code to simplify my test and as I expected 'testing' is logged when I tap the screen for iOS13 but not iOS12. However when I put that code (and nothing else) into codepen.io and view it that way then both versions work fine.
function doTest() {
console.log('testing');
}
document.addEventListener('click', doTest);
Apparently any non-anchor elements on iOS can not receive "mouse" events without cursor: pointer; See: https://stackoverflow.com/a/27938334/529024.
So I suggest to try either changing your element to anchor <a> or use touch events: touchstart and touchend. See: https://stackoverflow.com/a/20882736/529024
touchend events will only run on mobile devices. Add a touchend to the document to hide the tooltips whenever the body is tapped, but block that from happening when the element you want to show the tooltip is tapped- and show the tooltip ontouchend instead. I made a simple example for you for clarification. It just demonstrates this concept with a single tooltip which has an id of "tooltip":
document.addEventListener("touchend", function(){
hideTooltip();
});
function showTooltip(){
document.getElementById("tooltip").style.display = "block";
}
function hideTooltip(){
document.getElementById("tooltip").style.display = "none";
}
body>div{
width:100px;
height:100px;
background:red;
position:relative;
}
#tooltip{
position:absolute;
top:100%;
left:0px;
width:100%;
background:#222;
color:#fff;
padding:5px;
box-sizing:border-box;
display:none;
}
<html>
<body>
<div onmouseenter="showTooltip();" onmouseleave="hideTooltip();" ontouchend="event.preventDefault();showTooltip();">
Tap me!
<div id="tooltip">tooltip info...</div>
</div>
</body>
</html>
In a web app, I need to disable the default callout that mobile browsers shows when touching and holding ("long tap") on a touch target, such as an <img> or a link.
I am already using -webkit-touch-callout: none for iPhone and iPad. I tried -ms-touch-action:none and touch-action:none for IE, but this doesn't seem to work (tested on IE11, Windows Phone 8).
This post from the W3 mailing list suggests adding a listener for the "contextmenu" event in Javascript and calling e.preventDefault(). This does not seem to work either.
Any suggestions?
I did a bunch of research and as far as I can tell these are your two options:
Use a transparent <div> to cover the link/image
using a <div> with style="background: url(yourimage.png)" instead of <img src="yourimage.png">
The core problem is that mobile IE on Windows Phone doesn't properly handle preventDefault with contextmenu events. That is the proper way to do this and it works in every other browser. The contextmenu event is fired on WP IE but it actually happens when the long press context menu is dismissed. It should happen before even showing the menu so that you can prevent it.
Here are some of the other options I tried:
Events: I tried registering for every event and using e.preventDefault(), e.stopPropagation() and return false to prevent all of the default actions. JSBin example.
Use element:before or element:after to place an element on top of the link or image. I thought this might be able to automatically do what the transparent <div> does. Unfortunately the :before or :after content is part of the <a> so it is all clickable as well. Also, apprently <img> elements don't support :before or :after. JSBin example.
user-select: none
-ms-touch-action
-webkit-touch-callout: none
I even pinged someone on the IE team and he didn't know of a way.
I tried every "normal" or "elegant" option out there, but apparently IE11 mobile ignores every single one of them.
CSS properties: -webkit-touch-callout equivalent for IE
The preventDefault method Microsoft suggests: https://msdn.microsoft.com/en-US/en-en/library/jj583807(v=vs.85).aspx
Catching all touch events: Disabling the context menu on long taps on Android
A homebrewn oncontextmenu callback with stopPropagation and preventDefault
The only thing actually working is the old ugly div-over-image:
<div class="img-container">
<img src="path/to/image.jpeg" />
<div class="cover"></div>
</div>
CSS:
.img-container {
position: relative;
}
.cover {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
}
Look at this example
Here is the code:
CSS:
div {
position:fixed;
top:100px;
left: 320px;
border: solid 1px blue;
}
Javascript:
var i = 1;
$(document.body).mousemove(function () {
$("#text").html(i++);
});
HTML:
<body>
<div>
<span>Test Text: </span>
<span id="text"></span>
</div>
</body>
This code just updates the span while mouse is moved over the body. It works fine in Google chrome but in Firefox the span is only updated when mouse moves over the div, To debug I looked into firebug and found that the height of the body is 0, so the mouse is actually not moving over the body, but in Google chrome body covers whole document.
So My question is:
Which is the right behavior?(chrome's or firefox's)?
Is the right behavior documented somewhere?
Also surprisingly when I added this code in jsfiddle, chrome started behaving like firefox, can someone explain me this unusual behavior also?
EDIT: I know I can make the code work in both browser by adding height:100% to body, I want to know why this different behavior in browsers and the right one.
You can see what's going on if you add this css:
body { border: 1px solid red; }
I'm not entirely sure of the reasoning, but Chrome decides that the 'body' element should be the full height of the window, whereas Firefox collapses the body element to a single line. I believe the body collapsing is the correct behavior, because a 'block' element (such as <body> or <div>) should only be as tall as necessary to contain its contents (and since you made the inner div absolutely positioned, it won't take this into account in calculating its height).
The correct fix depends on your intended outcome, but you could use document or window instead of document.body because they represent the entire viewable window instead of just the actual <body> element.
You could also set your body to a specific height like 100%. Alternatively, once you add more content to the body (stuff that isn't absolutely positioned), it will "fill out" and cause the mousemove event to fire properly anyway, so you won't need any of these fixes.
Additional to Alex's answer I was still interested in the different behaviour. I found the solution: in jsfiddle you are not supposed to add the 'body' element in the html. If you remove that then you get the same behaviour as with the stand-alone page.
UPDATE:
That wasn't the case. The real reason is that the stand-alone page missed the
<!DOCTYPE html>
declaration which caused a HTML version difference.
I don't know why but this works
Replaced document.body with document in
$(document.body).mousemove(function () {
This also works on Firefox.
I would like to expand/collapse a div when this div is clicked on. It already works with onmouseover/onmouseout, but I would prefer onclick.
Now, the problem seems to be the content of the div:
This works:
<div onclick="alert('works')" style="position:fixed; height:100px; width:100px; background:#FF0000;">
</div>
This doesn't work:
<div onclick="alert('works')">
<div style="position:absolute; top:0px; bottom:-18px; left:0px; right:-18px; overflow: hidden; z-index:300;">
<script>
document.write('<IFRAME id="test_frame" SRC="iframesrc.html" frameborder="0" WIDTH="100%" HEIGHT="100%"></IFRAME>');
</script>
</div>
</div>
But this (onmouseover instead of onclick) works again:
<div onmouseover="alert('works')">
<div style="position:absolute; top:0px; bottom:-18px; left:0px; right:-18px; overflow: hidden; z-index:300;">
<script>
document.write('<IFRAME id="test_frame" SRC="iframesrc.html" frameborder="0" WIDTH="100%" HEIGHT="100%"></IFRAME>');
</script>
</div>
</div>
I guess it must be some layering issue, but I tried putting the "onclick" into each of the different div/iframe layers and I couldn't get it to work. I'm a beginner and it'd be great to get a tip on what's wrong! Thanks!
I would recommend using JQuery for this.
You can do what you wanna do with 1 line of code.
write a test.js like this:
$(document).ready(function() {
// hides the div as soon as the DOM is ready
$('#yourDiv').hide();
// shows the div on clicking the noted link
$('#yourDiv-show').click(function() {
$('#yourDiv').show('slow');
return false;
});
// hides the div on clicking the noted link
$('#youDiv-hide').click(function() {
$('#yourDiv').hide('fast');
return false;
});
// toggles the div on clicking the noted link
$('#youDiv-toggle').click(function() {
$('#yourDiv').toggle(400);
return false;
});
});
Then import this javascript to your HTML,JSP etc...
If you set the first div with border 10px and click on that border it will work.
As you start a new div the first div is just the container, any javascript calls will not be triggered.
like border: 50px solid; you will see what i mean.
The onmouseover works because you actually go over the invisible line of the div.
JavaScript events are supposed to 'bubble' up through the ancestry of DOM nodes from the one you click, all the way up to the body node, executing any appropriate handlers registered for those nodes along the way, unless a specific event handler stops the propagation of that event.
I suspect the iframe is your issue, since that is a separate HTML document, with a separate event chain, and that events don't bubble out of that, but I don't know for certain.
I would try the jQuery suggestion above, but I think this particular situation is not going to allow even jQuery to work.
We have a web page with this general structure:
<div id="container">
<div id="basicSearch">...</div>
<div id="advancedSearch" style="display: none">...</div>
<div>
With this CSS:
#container { MARGIN: 0px auto; WIDTH: 970px }
#basicSearch { width:100% }
#advancedSearch{ width:100%;}
We have a link on the page that lets the user toggle between using the "basic" search and the "advanced" search. The toggle link calls this Javascript:
var basic = document.getElementById('basicSearch');
var advanced = document.getElementById('advancedSearch');
if (showAdvanced) {
advanced.style.display = '';
basic.style.display = 'none';
} else {
basic.style.display = '';
advanced.style.display = 'none';
}
This all works great in IE.
It works in Firefox too - except - when we toggle (ie: show/hide) from one div to the other, the page "moves" in Firefox. All the text in the "container" moves about 5px to the left/right when you toggle back and forth. Anyone know why?
Is it causing a scrollbar to appear / disappear?
Toggling content can make the page content taller. Check whether this makes a scrollbar appear, as this will affect the page width slightly.
What I ended up doing was this: HTML { OVERFLOW-Y:SCROLL; OVERFLOW-X:HIDDEN; }
Here's a good related SO post.
Check your XHTML is well formed, sounds like a dangling DIV (firebug will help with this).
On a side note jquery has some really nice animations that make this switch much nicer on the eyes.
I don't know why, but if you install Firebug a Firefox plug in you can use it to debug your problem.
Firebug has saved my hours of debugging time when it comes to CSS and showing and hiding divs.
With firebug you can view what may be different between the two divs.
From firefox, just choose the Tools Menu, then click Ad-Ons, then click Get Ad-Ons and search for firebug.
One thing that you could try is to hide before you show, this may have less flicker. If you are causing the page to get taller, this could be the source of your trouble.
I hope this helps.