whatwg / dom

DOM Standard
https://dom.spec.whatwg.org/
Other
1.56k stars 290 forks source link

document.createEvent() should maybe not be conditional upon exposure #952

Open annevk opened 3 years ago

annevk commented 3 years ago

Apparently TouchEvent is always exposed in Chrome, but document.createEvent("touchevent") depends on the "touch events flag" (see https://github.com/w3c/touch-events/issues/64). Having said that, neither Firefox nor Safari expose TouchEvent so maybe Chrome should change?

cc @patrickhlauke @RByers

(Firefox bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1693172.)

patrickhlauke commented 3 years ago

I vaguely remember asking before somewhere, but: philosophically, does it not make sense to expose TouchEvent (as an API that the browser understands/supports) regardless of presence of an actual touchscreen? Are there other APIs that are simply not exposed (as if the browser didn't understand them / support them at all) in the absence of certain conditions?

And yes, Chrome's selective support for certain properties/calls based on the actual presence of a touchscreen is a hacky workaround to naive "mobile-only" detection that assumed "if there's a touchscreen, then i can just listen to touch events as it's mobile ... no need to use mouse events or keyboard / can just switch the the 'mobile' version of the site / etc"

annevk commented 3 years ago

It makes sense, but it might well break code that does

if ("TouchEvent" in self) { ... }

and the precedent was set by WebKit as I understand it, so legacy code would assume WebKit's model.

patrickhlauke commented 3 years ago

so legacy code would assume WebKit's model.

I seem to remember (but Googlers may have more detail) that the internal touch events flag thing and deciding when to be truthful (yes, of course we know what Touch Events are, even if you don't have an actual touchscreen) and when to lie came mostly from looking at (then already) legacy code to see how sites were doing naive "isMobile?" type sniffing and then essentially only listening for touch events and not mouse/keyboard - breaking sites on touch-enabled laptops/desktops. This may have been based on data analysis of "what's the most prevalent pattern that sites use for this sort of naive detection", but I'm not sure).

If that's now less of a problem (?) then I guess it does make sense to go with the wonky WebKit precedent...

RByers commented 3 years ago

Mobile Safari exposes TouchEvent, right? Desktop Safari doesn't support touch at all, so no surprise not to have it there. Anyway further alignment on any differences between browsers SGTM. Anything in mobile Safari or Firefox for Android is probably sufficiently web compatible for chromium to try.

Over to @flackr who leads input on Chrome these days (I'm not sure who on the team might be working in this area).

patrickhlauke commented 3 years ago

sorry, I realised just now that I almost repeated everything I said a few days ago already in my second comment. Serves me right to try and "catch up" with threads without seeing what I might have previously said.

In any case, as long as this doesn't end up breaking sites on touch-enabled desktop/laptop (to the point where users are locked out of using mouse/keyboard and forced to use touch) somehow, it probably makes sense to align...

flackr commented 3 years ago

Mobile Safari does indeed expose TouchEvent. My understanding is that desktop Safari never supports touch (is compiled without support). I created a test page https://output.jsbin.com/pipudek which tests a few means of detecting touch support.

Test Chrome Desktop Firefox Desktop Safari Desktop Chrome Mobile Firefox Mobile Safari Mobile
'TouchEvent' in window true false / true* false true true true
document.createEvent('touchevent') throws throws throws object object object
typeof(TouchEvent) function undefined / function* undefined function function function
'ontouchstart' in window false false false true true true

* Depends if local device supports touch

Is the proposal is to not expose TouchEvent, but still dispatch TouchEvents to touch event handlers? I worry existing sites may be using UA detection to decide whether to include references to TouchEvent, which would then turn into errors if we were to do this.

annevk commented 3 years ago

I don't have a concrete proposal, but it seems Firefox's behavior would allow you to detect touch support across all browsers, whereas what Chrome shipped defeats that? Maybe that's okay though.

I should also note that since I filed OP I learned that a simple flag as suggested in https://github.com/w3c/touch-events/issues/64 might not be enough (as your table also shows), depending on which way we go.

smaug---- commented 3 years ago

@RByers Is the anyway in desktop Chrome to detect touch support? Perhaps using navigator.maxTouchPoints ?

RByers commented 3 years ago

Chrome desktop always has "touch support". A user could plug in a touch device at any moment, including devtools emulation etc. More commonly many Windows machines appear to have "touch devices" the user never actually uses or knows about (IIRC Visual Studio installs an emulated touchscreen driver that's indistinguishable to us from a real touch screen, and we had user complaints about using a touch laptop with external screen/keyboard).

I forget all the details (@flackr can reflect current expertise/guidance), but I think the 'pointer' and 'hover' media queries are what we consider the 'right' way to detect whether a user is likely to use touch as their input modality. I.e. asking "does the browser/hardware support touch" is usually the wrong question, instead "should I be optimizing my UI for larger targets" and "should I expect the user has the ability to 'hover' their pointing device'.

https://hacks.mozilla.org/2013/04/detecting-touch-its-the-why-not-the-how/

patrickhlauke commented 3 years ago

who's that handsome gentleman that wrote that hacks article, i wonder...i'd say it's good to consider this chaser as well though https://css-tricks.com/interaction-media-features-and-their-potential-for-incorrect-assumptions/

patrickhlauke commented 3 years ago

incidentally, one case i remember where i site made a naive/wrong assumption about touch support - flickr on a Surface. they fixed this after I reported it though. https://www.youtube.com/watch?v=f_2GKsI9TQU

RByers commented 3 years ago

😄 Awesome, hadn't seen that one Patrick.

BTW you can tell it's performance review season at Google when I start engaging with low-latency on GitHub issues (wishing I still got to hack on this stuff with you awesome folks instead of doing management crap) 😉 .

flackr commented 3 years ago

I don't have a concrete proposal, but it seems Firefox's behavior would allow you to detect touch support across all browsers, whereas what Chrome shipped defeats that? Maybe that's okay though.

I should also note that since I filed OP I learned that a simple flag as suggested in w3c/touch-events#64 might not be enough (as your table also shows), depending on which way we go.

We used to enable / disable touch API's based on the existence of a touchscreen but ran into the issues @RByers mentioned above.

@RByers Is the anyway in desktop Chrome to detech touch support? Perhaps using navigator.maxTouchPoints ?

This does indeed reflect whether Chrome currently believes it has a touchscreen attached however it can change dynamically when you attach a touchscreen or enable touch emulation in dev tools. I've noticed the detection can also can be a little flaky (on my ChromeOS Linux container running desktop Chrome Linux it claims 0 even though it fires touchevents).

As @RByers mentioned we encourage developers to handle both types of events and use media queries to determine whether they should size elements for touch or not. Note that the pointer / hover media queries effectively answer the opposite question, does the user have a mouse capable of hovering, you can use any-pointer / any-hover as @patrickhlauke noted in his article, optionally using window.matchMedia to observe changes to these queries, e.g. https://jsbin.com/daqedes/edit?js,output

P.S. apologies if this no longer adds value, other replies came in while I was still writing this :-)

zcorpan commented 2 years ago

Is there a recommendation here? Should we specify what Chromium does? It is evidently web compatible (at least for Chromium-based browsers) to expose window.TouchEvent always. It also seems more flexible since a desktop browser could have touch supported and web devs could still use touch events, only not the event handlers or createEvent.

zcorpan commented 2 years ago

Gecko seems to have two levels of API exposure:

References

So I think Gecko matches Chromium when dom_w3c_touch_events_enabled is 1 (or autodetected as enabled).

annevk commented 2 years ago

@cdumez @smaug---- thoughts? Aligning with Chrome here seems relatively straightforward and it is somewhat nice that at least the event constructors would end up being consistently exposed.

smaug---- commented 2 years ago

Curious to know if that would break sites which don't expect TouchEvent constructor especially with desktop Safari.

Does Chrome expose TouchEvent even on Mac where the interface is never used?

annevk commented 2 years ago

Yeah it does.

gsnedders commented 2 years ago

Is there a recommendation here? Should we specify what Chromium does? It is evidently web compatible (at least for Chromium-based browsers) to expose window.TouchEvent always. It also seems more flexible since a desktop browser could have touch supported and web devs could still use touch events, only not the event handlers or createEvent.

It is evidently web compatible at least for Chromium-based browsers, yes. But there's historically been content that has relied on the presence of TouchEvent to distinguish mobile Safari from desktop Safari, so there is still web compat risk for Safari from that. (There's also—inevitably—some risk in shipping more code.)

zcorpan commented 2 years ago

OK.

If WebKit is unable to change this, the spec can document this lack of interop through the navigator compatibility mode.

I ran a query on the 10k sample mobile pages in httparchive for pages containing "window.TouchEvent". There were 163 matches. I haven't looked at them, but you could look for evidence that there are web pages that would break in desktop Safari (or macOS Firefox) before trying to ship the suggested change.

https://docs.google.com/spreadsheets/d/1G3qs7i6V2E5NWVPHZY5E1GAHFYwo1frDxoLhqaYIQrU/edit#gid=752407919

Query ``` SELECT * FROM ( SELECT page, url, REGEXP_EXTRACT(body, r'(\bwindow\.TouchEvent\b)') AS match FROM `httparchive.sample_data.response_bodies_mobile_10k` ) WHERE match IS NOT NULL ```
hsivonen commented 2 years ago

What does Epiphany do?

howard-e commented 2 years ago

@zcorpan shared:

I ran a query on the 10k sample mobile pages in httparchive for pages containing "window.TouchEvent". There were 163 matches. I haven't looked at them, but you could look for evidence that there are web pages that would break in desktop Safari (or macOS Firefox) before trying to ship the suggested change. https://docs.google.com/spreadsheets/d/1G3qs7i6V2E5NWVPHZY5E1GAHFYwo1frDxoLhqaYIQrU/edit#gid=752407919

Created a copy of this worksheet to expand on it. Using an extension to modify and intercept calls done to window.TouchEvent, found that at least one of the sites in the list was affected. It displayed a difference in the layout when window.TouchEvent was nullified. This can be viewed at https://docs.google.com/spreadsheets/d/1VQW1ZFP-FEsGoSpEfy6VpThsqKBuksJZ3bnYlDOZXjg/edit?usp=sharing.

Additional notes also detail the supposed use with which checking for window.TouchEvent, may be trying to perform.

The original list hasn’t been exhausted as yet.

zcorpan commented 2 years ago

Thanks @howard-e ! To clarify the methodology, you tested in Desktop Safari with the "Userscripts" extension (or maybe "Tampermonkey"), with a user script something like:

// ==UserScript==
// @name        TouchEvent compat research
// @description Expose window.TouchEvent
// @match       *://*/*
// ==/UserScript==

Object.defineProperty(window, 'TouchEvent', {
  get: () => {
    console.log('TouchEvent getter called');
    debugger;
  }
});

and then load each page and check if the layout is different or if something is clearly broken.

And out of the 45 pages analyzed, 1 page (https://meridian.broker/) had different layout, for the chat bot thing.

I couldn't see any difference, though. Can you post screenshots? Does it only happen at certain viewport widths?