I am a JavaScript noob and I need some help to write my code. I have a scrollable div inside a (bigger) Layout that is another framework (not HTML/JavaScript). In this Layout, you can swipe horizontally BUT it doesn't detect touch events if the touch start is over the HTML div. I figured out that the reason is that HTML pointer-events take priority over the other framework's touch events. So, I decided I need to detect whether swipe is in the x-axis (horizontal swipe) and disable pointer-events for that div, OR whether the swipe is in the y-axis (meaning that the user is scrolling the div) and (re)enable pointer-events.
I don't want to ask you to write my code, but I am really a JS noob and I would be very grateful if someone could complete this code.
var el = document.getElementById("swipeArea");
var swipeStartX;
var swipeStartY;
//On any touch start {
swipeStartX = //touch.AbsoluteX ;
swipeStartY = //touch.AbsoluteY ;
setTimeout(checkDirection, 100);
//set the value for the two variables, wait 100 ms and call checkDirection
//}
function checkDirection() {
if (Math.abs(swipeStartX-Touch.AbsoluteX) > Math.abs(swipeStartY-Touch.AbsoluteY)) {
//if horizontal swipe, disable pointer-vents
el.style.pointerEvents = "none";
} else {
//if vertical swipe, enable pointer-events
el.style.pointerEvents = "initial";
}
}
//This is the logic I need, but I really have no idea on how to detct touch events
//And, very important: if pointer-events are disabled and the function checkDirection
//reenables them, will the user be able to scroll without having to release his touch
//and start again??
//Thank you for your help! :)
div {
height: 300px;
width: 300px;
background: turquoise;
}
<div id="swipeArea"></div>
Related
I'm having a vague bug while scrolling in a browser on an iOS device (iPad), it works 90% of the time but 10% it the scrolling is blocked. I then have to wait for a couple of seconds before it works again. This often happens after I've contracted/expanded a filter panel, which is also a scrollable component.
On all other devices, the scrolling is no issue whatsoever. I've looked everywhere on the internet but I couldn't find anyone with a similar problem?
My two scrollable components do have overflow-y: scroll and
-webkit-overflow-scrolling: touch, but in general I highly doubt it's a CSS issue as it works most of the time, just not at random times.
I have tried adding onTouchStart={ () => {} } to my component, but also that doesn't solve it.
This problem is still here in iOs15, and I developed a small fix and put it on GitHub.
Complete code here:
https://github.com/AlessandroCipolletti/fix-ios15-safari-scroll/blob/main/preventScrollBugsIfNeeded.ts
I noticed that the bug happens only when the scrollable content is "all on top" or "all at the end" of its scroll space.
I mean, when there is no scroll available in one of the two directions (top-bottom / left-right makes no difference for the occurrence of the bug).
So the idea is to check if this is the case during a touchstart event, and if so, make a 1px scroll by code.
I don't know why iOS "needs" this to make a proper scroll, but it works fine for me.
// do this inside a onTouchStart event handler:
const target = myScrollableContainer
// if it has vertical scroll
if (target.scrollHeight > target.clientHeight) {
// if scroll is on top
if (target.scrollTop === 0) {
// move content 1px up
target.scrollTop = 1
} else
// if scroll in at the bottom
if (target.scrollTop === (target.scrollHeight - target.clientHeight)) {
// move content 1px down
target.scrollTop = (target.scrollHeight - target.clientHeight) - 1
}
}
// if it has horizontal scroll
if (target.scrollWidth > target.clientWidth) {
// if scroll is at the beginning (left)
if (target.scrollLeft === 0) {
// move content 1px to the left
target.scrollLeft = 1
} else
// if scroll is at the end (right)
if (target.scrollLeft === (target.scrollWidth - target.clientWidth)) {
// move content 1px to the right
target.scrollLeft = (target.scrollWidth - target.clientWidth) - 1
}
}
I've come across this bug before. It seems to arise when setting elements to be the height of the browser viewport (e.g., height: 100vh). Try setting this on your <body> element:
body {
position: relative;
}
I can't find a solution to this, there was a question over here, but the answers are not very usable (at least for me).
I have a JavaScript modal pop-up that disables everything on the background by placing transparent div over the page. It also disables the scrolling by setting the overflow to hidden, and must do so, because the page is scrollable with the mouse wheel otherwise and distracts the user.
The problem is, when hiding and showing the scrollbar the page resizes and the effect is ugly. Also, my page is designed in such a way that if I stop it from resizing that would be ugly either.
What I want is to disable the scrollbar, but keep it visible (the page content is longer than the screen fits). Is this somehow possible in CSS?
Instead of changing the css, which will remove the scrollbar, and as you said change the layout of the page, try calling a jquery function instead.
// call your pop up and inside that function add below
$('body').on('scroll mousewheel touchmove', function(e) {
e.preventDefault();
e.stopPropagation();
return false;
});
then when you close the modal, call the same function but replace on with off
Since scrollbars are not all 17px wide, I solved this with JavaScript. That is, I calculated the exact width of the scrollbar and added an equal amount of margin to the right of the body element. This also works when the scrollbar isn't present due to a high resolution or a lack of content.
function toggleMenu() {
// get width before hiding scrollbar
let oldWidth = document.documentElement.clientWidth;
// toggle CSS class that sets overflow to hidden
document.body.classList.toggle('MenuOpen');
// get new width after hiding scrollbar
let newWidth = document.documentElement.clientWidth;
// set margin-right value equal to width of the scrollbar
let scrollbarWidth = Math.max(0, newWidth - oldWidth);
document.body.style.marginRight = `${scrollbarWidth}px`;
}
...and my CSS looks like:
html {
background-color: #e6e6e6; /* color of fake scrollbar */
}
body.MenuOpen {
overflow: hidden;
}
Once you start showing your popup, give the body a class (like popupOpen). This should be an easy workaround.
.popupOpen {
overflow: hidden;
margin-right: 17px //size of the scrollbar in each browser
}
When you close your popup, simply remove the class from the body.
I want to call some actions, when the user is scrolling in iScroll4. Also depending on the position and speed on the scrolling.
Where and how to hook in best to achive this?
With addListener I had no luck, because it reacts on on-time events, eg. Touchmove, touchstart. What i need is to know when the div is scrolling..
Any ideas?
There are lot of callback functions iScroll. You can use those for your purposes.
A small explanation about those.
scroller = new iScroll('ID', {
onRefresh : function(){
/* iScroll provided feature to refresh the scroller. This will help to refresh the scroller container when you dynamically add contents. */
},
onBeforeScrollStart : function(e){
/* this is nothing but just when your mousedown event (This will be triggered each and every mousedown event). This is very useful when your parent container have scroller and your child container also have scroller. Assume this is your child scroller. What you can do is just get your parent scroller object (parentScroller) and disable it "parentScroller.disable()" */
},
onScrollStart : function(){
/* now you start to move your mouse while holding mouse left button */
},
onBeforeScrollMove : function(){
/* this where your scroller is start to move actually */
},
onScrollMove : function(){
/* now your scroller is moving. If you need to do something, when your scroller is moving you can do those here */
},
onBeforeScrollEnd : function(){
/* your scroller movement is about to stop */
},
onScrollEnd : function(){
/* your scorller movement stoped. Will say you have disable your parent scroller. Now this is the good place to enable your parent scroller "parentScroller.enable()"*/
},
onDestroy : function(){
/* you destroy your scroller. iScroll is provide a feature to remove the attached sctoller. */
}
});
I just gave you a small explanation about the some of callback functions. But there are some more exists such as onTouchEnd, onZoomStart, onZoom, onZoomEnd. You can experiment those if you need.
I hope this might help you to sort out issue.
Latest Update to get the position and speed of the scroller.
scroller = new iScroll('ID', {
onScrollMove : function(e){
/* this function return an object in which it has almost all the required stuffs. */
}
});
For your reference console.log(e) and analyze the value e has. It return lot of x & y positions. From those you can get the scroller position directly. But to get the speed of the scroller you have to use physics ;). It returns timestamp, scroller position. I think you might to able to get the speed using these values. I am sorry at the moment I could not analyze these values to exactly say how you can get the speed. But I think you can calculate speed using the values available.
The scroll event is available on iScroll probe edition only (iscroll-probe.js). The probe behavior can be altered through the probeType option.
you can include "iscroll-probe.js" in your html and :
var myScroll = new IScroll('#container', { probeType: 3, mouseWheel: true });
myScroll.on('scroll',function(){
var top = parseInt(-this.y);// scrolltop value
//do something with top
})
I have a page with a section to sketch a drawing in. But the touchmove events, at least the vertical ones, are also scrolling the page (which degrades the sketching experience) when using it on a mobile browser. Is there a way to either a) disable & re-enable the scrolling of the page (so I can turn it off when each line is started, but turn it back on after each is done), or b) disable the default handling of touchmove events (and presumably the scrolling) that go to the canvas the sketch is drawn in (I can't just disable them completely, as the sketching uses them)?
I've used jquery-mobile vmouse handlers for the sketch, if that makes a difference.
Update: On an iPhone, if I select the canvas to be sketched in, or just hold my finger for a bit before drawing, the page doesn't scroll, and not because of anything I coded in the page.
Set the touch-action CSS property to none, which works even with passive event listeners:
touch-action: none;
Applying this property to an element will not trigger the default (scroll) behavior when the event is originating from that element.
Note: As pointed out in the comments by #nevf, this solution may no longer work (at least in Chrome) due to performance changes. The recommendation is to use touch-action which is also suggested by #JohnWeisz's answer.
Similar to the answer given by #Llepwryd, I used a combination of ontouchstart and ontouchmove to prevent scrolling when it is on a certain element.
Taken as-is from a project of mine:
window.blockMenuHeaderScroll = false;
$(window).on('touchstart', function(e)
{
if ($(e.target).closest('#mobileMenuHeader').length == 1)
{
blockMenuHeaderScroll = true;
}
});
$(window).on('touchend', function()
{
blockMenuHeaderScroll = false;
});
$(window).on('touchmove', function(e)
{
if (blockMenuHeaderScroll)
{
e.preventDefault();
}
});
Essentially, what I am doing is listening on the touch start to see whether it begins on an element that is a child of another using jQuery .closest and allowing that to turn on/off the touch movement doing scrolling. The e.target refers to the element that the touch start begins with.
You want to prevent the default on the touch move event however you also need to clear your flag for this at the end of the touch event otherwise no touch scroll events will work.
This can be accomplished without jQuery however for my usage, I already had jQuery and didn't need to code something up to find whether the element has a particular parent.
Tested in Chrome on Android and an iPod Touch as of 2013-06-18
There is a little "hack" on CSS that also allows you to disable scrolling:
.lock-screen {
height: 100%;
overflow: hidden;
width: 100%;
position: fixed;
}
Adding that class to the body will prevent scrolling.
document.addEventListener('touchstart', function(e) {e.preventDefault()}, false);
document.addEventListener('touchmove', function(e) {e.preventDefault()}, false);
This should prevent scrolling, but it will also break other touch events unless you define a custom way to handle them.
The ultimate solution would be setting overflow: hidden; on document.documentElement like so:
/* element is an HTML element You want catch the touch */
element.addEventListener('touchstart', function(e) {
document.documentElement.style.overflow = 'hidden';
});
document.addEventListener('touchend', function(e) {
document.documentElement.style.overflow = 'auto';
});
By setting overflow: hidden on start of touch it makes everything exceeding window hidden thus removing availability to scroll anything (no content to scroll).
After touchend the lock can be freed by setting overflow to auto (the default value).
It is better to append this to <html> because <body> may be used to do some styling, plus it can make children behave unexpectedly.
EDIT:
About touch-action: none; - Safari doesn't support it according to MDN.
try overflow hidden on the thing you don't want to scroll while touch event is happening. e.g set overflow hidden on Start and set it back to auto on end.
Did you try it ? I'd be interested to know if this would work.
document.addEventListener('ontouchstart', function(e) {
document.body.style.overflow = "hidden";
}, false);
document.addEventListener('ontouchmove', function(e) {
document.body.style.overflow = "auto";
}, false);
I found that ev.stopPropagation(); worked for me.
To my surprise, the "preventDefault()" method is working for me on latest Google Chrome (version 85) on iOS 13.7. It also works on Safari on the same device and also working on my Android 8.0 tablet.
I am currently implemented it for 2D view on my site here:
https://papercraft-maker.com
this worked for me on iphone
$(".owl-carousel").on('touchstart', function (e) {
e.preventDefault();
});
the modern way (2022) of doing this is using pointer events as outlined here in the mozilla docs: https://developer.mozilla.org/en-US/docs/Web/API/Pointer_events
Pointer events build on touchstart and other touch events and actually stop scroll events by default along with other improvements.
I am using media queries to make a responsive site. That isn't my problem but it is why I am here today with this question.
At a certain browser width, my horizontal navigation at the top of my page becomes too wide (becomes squished) and looks awkward in my layout. What I want to do is this: When a users browser reaches a certain min-width, I would like to (using js) hide the horizontal navigation (an unordered list of 6) that originally rendered on the users screen (if you are viewing wider than 650px) and replace it with a single 'button' that when clicked drops down the un-ordered list.
Now, the CSS isnt the problem. I just cant seem to figure out how to do the transition from the original horizontal nav that originally renders, to a more user friendly navigation.
A simple solution would be to have 2 sets of navigation mechanisms. Hide one and show the other.
You will need to add an eventlistener on the resize event for document, where you will check the innerWidth of the window and decide which navigation div to display.
document.addEventListener("resize", function () {
if (window.innerWidth < 650) {
document.getElementById("horizontal_nav").style.display = "block";
document.getElementById("dropdown_nav").style.display = "none";
} else {
document.getElementById("dropdown_nav").style.display = "none";
document.getElementById("horizontal_nav").style.display = "block";
}
});
Alternatively, you can keep your horizontal navigation but specify a max-width of 650px, once this has been reached, it will stop growing.
div#horizontal_nav {
width: 100%;
max-width: 650px;
}
Maybe these can help:
http://www.bram.us/2011/10/24/jquery-mobile-select-jquery-mobile-navigation-replacement-plugin/
https://github.com/joggink/jquerymobiledropdown
I know. It´s jQuery but I hope ppl get the general idea.