I'm facing an issue with the scrollTo function when the body has an dir=rtl attribute. here is a jsfiddle for my case.
HTML:
window.scrollTo(-200, 0);
<html>
<head>
</head>
<body dir="rtl">
<div width="100%" style="width: 3000px; height:200px; overflow: hidden">
<div style="width: 1000px; height: 100px; border: 2px solid black; display: inline-block"></div>
<div style="width: 1000px; height: 100px; border: 2px solid red; display: inline-block"></div>
</div>
<script type="text/javascript">
window.scrollTo(-200, 0);
</script>
</body>
</html>
So if I pass a positive value for the xpos parameter, it works on IE (sort of) naturally, it scrolls from the right side of the screen for an amount of 200px. but on chrome and firefox it doesn't work, I have to pass a negative value for the scrolling to work as expected.
My question, is how I can handle this case in my code, should I do browser sniffing? or is there a better way? some feature I can test if its supported?
as othree explains in his jQuery rtl scroll type plugin there are 3 main implementations for horizontal scrolling when dir is set to rtl: WebKit, Firefox/Opera and IE
the difference between these implementations is as follows:
because you can't use jQuery I've modified othree code in this plunker and it works fine in chrome, firefox and IE11
This snippet worked for me on IE and Chrome
http://jsfiddle.net/05w4tr0g/4/
var m = -1;
var pos = window.pageXOffset;
window.scrollTo(0,0);
window.scrollTo(1, 0);
if (-1 == window.pageXOffset) m = 1;
window.scrollTo(pos, 0);
window.scrollTo(m*200, 0);
Hope that helps. The idea is that that the pageXOffset is with IE and Chrome always negative if there was scrolling. The snippet will cause a little flicker because of the test scroll to x=0 and x=-1.
You could store the m value on a page load and reuse it in a wrapper function for scrollTo (or scrollBy for that matter). You could also overload the two methods and keep it all in the window context.
Related
After testing in BrowserStack, I've concluded that using scrollTo() with option parameter behavior: smooth does not work in Chrome and Edge since version 81. Version 80 of both Edge and Chrome was working as expected. According to MDN, it should be working with no asterisk. (unlike Safari)
In popular answers such as this one, using behavior: smooth is the recommended way to enable smooth-scrolling in your web application.
Here's a small reproducible:
<html>
<button onclick="goToAnchor('b')">Scroll to B</button>
<div id="a" style="height: 1000px; background-color: blue;">Blue</div>
<div id="b" style="height: 1000px; background-color: red;">Red</div>
<div id="c" style="height: 1000px; background-color: green;">Green</div>
</html>
<script>
function goToAnchor(anchor) {
let rect = document.getElementById(anchor).getBoundingClientRect();
window.scrollTo({
left: rect.left + window.pageXOffset,
top: rect.top + window.pageYOffset,
behavior: 'smooth',
});
}
</script>
The expected behavior would be that the browser window smoothly interpolate the view down to the red div. It does this properly in all versions of Firefox I've tested. In all of the versions of Chrome since v81, and all versions of Edge since v81, it seems to use the behavior of behavior: auto - i.e. it jumps to the div rather than smoothly interpolating the view.
In version 80 of both Edge and Chrome, it behaves just like Firefox, meaning this bug (?) must've been introduced in version 81 - perhaps in the shared Chromium code-base?
I find it very unlikely that I am the first person to find this issue, as it has been not been working since April, and must therefore conclude I am doing something wrong. Can someone point towards the error in the code? Or is the Chrome and Edge APIs really broken? Is the behavior hidden behind a feature flag, like in Safari?
I believe I've found the culprit, and interestingly, it seems it is Firefox that is the odd one out.
In this StackOverflow thread about detecting RDP connections, the current top answer says:
You can use the following media query:
#media screen and (prefers-reduced-motion: reduce) { . . . }
The prefers-reduced-motion part is interesting. It seems in my testing that this also changes scrollTo() calls with scroll-behavior: 'smooth' to jump rather than interpolate.
I did an addendum to the question's code example to demo the feature:
<html>
<button onclick="goToAnchor('b')">Scroll to B</button>
<p class="reduced-motion">Reduced motion is enabled.</p>
<div id="a" style="height: 1000px; background-color: blue;">Blue</div>
<div id="b" style="height: 1000px; background-color: red;">Red</div>
<div id="c" style="height: 1000px; background-color: green;">Green</div>
</html>
<style>
.reduced-motion {
display: none;
}
#media (prefers-reduced-motion) {
.reduced-motion {
display: inline;
}
}
</style>
<script>
function goToAnchor(anchor) {
let rect = document.getElementById(anchor).getBoundingClientRect();
window.scrollTo({
left: rect.left + window.pageXOffset,
top: rect.top + window.pageYOffset,
behavior: 'smooth',
});
}
</script>
It will now say "Reduced motion is enabled." next to the button depending on your OS and browser configuration. In that case, the scrollTo call will simply jump rather than interpolate.
In short, the issue is that BrowserStack's remote desktop control is also enabling this flag.
I try to make a test with the MS Edge Version 87.0.664.60 and Google Chrome Version 87.0.4280.88.
On my side, the code works fine on both browsers.
Here is my test result: (Above is the MS Edge and below one is the Google Chrome browser)
You are making this test using the BrowserStack. It is can be possible that the issue is related to BrowserStack.
I suggest you try to make a test using the actual browsers. It may help you to find the cause of the issue.
I'm experiencing a strange issue while using the jQuery version 1.11.3 .fadeOut() method.
It's used to briefly display a percentage when the user changes the zoom level of an image using the mouse wheel. It more or less works as expected, except that moving the mouse seems to halt the fade in mid-progress until the mousemove event is complete. Examples depicting the relevant portions of my code are shown below.
var value = 50;
$('#outer').bind('mousemove', function(e) {
//Do something
console.log('bind outer');
});
$('#inner').bind('mousewheel DOMMouseScroll MozMousePixelScroll', function(e) {
e.stopImmediatePropagation();
e.stopPropagation();
e.preventDefault();
$('#number').replaceWith("<span id='number' class='number'>" + Math.round(value) + "%</span>");
$('#number').delay(300).fadeOut("slow");
//Do something
console.log(value);
});
#outer {
height: 300px;
width: 300px;
border: 1px solid red;
}
#inner {
height: 150px;
width: 300px;
border: 1px solid green;
}
#number {
border: 1px solid blue;
}
<script src="http://code.jquery.com/jquery-1.11.3.min.js"></script>
<div id="outer">
<div id="inner">
<span id="number">50</span>
</div>
</div>
Per the usual disclaimer that seems to be required these days, yes I have searched for answers. I also know that the jQuery .bind() method has been depreciated but it's not an issue because I may eventually port this code to pure JavaScript for better processing speed and and to eliminate the dependency on jQuery.
Update: It looks like this may be a browser issue. I tested it in Firefox 41.0, Chrome 45.0, Opera 32.0, Safari 5.1.7, and the issue seems to be specific to Firefox. I also tested it in Internet Explorer 8 (for XP users), but that is an entirely different animal.
I have a div with display:none as style attribute value. In css, a background image url is set for this div. I simply don't want the request for the image to be fired until the div is visible later through some JS code. In Firefox , the network tab shows that the request is not issued which is as expected. But in Chrome developer tools I found that the request for the image is actually fired after the DOMContentLoaded event. What could be the possible reason of different behaviors with hidden elements in these two different browsers ?
Markup:
<html>
<head>
<title></title>
<style type="text/css">
.remoteAudioSoundButton{
background: url("http://ourserverurl/images/image_lady.png");
width: 200px;
height: 200px;
border: 2px black;
}
</style>
</head>
<body >
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<div class='remoteAudioSoundButton' style="display:none"></div>
<script type="text/javascript">
window.onload = function(){
console.log("inside onload");
};
</script>
</body>
</html>
Screenshots:
Chrome:
Firefox:
Why not add the background to a specific class? This way the image will only be loaded when the specific class is added to the element.
$(function(){
$('button').click(function() {
$('.remoteAudioSoundButton').toggleClass('visible');
});
});
.remoteAudioSoundButton{
display: none;
width: 200px;
height: 200px;
border: 2px black;
}
.visible {
background: url("http://ourserverurl/images/image_lady.png");
display: block;
}
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<div class='remoteAudioSoundButton'></div>
<button>Toggle Class</button>
Here is documentation of different browser behavior:
http://justinmarsan.com/hidden-elements-and-http-requests/
Which says:
Chrome and Safari (WebKit)
WebKit downloads the file every time except when a background is
applied through a non-matching media-query. Firefox
Firefox won’t download the image called with background image if the
styles are hidden but they will still download assets from img tags.
Opera
Like Firefox does, Opera won’t load useless background-images.
Internet Explorer
IE, like WebKit will download background-images even if they have
display: none;
So to answer the question of why:
A quick argument for either side:
Firefox - Don't load until the content is visible:
No reason to load something not being viewed, improve page load time.
Webkit - Load the image on pageload: So, perhaps JavaScript decides to make the element visible later, the transition might be choppy if the image is not preloaded, and any other number of arguments for preloading images.
And a brief discussion of the topic:
http://robertnyman.com/2010/03/11/do-hidden-elements-load-background-images/
Browsers may load images that are related to elements that have display:none; set.
I have worked around this before by using a technique like this snippet:
document.getElementById('showKitty').addEventListener('click', function() {
var kitty = document.getElementById('kitty');
kitty.src = "https://placekitten.com/g/200/300";
kitty.classList.toggle('hidden');
});
.hidden {
display:none;
}
<h1>What Can JavaScript Do?</h1>
<img id="kitty" class="hidden">
<button id="showKitty">Show kitten</button>
I'm developing a web application where users can learn Spanish by putting words together like pieces of a puzzle. I've created some JavaScript to make the puzzle pieces "draggable" (I know there is a new D&D API with HTML5, but the way I did it even works on browsers that don't support that).
Anyway, everything works perfectly in IE (even my old IE7) and Firefox, but I ran into an interesting snag with Google Chrome: each piece could only be dragged once; then they became "locked" (unable to move).
So my question is, is there something that needs to be done differently for this to be compatible with Chrome? I was thinking of maybe having the "drop" script refresh the browser every time the user drops a piece, but that would probably be a pain for users with slow connections... anyway I'm sure there's something I'm overlooking, but I'm not sure what it could be. Here's my code:
<html>
<head>
<title> Making Sense out o Spanish </title>
<style>
#div1, #div2{
position: absolute;
left: 100px; top: 100px;
width: 80px; height: 60px;
background-color: yellow;
}
#div3, #div4{
position: absolute;
left: 200px; top: 200px;
width: 80px; height: 60px;
background-color: green;
}
</style>
<script>
var activePiece = "nothing";
function move(id,x,y){
if (activePiece == id){
var element = document.getElementById(id);
element.style.left = x-40 + "px";
element.style.top = y-30 + "px";
}
}
function go(id){
activePiece = id;
var element = document.getElementById(id);
element.style.zIndex = "1";
}
function stop(id){
activePiece = "nothing";
var element = document.getElementById(id);
element.style.zIndex = "-1";
}
</script>
</head>
<body bgcolor="blue" onmousemove="update(event.clientX,event.clientY);">
<div id="div1" onmousedown="go('div1');" onmouseup="stop('div1');" onmousemove="move('div1',event.clientX,event.clientY);">Quiero</div>
<div id="div2" onmousedown="go('div2');" onmouseup="stop('div2');" onmousemove="move('div2',event.clientX,event.clientY);">Necesito</div>
<div id="div3" onmousedown="go('div3');" onmouseup="stop('div3');" onmousemove="move('div3',event.clientX,event.clientY);">bailar</div>
<div id="div4" onmousedown="go('div4');" onmouseup="stop('div4');" onmousemove="move('div4',event.clientX,event.clientY);">trabajar</div>
</body>
</html>
I spent some time looking into this, and it seems the "short answer is, the event listener is the solution. I found this site:
JavaScript mouse events tutorial
And they have a demo that works exactly like mine, EXCEPT that they added the event functions in the script instead of the individual div elements. I haven't had the chance to do try it in my code yet, but their demo works fine in Chrome as well as Firefox and IE.
I want to hide any scrollbars from my div elements and my whole body, but still let the user scroll with the mouse wheel or arrow keys. How can this be achieved with raw JavaScript or jQuery? Any ideas?
Like the previous answers, you would use overflow:hidden to disable the scrollbars on the body/div.
Then you'd bind the mousewheel event to a function that would change the scrollTop of the div to emulate scrolling.
For arrow keys, you would bind the keydown event to recognize an arrow key, and then change scrollTop and scrollLeft of the div as appropriate to emulate scrolling.
(Note: you use keydown instead of keypress since IE doesn't recognize keypress for arrow keys.)
Edit: I couldn't get FF/Chrome to recognize keydown on a div, but it works in IE8. Depending on what you needed this for, you can set a keydown listener on the document to scroll the div. (Check out the keyCode reference as an example.)
For example, scrolling with the mouse wheel (using jQuery and a mousewheel plugin):
<div id="example" style="width:300px;height:200px;overflow:hidden">
insert enough text to overflow div here
</div>
<script>
$("#example").bind("mousewheel",function(ev, delta) {
var scrollTop = $(this).scrollTop();
$(this).scrollTop(scrollTop-Math.round(delta));
});
</script>
(This is a quick mockup, you'd have to adjust the numbers since for me, this scrolls a bit slowly.)
keyCode reference
mousewheel plugin
keydown, keypress # quirksmode
Update 12/19/2012:
The updated location of the mousewheel plugin is at: https://github.com/brandonaaron/jquery-mousewheel
What about a purely CSS solution?
Solution 1 (cross browser but more hacky)
#div {
position: fixed;
right: -20px;
left: 20px;
background-color: black;
color: white;
height: 5em;
overflow-y: scroll;
overflow-x: hidden;
}
<html>
<body>
<div id="div">
Scrolling div with hidden scrollbars!<br/>
On overflow, this div will scroll with the mousewheel but scrollbars won't be visible.<br/>
Scrollable<br>Scrollable<br>Scrollable<br>Scrollable<br>Scrollable<br>Scrollable<br>Scrollable<br>Scrollable<br>Scrollable<br>Scrollable<br>Scrollable<br>Scrollable<br>Scrollable<br>Scrollable<br>Scrollable<br>Scrollable<br>Scrollable<br>Scrollable<br>Scrollable<br>Scrollable<br>Scrollable<br>Scrollable<br>Scrollable<br>Scrollable<br>Scrollable<br>Scrollable<br>Scrollable<br>Scrollable<br>Scrollable<br>Scrollable<br>Scrollable<br>Scrollable<br>Scrollable<br>Scrollable<br>Scrollable<br>Scrollable<br>Scrollable<br>Scrollable<br>Scrollable<br>Scrollable<br>Scrollable<br>Scrollable<br>
</div>
</body>
</html>
Solution 2 (uses experimental features, may not support some browsers)
Just add the nobars class to any element you want to hide the scrollbars on.
.nobars {
/* Firefox: https://developer.mozilla.org/en-US/docs/Web/CSS/scrollbar-width */
scrollbar-width: none;
/* IE: https://msdn.microsoft.com/en-us/library/hh771902(v=vs.85).aspx */
-ms-overflow-style: none;
}
.nobars::-webkit-scrollbar {
/* Chrome/Edge/Opera/Safari: https://css-tricks.com/custom-scrollbars-in-webkit/ */
display: none;
}
Solution 3 (cross browser javascript)
Perfect Scrollbar doesn't require jQuery (although it can utilise jQuery if installed) and has a demo available here. The components can be styled with css such as in the following example:
.ps__rail-y {
display: none !important;
}
Here is a complete example including the implementation of Perfect Scrollbar:
<link rel="stylesheet" href="css/perfect-scrollbar.css">
<style>
#container {
position: relative; /* can be absolute or fixed if required */
height: 200px; /* any value will do */
overflow: auto;
}
.ps__rail-y {
display: none !important;
}
</style>
<script src='dist/perfect-scrollbar.min.js'></script>
<div id="container">
Scrollable<br>Scrollable<br>Scrollable<br>Scrollable<br>Scrollable<br>Scrollable<br>Scrollable<br>Scrollable<br>Scrollable<br>Scrollable<br>Scrollable<br>Scrollable<br>Scrollable<br>Scrollable<br>Scrollable<br>Scrollable<br>Scrollable<br>Scrollable<br>Scrollable<br>Scrollable<br>Scrollable<br>Scrollable<br>Scrollable<br>Scrollable<br>Scrollable<br>Scrollable<br>Scrollable<br>Scrollable<br>Scrollable<br>Scrollable<br>Scrollable<br>Scrollable<br>Scrollable<br>Scrollable<br>Scrollable<br>Scrollable<br>Scrollable<br>Scrollable<br>Scrollable<br>Scrollable<br>Scrollable<br>Scrollable<br>
</div>
<script>
// on dom ready...
var container = document.getElementById("container");
var ps = new PerfectScrollbar(container);
//ps.update(container);
//ps.destroy(container);
</script>
You dont have to use jquery or js to make this. Its more performant with simple webkit.
Just add the code below to your css file.
::-webkit-scrollbar {
display: none;
}
Caution !
This will disable all the scrollbar so be sure to put it in a specific class or id if you just want one to be hidden.
I much prefer SamGoody's answer provided to a duplicate of this question. It leaves native scrolling effects intact, instead of trying to manually re-implement for a few particular input devices:
A better solution is to set the target div to overflow:scroll, and wrap it inside a second element that is 8px narrower, who's overflow:hidden.
See the original comment for a fleshed-out example. You may want to use JavaScript to determine the actual size of scrollbars rather than assuming they are always 8px wide as his example does.
To get this working for me, I used this CSS:
html { overflow-y: hidden; }
But I had problems using $(this).scrollTop(), so I bound to my #id, but adjusted the scrollTop of window. Also, my smooth scrolling mouse would fire lots of 1 or -1 deltas, so I multiplied that by 20.
$("#example").bind("mousewheel", function (ev, delta) {
var scrollTop = $(window).scrollTop();
$(window).scrollTop(scrollTop - Math.round(delta * 20));
});
As Baldráni said above
::-webkit-scrollbar { display: none; }
Or you can do
::-webkit-scrollbar{ width: 0px; }
(posted for other people that stumble on this from google search!)
Well, perhaps not the most intuitive in my opinion, but I can imagine you being able to make it a decent experience, give this a try.
overflow:hidden;
make sure the parent object has a height and width, and displays as block