Skip to content
This repository has been archived by the owner on Feb 11, 2021. It is now read-only.

Try to support CSS touch-action rather than using attributes #151

Closed
jzaefferer opened this issue Jan 12, 2015 · 41 comments
Closed

Try to support CSS touch-action rather than using attributes #151

jzaefferer opened this issue Jan 12, 2015 · 41 comments
Assignees

Comments

@jzaefferer
Copy link
Contributor

Browsers like Chrome that have native support for the CSS property make this easy, otherwise its necessary to load the original stylesheet via ajax and parse them manually, since unsupported CSS properties are just dropped when the browser parses them.

@scottgonzalez
Copy link
Contributor

Investigate what hammer.js is doing: https://github.com/hammerjs/hammer.js/blob/master/src/touchaction.js

@bethge
Copy link
Contributor

bethge commented Apr 19, 2015

If I understand correctly, hammer.js gets TouchAction properties passed via the constructor (see their testcases). If the browser supports touch-action, hammer.js adds / overwrites the touch-action CSS property otherwise it polyfills. In my tests it didn't consider existent touch-action CSS rules. It defaults to touch-action: pan-y.

@stuartpb
Copy link
Contributor

Also worth tracking the work being done by the Houdini WG to surface more CSS features to scripts

@stuartpb
Copy link
Contributor

stuartpb commented Jun 9, 2015

Here's how hand.js does it: https://github.com/deltakosh/handjs/blob/master/src/hand.css.js

@arschmitz
Copy link
Contributor

Unless i'm missing something it looks like the handjs approach only runs once when the page initially loads and will not account for elements added at any point after that.

@arschmitz
Copy link
Contributor

As a follow up to conversations with the hammer.js team and in todays meeting we should attempt to collaborate on the best way to handle touch action. @jacobrossi has also offered to put the two teams in touch with someone from http://ecsstender.org/ to see what we can do about attempting to support the actual css.

ref hammerjs/hammer.js#809

@aarongustafson
Copy link

When I was working on eCSStender, Ajax was the only way to accurately get the CSS info. @jzaefferer is dead on with that. That said, we have a fully-functioning CSS parser in JS. I haven’t touched it in a while, so it could probably be optimized, but it’s there.

@arschmitz
Copy link
Contributor

@aarongustafson our main concern here I think is performance size, PEP is just a polyfill so we would not want to add too much overhead to it. There is only a single css property that we care about so ideally we would want to highly optimize around that.

@jacobrossi Am i crazy or didn't you tell me there was a way to get the raw stylesheet in IE to avoid the ajax? Not that that helps else where but its something...

@aarongustafson
Copy link

In terms of bare-bones implementation, what you’re gonna need is a parser
that grabs the raw CSS and then figures out which rule sets contain the
property, grabs their selectors and runs specificity comparisons against
any other instances of that property (in case it gets turned off for
certain elements). If there are any other factors to consider (some
properties negate others, like flexbox does for floats), you’ll want to
search on them too.

The actual CSS file parser in eCSStender isn’t all that big. Neither is the
specificity calculator. You should be able to use those relatively easily.
And since you only care about this one property, you might even be able to
optimize the parser to hunt for the property and then back up to the
containing rule set.

I’d recommend cacheing the result (and the raw CSS) in localStorage so you can see if you need to re-run the expensive processing before you do so. In eCSStender, I believe I compared timestamps on the cached and remote CSS file to avoid the double download if possible (by doing a header lookup) or I may have looked at the expires header and stamped the file in localStorage`. Without digging deep into the source again (which I don’t
have the time for today) I can’t say for sure; it’s been a few years.

On Thu, Jul 16, 2015 at 2:01 PM, Alexander Schmitz <notifications@github.com

wrote:

@aarongustafson https://github.com/aarongustafson our main concern here
I think is performance size, PEP is just a polyfill so we would not want to
add too much overhead to it. There is only a single css property that we
care about so ideally we would want to highly optimize around that.

@jacobrossie Am i crazy or didn't you tell me there was a way to get the
raw stylesheet in IE to avoid the ajax? Not that that helps else where but
its something...


Reply to this email directly or view it on GitHub
#151 (comment).

@arschmitz
Copy link
Contributor

@aarongustafson
So i guess the big questions here are based on your experience with eCSStender do you think it is feasible based on a couple things

  1. Currently we use this to determine what elements we should be listening to events on using a mutation observers. https://github.com/jquery/PEP/blob/43ce883b0b03c85af0d7765863e444838fb2dadc/src/installer.js Could we work with the css prop in a similar way?
  2. Keeping in mind that we only have a single property we care about and that there are no other properties that negate or effect it. ( spec maintainers please jump in if i'm wrong on this ). Could this potentially be optimized enough to include within a library this size?
  3. For number 1 all we care about is if there is a touch action property at all not what that value is. at the time the events are actually emitted we need to then know the value to determine what if any events we will emit. Do you foresee a performance issue in either of these situations.

Not looking for firm answers or anything just wondering if you think there is anyway this is feasible or if based on your experience is this just a no go for our use case?

@stuartpb
Copy link
Contributor

I think postcss is probably the most well-known/maintained JS CSS parser today: https://github.com/postcss

Also, since, again, this is a domain that the Houdini WG is supposed to be tackling, it might be worth following their https://wiki.css-houdini.org/background page (though admittedly it doesn't appear to have any relevant resources to this right now).

@patrickhlauke
Copy link
Collaborator

[...] we only have a single property we care about and that there are no other properties that negate or effect it [...]

Just a side-note to say that yes, that's correct, and there is also no inheritance, which may simplify matters https://w3c.github.io/pointerevents/#the-touch-action-css-property

@arschmitz
Copy link
Contributor

@patrickhlauke thank you for confirming that and yeah I forgot about no inheritance that simplifies it too. That means we only need to find containing rules, and compare the selector specificity if there is more then one that applies.

@stuartpb Yeah i don't think we want or need a full css parser we only need to find rules actually containing and compare selector specificity to pick the right one. The Houdini group while applicable i don't think will be seeing any useable results in the time frame that this will really matter here but worth keeping an eye out for forsure.

@patrickhlauke
Copy link
Collaborator

also, perhaps an edge case, but: worth also checking any style="..." attributes on the element for any touch-action:... ?

@arschmitz
Copy link
Contributor

@patrickhlauke that actually brings to mind an interesting idea here to super easily support this with strict limits. So right now we require you to use an attribute touch-action='. Supporting css style sheets is super gross and complicated no way around it. It also would always have to still exclude crossdomain stylesheets. what about if we only supported touch action in a style attribute? Is it perfect no. But its valid css that will work normally where supported and its no worse then the attribute its still part of the markup now its just valid css and we wont have to write a stylesheet for these elements any more https://github.com/jquery/PEP/blob/43ce883b0b03c85af0d7765863e444838fb2dadc/src/touch-action.js.
I would really like to hear others thoughts on this?
cc/ @jacobrossi @runspired

@jzaefferer jzaefferer mentioned this issue Jul 24, 2015
@msegado
Copy link

msegado commented Jul 27, 2015

@patrickhlauke @arschmitz - supporting touch-action in inline styles seems like both (1) a good idea when compared to the attribute, and (2) a good idea for folks that use inline styles instead of stylesheets for, e.g., React components.

@arschmitz
Copy link
Contributor

@msegado Agreed i have a POC for this ill be posting very shortly just working out a few things.

@msegado
Copy link

msegado commented Jul 27, 2015

@arschmitz Sweet!

Yet another benefit: it'll allow default browser behavior for those that support touch-action (e.g. Chrome) without the need to keep an attribute + stylesheet in sync. This is beneficial for preventing zoom on double-tap (#211) and also removes the 300ms click delay!

@stuartpb
Copy link
Contributor

So to sum up my understanding:

Right now, PEP tells users that they need to specify a PEP-specific touch-action="none" attribute on any element to support touch for pointer events from PEP, and a touch-action: none CSS rule somewhere to support touch for native pointer event implementations.

This would change it so users could specify a touch-action: none rule inline on the element for PEP to support touch pointer events, and while they can choose to specify it in a stylesheet as well, redundantly, they need to make sure that it gets inlined if PEP is used (with the attribute still being supported for legacy reasons, but deprecated).

Sounds good to me.

One thought: does PEP have some kind of callback or reporting mechanism that would allow code to only execute if PEP is being used to provide pointer events (rather than native pointer events)? If not, I think that would be a good idea, since it would allow implementations to add this inlined rule conditionally based on some kind of application-specific logic.

@patrickhlauke
Copy link
Collaborator

a simple check for window.PointerEvent should allow devs to see if the browser natively supports Pointer Events, and from that deduce whether PEP did or didn't kick in, I guess

@arschmitz
Copy link
Contributor

Worked on a POC for using the native style over the weekend. I implemented it in a small fast-click we have been working on for hammer.js that was previously using the touch-action attribute like PEP.

There is one main gotcha to this which is if the style attributes properties are set directly the browser will sanitize the style attribute of any invalid properties. To work around this I used a mutation observer to restore the touch-action property when ever it was removed. PEP is already using a mutation observer to watch the touch-action attribute so this would not be a big change

code: https://github.com/hammerjs/hammer-time/blob/master/hammer-time.js
demo: https://rawgit.com/hammerjs/hammer-time/master/index.html

@stuartpb PEP currently creates a stylesheet and sets touch action for elements within it to support native implementations of touch-action https://github.com/jquery/PEP/blob/master/src/touch-action.js

@msegado
Copy link

msegado commented Jul 27, 2015

@arschmitz @stuartpb Huh, it's actually only creating the stylesheet if window.PointerEvent exists, which explains the issue I was having with Chrome in #211 (Chrome supports the touch-action CSS property but does not yet support native pointer events). I'll comment more over there.

@arschmitz
Copy link
Contributor

@msegado ah your right we will need to fix that. This was written before chrome supported touch-action so at the time this was a valid check. We will need to update this if we stick with the attribute.

@runspired
Copy link

http://stackoverflow.com/questions/4565112/javascript-how-to-find-out-if-the-user-browser-is-chrome

Despite it's downvote for mechanical reasons, window.chrome && window.chrome.webstore might be the simplest test you could add to check for chrome.

@arschmitz
Copy link
Contributor

@runspired I think in this case we should just switch from looking for
window.pointerEvent
to
document.documentElement.style[ "touch-action" ] !== undefined

It will do what we actually want which is install when native touch-action is supported

@runspired
Copy link

👍

@msegado
Copy link

msegado commented Jul 27, 2015

@arschmitz Agreed. (I think IE10 uses -ms-touch-action, so check both?)

@arschmitz
Copy link
Contributor

@msegado Yup I believe you are correct.

@arschmitz
Copy link
Contributor

We talked about this in the meeting today and we have decided to move to using the style attribute as a way to support using valid css. I have a PR in progress for this.

@stuartpb since we have done only one alpha release we are not going to provide backcompat for the touch-action attribute.

@msegado
Copy link

msegado commented Jul 30, 2015

Sweet!

A quick question: what's the plan for -ms-touch-action? It might be nice to make it track the touch-action CSS property automatically so we don't have to worry about setting both for compatibility...

@aarongustafson
Copy link

@msegado: Depends. Do you want to support IE10 or not? IE10 is prefixed.

@arschmitz
Copy link
Contributor

@msegado i'm not sure us doing it automatically would be wise. Currently pep is a complete noop on ie10 this would mean doing a non insignificant amount of work to make it possible in any real sense to sync the attributes. More so when you consider the lack of mutation observers in ie10.

@msegado
Copy link

msegado commented Jul 30, 2015

Ack, sorry, I keep forgetting that ie10 has native pointer events...
Agreed, definitely not worth the effort if it's currently a noop.

@stuartpb
Copy link
Contributor

@stuartpb since we have done only one alpha release we are not going to provide backcompat for the touch-action attribute.

I could have sworn we mentioned this in this thread, maybe it was somewhere else, but the big problem with relying on unrecognized property names in an inline style is that they get removed whenever the content of the inline style string is recalculated through any update to element.style.someProperty = 'some-value'.

I don't like this behavior at all, and I've started a WICG thread about changing it, but it is the reality of the current browser landscape (what polyfills, by definition, have to deal with).

For this reason, I think it's important to keep recognition of the touch-action property in alongside inline style rule parsing. If my code uses it, I shouldn't have to abandon element.style access just to have compatibility with PEP. (Of course, if my code doesn't use it, then specifying it in the style attribute might be the cleaner approach, but it's not a one-size-fits-all solution.)

@arschmitz
Copy link
Contributor

@stuartpb that is not an issue if you see the code and explination i posted above, and the meeting discussion http://irc.jquery.org/%23jquery-meeting/default_%23jquery-meeting_20150730.log.html#t09:10:54 this is easily handled with a mutation observer which we are already using. There is no need to keep the touch-action property.

@stuartpb
Copy link
Contributor

There it is, I was trying to find that post: #151 (comment)

Good to know this can actually be polyfilled at a higher level for the WICG thread I posted.

@deltakosh
Copy link

About using xhr to load the css: why not offering an option to enable it? on by default (for KISS), it could be turned off by web developers who are concerned about performance.
We offered this option in hand.js with a two version of the lib: one with the check, one without.

As a side note, starting yesterday we discontinued hand.js in favor of PEP :)

@jzaefferer
Copy link
Contributor Author

@arschmitz 🙈 🙉 🙊

@jzaefferer
Copy link
Contributor Author

@arschmitz ping

@scottgonzalez
Copy link
Contributor

Setting style.touchAction as a property is preserved in all browsers, only the style attribute is sanitized by the browsers. Even changing styles via style.cssText and setAttribute('style', …) doesn’t kill custom properties on the style property.

@arschmitz
Copy link
Contributor

We sadly need to check the attribute at least initially to be able to get the value from the markup

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

10 participants