WICG / scroll-to-text-fragment

Proposal to allow specifying a text snippet in a URL fragment
Other
589 stars 42 forks source link

How this affects CSS target pseudo-class :target, propose :target-within #1

Closed laukstein closed 3 years ago

laukstein commented 5 years ago

Currently target element https://drafts.csswg.org/selectors-4/#the-target-pseudo is capturable with CSS :target that applies to elements having attribute id.

Since Scroll-To-Text may target text inside element and not directly text, I recommend to take an example from CSS :focus, :focus-within and to implement a new target pseudo-class :target-within that would capture element within is the targeted text part.

@tabatkins, any suggestions?

bokand commented 5 years ago

I like :target-within, it makes a lot of sense to me.

Another interesting point here is that the proposal, as stated, would allow having multiple targets. Off hand, I expect we could just apply :target-within to multiple elements but am interested if anyone has some counter examples.

hftf commented 5 years ago

Another interesting point here is that the proposal, as stated, would allow having multiple targets.

I would love the ability to target multiple fragments of a page and style them using the existing CSS :target selector – and not just text (this proposal), but IDs or other locators (source line numbers) too. Imagine these examples:

Although this is almost certainly off-topic, it is related to the quoted excerpt above.

bokand commented 5 years ago

Our proposal already allows for highlighting multiple passages: E.g. in Chrome enable chrome://flags/#enable-text-fragment-anchor and follow this link

We could trivially extend this mechanisms to element id's: https://example.org##id=section1&id=section2

However, given that there's no visual indication on element-id's today, this wouldn't really add anything (except maybe a fallback). Perhaps we should add some sort of highlight for element-id's too...

That said, I think this is interesting follow-up work. We're currently focusing on getting the text selector completed.

domenic commented 5 years ago

Note that the current spec seems to imply :target will continue working, as it intends to use "the indicated part of the document", which fuels the :target selector. There'd need to be some more legwork done if the idea was to avoid interaction with :target, and instead have some new selector.

Krinkle commented 5 years ago

Does this mean :target would point to the lowest common element that contains all the found text? That would, I think, be ideal and obsolete the need for :target-within.

If we do consider :target-within, we would likely also need to consider how to accomplish the presumed-common use case of wanting to highlight the inner most element only. As-is I would expect a :target-within to select all ancestor elements as well (e.g. <em>, and <p>, and <article> ,and <body>). This is great if the design-need in question is about styling a specific element based on there being a highlight within it. But, not so great when wanting to generically highlighting the individual span or paragraph where the highlighted text resides.

bokand commented 5 years ago

I think I agree that just applying :target to the inner-most containing element makes sense and probably solves most of the use cases we care about. I'll have to think about the compat implications a little more. Other issues to think about:

callionica commented 5 years ago

If the "highlight" mentioned in the spec as something the UA produces when a page is visited is intended to be stylable, there should be some explicit mention of exactly what the intention is with regard to preventing scripts from seeing the fragment directive (since styles are typically script-detectable).

The spec currently uses "highlight" in two distinct contexts: 1) To mean a text selection provided by the user 2) To mean a visual effect to indicate to the user on arrival which text is of interest

I assumed the spec did not intend to imply that the result of visiting a link with a fragment directive would be a standard text selection (both because I don't think that's useful and because it would be script-detectable), but it's not currently clear what is intended.

My preferred result would be that the visual highlight effect would be entirely under the control of the UA and would be absolutely undetectable to script. I would like the highlight on the text to be short-lived and easily turned on/off. Sites should not have to implement that functionality: it should be the job of the UA.

bokand commented 5 years ago

Thanks for pointing that out, I've opened GH-51 with some normative text around how the text match must be surfaced to the user and cleaning up some of the ambiguity.

It explicitly must not be a text selection as that could allow malicious sites an attack vector to drag/drop tricks on a user.

For the most part, I also prefer having it be UA defined. The one area I could see some customization is allowing pages to set the indication color for more optimal contrast/theme/branding. I think this could be done in a way that it's not script readable but I'm wondering why we'd need that? If it's related to security/privacy, if the page can execute script in the origin then it can already do much worse.

callionica commented 5 years ago

Suppose I receive a link from a friend that links me to a page that displays multiple legal decisions and that friend wants to direct me to a specific legal decision using a fragment. Is it desirable that the site and any 3rd party scripts it loads should be able to determine at a granularity lower than the page level what specific part of the page my friend and I are referring to? No. That's creepy. It's none of their business.

While true that scripts can monitor all kinds of activity on a page, I am hoping that the design of this feature will allow some forms of sharing that scripts can't creepily (or accidentally) monitor. It's worth pointing out that even when you can't technically create a security boundary, you can still create legal/social boundaries to undesired behavior. If scripts needs to start implementing a bunch of code to monitor specific interactions, it becomes clear that they are exploiting technical limitations and that can expose the authors to social and legal consequences.

bokand commented 5 years ago

Ah, yes yes, I was thinking that cross-origin cases were the only thing to worry about and we were covered by the same origin policy. I agree though that there's value in hiding the targeted text even from the destination origin.

There's a bit of a trade-off here though. E.g. on mobile Wikipedia where all sections are initially collapsed, the page must have some way to know which section to expand so we necessarily have to provide, e.g. :target on a nearest element.

One other thing to note: since style can only apply to an element (i.e. not text nodes) I don't think any kind of script-readable styling can be more granular than :target. i.e. if we did provide something like ::text-indicator-color: red, I don't think script can use it to determine what part of the text is indicated.

callionica commented 5 years ago

Thanks for thinking about this.

It's true that any scroll or expansion in the page leaks information to scripts. Definite trade-offs.

My initial thought is that even if color is harder to detect than just calling getComputedStyle, presumably it would still possible to detect it if the UA's visual indication were to be part of the standard UI surface of the HTML that is accessible to script. (I don't know what the state of the art is, but presumably it's still possible to get image data for HTML elements from script?)

This doesn't necessarily mean that there shouldn't be color styles, but it perhaps does suggest that the visual indicator should be implemented as an overlay, so that it's UA "chrome" and not page "content".

bokand commented 5 years ago

I'm not aware of any APIs that let you get the raw pixel data from the rendered page - is such a thing possible?

I think as long as there's no way to get at the text-graunularity differences via script (getComputedStyle or otherwise) then I think that's reasonably restricted.

Re: making the indicator short-lived. I think it's fair to leave that up to the UA. The current implementation in Chrome removes it as soon as the user taps/clicks anywhere on the page.

Krinkle commented 5 years ago

Regarding security/privacy: This is related to the restrictions behind :visited links. We may want to consider similar restrictions on this new styling ability.

On the other hand, if we are concerned about scripts able to access which text highlight you opened via link, I am not sure that is feasible with the current proposal. The implementation proposes to use # fragments in the URL. These are de-facto visible via location.hash, location.href, document.URL. This seems fundamentally incompatible with considering text highlights as private information. Note, I agree it should remain private. I merely want to point out that the styling attack scenario seems secondary to the simpler JS interface which is an easier and more obvious way to reveal this information.


@bokand wrote: There's a bit of a trade-off here though. E.g. on mobile Wikipedia where all sections are initially collapsed, the page must have some way to know which section to expand so we necessarily have to provide, e.g. :target on a nearest element.

Regarding collapsed sections, this is something Wikipedia's mobile site is struggling with today as well, e.g. through the "Find in page" functionality (downstream task), and relates to the "Find in page API" proposed a while back by @rakina and others. (WICG Discourse, https://github.com/w3ctag/design-reviews/issues/236).

bokand commented 5 years ago

These are de-facto visible via location.hash, location.href, document.URL.

See issue #15 the history and how we work around this (it was originally to prevent compat issues but improved privacy is a great bonus). From the explainer:

The targetText is delimited from the rest of the fragment using the :~: token to indicate that it is a fragment directive that the user agent should process and then remove from the URL fragment that is exposed to the site. This change has been proposed to the HTML spec.

This means that if you have a URL: https://example.com#fragment:~:text=some private text

location.hash will return "fragment" and document.URL will return "https://example.com#fragment".

Krinkle commented 5 years ago

@bokand Thanks, that makes sense. That would mean it is hidden from JS if it was already in the original navigation. And if assigned by JavaScript, it will be possible to intercept probably, but that's unavoidable within JS. It would also not see its own actions. Not sure how that goes compat-wise, but I'll leave that be, given it's a closed issue.

bokand commented 5 years ago

Correct, but as a security mitigation, we don't invoke the text fragment directive on same-site navigations so simply writing to location.hash wouldn't invoke the feature. But that's moot because if you're writing to location.hash you already know what's going in there :)

laukstein commented 5 years ago

Keep in mind that pseudo-elements ::before, ::after may affect textual context too. For example

p::before {
    content: "Hello ";
}
p::after {
    content: " World";
}

of

<p>This</p>

would result Hello This World and Scroll-To-Text should consider supporting this whole text.

tabatkins commented 5 years ago

I think I agree that just applying :target to the inner-most containing element makes sense

Yes, the nearest common ancestor of all the matched text is def what :target should match.

How to apply :target with multiple highlights?

Nothing wrong with having multiple elements match :target. Need to define how target navigation works (first one in document order? or closest to the page origin after layout?).

Keep in mind that pseudo-elements ::before, ::after may affect textual context too.

They don't show up (currently) in find-in-page, tho. I think we should be consistent with that feature, and include/exclude ::before/::after the same as f-i-p.

chrishtr commented 5 years ago

Regarding collapsed sections, this is something Wikipedia's mobile site is struggling with today as well, e.g. through the "Find in page" functionality (downstream task), and relates to the "Find in page API" proposed a while back by @rakina and others. (WICG Discourse, w3ctag/design-reviews#236).

Finding / linking within collapsed sections can be achieved with display locking. This feature is going to an Origin Trial in the upcoming Chrome 79. Would Wikipedia be able to give feedback and participate?

bokand commented 3 years ago

The spec and Blink implementation are now clear that :target is applied to the nearest common ancestor, and only on the first target.

I'm going to close this as it seems to work reasonably. Feel free to reply or file a new issue if there's use cases we're missing or improvements we could make.