Closed laukstein closed 3 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.
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:
http://path/to/doc#sec2#sec5
http://path/to/doc#L175-180,R243-248
Although this is almost certainly off-topic, it is related to the quoted excerpt above.
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.
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.
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.
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:
:target
with multiple highlights?:target
when the text spans multiple siblings/parent-child elementsIf 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.
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.
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.
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.
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".
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.
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).
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".
@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.
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 :)
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.
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.
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?
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.
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?