w3c / csswg-drafts

CSS Working Group Editor Drafts
https://drafts.csswg.org/
Other
4.5k stars 668 forks source link

[css-ui] Control whether an element is findable/searchable (Ctrl+F) #3460

Open hftf opened 5 years ago

hftf commented 5 years ago

I want to control whether an element is findable/searchable via a browser’s Find function (usually accessed with the Ctrl+F or Cmd+F shortcuts).

Why?

In an interface where meaningful elements accompany or interrupt the flow of running text, users should still be able to interact normally with the text as if those elements were inert.

This JSFiddle shows a sentence interspersed with some annotations. Both the words and annotations are marked up with abutting <span> tags. (The example is simplified from a real interface I designed.)

Suppose you want to find a sentence within a long annotated paragraph. Most browsers will only find up to a single word (e.g. Th, This), but not a string of several words (This sentence). That behavior is demonstrated below by Chrome 71/Mac:

GIF showing Find behavior for annotated sentence example

While this feature would primarily be used by authors to improve user experience in browsers, it could also be used by search engines to ignore certain interface elements when indexing or displaying blurbs on results pages.

Current status

The desired behavior is similar to the existing user-select property, which controls whether an element is selectable or copyable.

However, the spec does not define whether user-select affects findability, and if not, does not provide an alternative mechanism for doing so.

CSS Basic User Interface Module Level 4 refers to “findable” once, in the context of generated content:

6.1 Controlling content selection

When generated content in pseudo elements becomes selectable through this mechanism, UAs should also make this content findable through their search function.

CSS Generated Content Module Level 3 refers to “searchable” once, in the context of generated content:

1.1. Accessibility of Generated Content

Generated content should be searchable, selectable, and available to assistive technologies.

Workarounds

Use CSS generated content.

Cons:


Other workarounds:

Questions

  1. Should user-select encompass findability?
  2. If not, should a new control be invented?
  3. How do findability, selectability, copyability, etc. interact with similar annotation methods, such as ruby annotation or interlinear glosses in linguistics?

More examples

  1. Example of English text containing a word with a phonetic ruby annotation (JSFiddle):

    GIF

  2. Example of per-letter ruby annotations (taken from a recent presentation):

    GIF

Further reading

birtles commented 5 years ago

3. How do findability, selectability, copyability, etc. interact with similar annotation methods, such as ruby annotation or interlinear glosses in linguistics?

For the particular case of ruby, it seems like UAs have the information needed to ignore ruby text when doing find in page (or alternatively match only the ruby text and ignore the base text) so this would just be a quality of implementation issue? That obviously doesn't help with the other use cases you mentioned, however.

I'd be a little bit concerned with authors abusing this (e.g. publishers deliberately making their content not searchable) but presumably UAs would provide a way to override this just like one can Shift+right click an element to get the native context menu when the content is overriding it.

mikkorantalainen commented 3 years ago

I think user-select should affect findability because the usual UI is to highlight/select the text that was found and if the user cannot select the text in first place, the find shouldn't do that either. In addition, user-select: none should already overlap with the text that's not worth searching for (e.g. UI elements) so existing use cases of user-select would probably already have correct behavior automatically.

stefanhamburger commented 1 year ago

Another motivating example:

I have a menubar with some options hidden behind a drop-down menu, which becomes visible on hover/focus. I still expose the options to the DOM (with position: absolute; left: -9999px) to allow users to tab through them and have them be part of the accessibility tree. However, I don't want them to be searchable via Ctrl+F while they're not visible, as the search results would only confuse users.

I would not need a CSS property if I could automatically detect when the browser searches for text; then I could e.g. automatically show the drop-down menu. But this is not possible because search does not trigger a select event or similar. I like the suggestion to make text with user-select: none not searchable but the current behavior in both Firefox and Chromium is that they will find text with user-select: none.

emilio commented 11 months ago

I filed https://github.com/w3c/csswg-drafts/issues/9726 with another motivating example, and a strawman proposal:

  user-find: auto | none;

Copying questions from there:

cc @josepharhar @mfreed7 @rniwa @fantasai @frivoal

hftf commented 11 months ago

Some annotations may contain meaningful text that one might want to find in some situations, but not in others. This may motivate a use case beyond only two simple values. Taking an example from my OP (and happy 5th birthday to it):

Pablo Casals (“kuh-ZALLS”) became

Pablo <ruby><rb>Casals</rb><rp> (“</rp><rt>kuh-ZALLS</rt><rp>”)</rp></ruby> became

A third option both could be most flexible in situations where the developer cannot assume the user’s intent at any point:

rt, rp { user-find: ____ } Casals became kuh-ZALLS Casals (“kuh-ZALLS”) became
auto: yes, annotation is always in text flow not found found found
none: no, annotation taken out before find found not found not found
both: skippable, tries both options above found found found

Another upside of a third value (both or optional or whatever you call it) is that it can apply to parentheses (rp).

I don't know how browsers implement finding, but the effect of both is like wrapping a (…)? around a regular expression or branching on epsilon in a state machine. Probably easier said than done and there may be other complexities (like what if multiple overlapping matches cross a skippable annotation?).

Perhaps creating a new ARIA role "annotation" that defaults to this both value would help users of assistive technology (AT). Users can still access the annotations (as they are meaningful), but they live in a separated context outside the running text without interrupting it, and can optionally skip them (as a whole or individual). Then the implicit ARIA role of rt and rp can become "annotation".


While the topic is fresh, maybe a similar issue of controlling copyability should be considered (probably in another thread). Currently, it is not possible to control whether ruby parentheses (rp) get copied. And if the author didn’t explicitly provide parentheses, should the lack of rp generate parentheses when the user is copying? The status quo is an unreadable result that looks like Casalskuh-ZALLS became even when rp exist.

josepharhar commented 11 months ago

Does that seem reasonable? It should be extensible in the future if we want to, but that seems like a consistent starting point to me.

As a way to make find-in-page stop finding things that are rendered, yeah this seems like a good way to do it. This does not conflate with hidden=until-found because that feature makes hidden things searchable, whereas this is the opposite. One of the reasons that hidden=until-found was moved from CSS to HTML was that the browser is able to modify the state of the attribute when the hidden thing is revealed, but in this case there is no state to change so CSS seems fine.

Another question is: Should this property be inherited? user-select isn't, but user-select is really weird. I think it'd be simpler if this one was inherited, but open to other ideas.

I don't have any thoughts on this.

A third option both could be most flexible in situations where the developer cannot assume the user’s intent at any point:

The particular way that find-in-page finds matches is not specced as far as I can tell and is really user agent dependent, and I kind of feel like this proposal is too imposing or at least would require us to spec how find-in-page really works, which seems like it would take a lot of work. I am not in favor of adding the both value.

Chrome had a feature request to allow case-sensitive find-in-page, but our UX people decided that we shouldn't allow it: https://bugs.chromium.org/p/chromium/issues/detail?id=8717 This isn't exactly the same as allowing the page to tweak how layout influences find-in-page matches, but if there were a proposed way to allow the site to force case-sensitivity for find-in-page results, I fear that it may be at odds with the resolution of that crbug. This layout idea could theoretically also be an option in the browser's find-in-page options in addition to case sensitivity, right?

I don't feel super strongly about this, but I think that we should just consider emilio's property values for now.

tabatkins commented 11 months ago

Yup, this seems reasonable, and I think your syntax is reasonable. (Notably, how it doesn't let you say "definitely make this findable", just "make this findable as normal", so things can stay unfindable if that's important.)

The GitHub use-case is pretty compelling, that's some hefty workarounds.

I think this should be inherited. Aside from a few weird cases, our general rule is "text properties inherit, block properties don't", and this is a text property.

frivoal commented 11 months ago

I'm tempted to say that having user-select affect find-ability is the right place to start. I suspect that the vast majority of the time, that will do what you want. If it isn't enough, we can always introduce user-find as well for the cases where they need to be decoupled, with the two interacting via auto.

emilio commented 11 months ago

@frivoal that seems reasonable at first, but there are cases now where text selectability and findability do not match already, and there are cases where you definitely want text to be findable but not selectable. Think of line numbers on a code listing for example.

Making unselectable text also unfindable by default is a somewhat risky change from a compat perspective in that sense too. It also means pseudo-elements would be unfindable, and that we'd need an opt into overriding it.

So I'd rather keep this like a completely separate toggle, both to avoid changing existing behaviour and to avoid the complexity of interacting with selection, which is generally limited to the DOM in ways that find isn't.

css-meeting-bot commented 9 months ago

The CSS Working Group just discussed [css-ui] Control whether an element is findable/searchable (Ctrl+F).

The full IRC log of that discussion <TabAtkins> emilio: i recently stumbled across the problem
<TabAtkins> emilio: github has an interesting use-case where they effectively neutralize the rendering of what you see
<TabAtkins> emilio: but for a11y they render text on top in an invisible textarea
<TabAtkins> emilio: in a way where, if they did the naive thing, ctrl-F would find the text twice
<TabAtkins> emilio: so instead they do terrible hacks to prevent that from working
<TabAtkins> emilio: but firefox's ctrl-F is better, so they do *worse* hacks
<TabAtkins> emilio: which then causes perf problems in firefox because the dom is 100x bigger
<TabAtkins> emilio: there are other properties that control findability
<astearns> s/is better/is better because it finds content in pseudo-elements/
<astearns> (like it says to do in the spec)
<TabAtkins> emilio: there are use-cases for having this separate from text selection (like pseudo-element text can be selected but not always findable)
<TabAtkins> emilio: Like PDF.js will render transparent text on top fo the PDF so you can search for it and select it
<TabAtkins> emilio: so there's no good *heuristic* for auto-determining text shouldn't be findalbe, that won't break some use-cases
<TabAtkins> emilio: so obious solution is providing some control over it
<TabAtkins> emilio: suggestion is an inherited user-find property that takes auto and none
<TabAtkins> emilio: `auto` does "the reasonable thing" (find isn't very well specified)
<TabAtkins> emilio: and none definitely makes it unfindable
<TabAtkins> emilio: You def don't want stricter control like "always make this findable" if it isn't displayed
<TabAtkins> emilio: so i think this proposal solves these use-cases
<iank_> q?
<TabAtkins> emilio: initially, tying it ot user-select looked like ab etter approach, but i convinced myself it doesn't work great
<iank_> q+
<TabAtkins> fantasai: a bunch of the examples i nthe issue are about ruby
<TabAtkins> fantasai: ruby annotations breaking contiguity
<TabAtkins> fantasai: that's justa bug
<TabAtkins> emilio: right, should be fixed
<florian> q+
<TabAtkins> fantasai: because you should also be able to find the annotation
<TabAtkins> emilio: yup
<emilio> https://github.com/w3c/csswg-drafts/issues/9726
<TabAtkins> emilio: I find similar examples in some other editors over time
<schenney> Sorry not in the meeting, but am reminded of user-select.
<TabAtkins> emilio: somebody filed a bug when i made text in a textarea findable
<TabAtkins> fantasai: i think the user often wants to find things hat the author didn't want them to find
<TabAtkins> emilio: problem here is double-finding
<TabAtkins> fantasai: can we solve those cases tho?
<TabAtkins> TabAtkins: use-case here is they want to offer a mor epowerful Find
<TabAtkins> emilio: also they want to virtualize large files
<TabAtkins> emilio: if the whole giant file is in textarea for a11y, that's fine, but you want to virtualize just about a page-worth of content in rich dom
<TabAtkins> emilio: but then the thing on screen shows up twice
<TabAtkins> fantasai: my concern is that a lot of use-cases presented here *aren't* reasonable
<TabAtkins> fantasai: so if we offer it people will do the wrong thing a lot
<TabAtkins> emilio: but you can say the same thing for user-select
<TabAtkins> emilio: sometimes annoying for users, but sometimes very good for authors (and uses)
<TabAtkins> fantasai: i dunno, not totally convinced
<TabAtkins> TabAtkins: i'm convinced, i think it's fine
<florian> q?
<TabAtkins> iank_: there was a period a few years ago where a lot of news sites were trying to make it difficult to select/copy/etc
<TabAtkins> iank_: i could see this being used to make the whole page unsearchable? any thoughts?
<TabAtkins> emilio: yeah, you can make annoying things. you can already do that in various ways.
<TabAtkins> emilio: we *try* to make visible thins findable
<florian> q-
<TabAtkins> emilio: the way we try to appraoch sites that hijack the context menu, is provide users ways to bypass
<TabAtkins> emilio: like in firefox shift-rightclick shows the original context menu
<khush> q?
<khush> q+
<TabAtkins> emilio: in general there are reasonable use-cases, and we expose worse functionality, so this isn't that bad and worth the use-cases
<florian> q+
<TabAtkins> khush: You point to one example, the argument is browsers aren't able to find this sentence because of annotations...
<khush> https://jsfiddle.net/jw8do93r/
<TabAtkins> fantasai: these probably *should* be ruby and marked up as ruby annotations
<TabAtkins> khush: right, if the author hides the annotation so the sentence is searchable, the annotations won't be
<TabAtkins> emilio: the interaction of the featur ewith adjacent content... this wouldn't even work in our find imples
<TabAtkins> emilio: the words in spans are in inline-block
<TabAtkins> emilio: and i dont' think we deal well with things spanning lines across blocks
<vmpstr> q+
<TabAtkins> emilio: i don't think we want people to use this feature for this use-case
<TabAtkins> khush: it was kinda funny that this was just the first example someone posted why they want the feature, when we said we didn't want it for this example
<TabAtkins> florian: I was originally convinced it shoudl be in user-select, i now agree it shouldn't. unsure if it shoudl exist at all. if it does...
<TabAtkins> florian: values are auto and none. for auto, you have heuristics
<TabAtkins> florian: if browsers have different opinions about pseudo-elements and whatnot, would it be good to have a third value that overrides the heuristics and make it searchable?
<TabAtkins> emilio: why would a browser not make it searchable tho
<TabAtkins> emilio: browsers dont' do it today as a tech limitation
<TabAtkins> emilio: like khush's example doesn't work due to tech limitations in Gecko anyway, this feature won't help
<TabAtkins> vmpstr: i'm a little concerned from a11y pov, i think finding content is more important than selecting content
<TabAtkins> vmpstr: i don't want to lump it into user-select
<TabAtkins> vmpstr: i think for github, potentially we can find ways of solving that expensive-rendering problem different
<TabAtkins> vmpstr: we've attempted that with content visibility
<TabAtkins> vmpstr: where you render what's requried but whole DOM remains available
<TabAtkins> vmpstr: if that's not good enough i'd rather revisit that
<TabAtkins> emilio: i'm not particularly sure why they chose that approach, but i do know that due to Firefox being able to defeat their basic hack, they serve a ridiculous giant DOM and make us super slow
<TabAtkins> vmpstr: that's fair, i just don't think that a blanket "you can't search this but you can see it" is a great direction from a11y
<TabAtkins> emilio: we do allow similar beahvior controls
<TabAtkins> emilio: in this case the thing you're finding isn't visible, but we allow you to find it becuase we don't realize it
<dholbert> q+
<TabAtkins> emilio: the textarea is transparent
<TabAtkins> emilio: so today if you hide it from search you also hide it from a11y
<TabAtkins> vmpstr: Right, that distinction doesn't seem great, anytime the two differ it's suspicious
<dholbert> q-
<TabAtkins> fantasai: two comments. first, if we go in this direction, we should get browsers to fix their ruby annotations disrupting searching
<TabAtkins> emilio: yeah this feature might not even improve that issue in browsers
<fantasai> s/searching/searching first/
<TabAtkins> emilio: depending on the markup you still might not be able to find across elements
<GameMaker> q+
<bkardell_> huh?
<TabAtkins> fantasai: second, highlight vlad's comment that if you hide something from finding but expose to a1y that's weird
<TabAtkins> fantasai: third, we have a control already to let us hide things from a11y but not visibly, and vice versa
<emilio> q+
<emilio> https://bugzilla.mozilla.org/show_bug.cgi?id=1699599 is relevant here
<fantasai> s/if we go/if we want to go/
<TabAtkins> dbaron: i had the thought, potentially you could have a none value that isn't quite as none as you were intending
<TabAtkins> dbaron: but instead is "i want this to not be findable if it isn't visible"
<TabAtkins> dbaron: so it biases more toward none but wouldn't prevent visible text
<TabAtkins> emilio: but that wouldn't work for github
<astearns> 'visible' being potentially visible if scrolled to, perhaps?
<TabAtkins> dbaron: the one other thought it, i think fixing the ruby case properly requires essentially allowing multiple readings fo the same dom to be found
<TabAtkins> dbaron: i don't know if there are other things with that characteristic
<florian> q?
<TabAtkins> dbaron: i suspect not, so that does make ruby thing hard to fix. not impossible, but more difficult
<florian> qq+
<TabAtkins> emilio: i was curious - gecko ignores ruby annotations for Find, so you can find the whole base. that's not controlalble, we just skip them
<florian> q-
<TabAtkins> emilio: so i want to separate this from the ruby thing because annotations are already unfindable
<TabAtkins> fantasai: they'll use this property wrongly if we don't get ruby to search correctly in other browsers
<TabAtkins> GameMaker: unsure if relevant, but there's another way to search in pages which is scroll-to-text-fragment
<TabAtkins> GameMaker: I think it tries to avoid finding things aren't visible
<TabAtkins> GameMaker: it's another way to find things, kinda weird that it's a unique impl
<TabAtkins> emilio: i agree ideally this wouldn't be a distinct algorithm
<florian> q+
<TabAtkins> GameMaker: yeah it's different from Find, handwaves some spaces, and generally is a little weird
<TabAtkins> fantasai: i'm not hearing consensus
<dholbert> TabAtkins (IRC): it sounds like, of the two major use-cases, one is ruby-basd, the other is virtualization-based
<fantasai> TabAtkins: It sounds like a lot of the objection is, of the two use cases one is ruby which is a bug, and another one is virtualization, which should be fixed by content-visibility
<florian> q-
<fantasai> TabAtkins: Maybe improve ocntent-visibility cases, maybe there will still be a need for virtualization, but either way ...
<TabAtkins> emilio: i'd say that realistically this pushes us to make our find impl suck, but
<fantasai> TabAtkins: Or maybe there's a third use case that motivates this feature
<fantasai> TabAtkins: I think investigating why not using content-visibility is worth doing
<fantasai> TabAtkins: helps everyone
<TabAtkins> emilio: i think part of the reason is that size of the syntax-highlighted dom can still be substantial
<TabAtkins> emilio: so you're shipping a giant dom that effectively contains the text content of the file
<TabAtkins> emilio: they wrote up a whole big thing about why they did what they did
<fantasai> TabAtkins: I saw that article, I do not remember whether or not they mentioned content-visibility
<fantasai> TabAtkins: I can 100% believe that rendering giant synax-highlighted DOM would be expensive, but the whole reason for us to introduce content-visiblity was assuming that DOM is relatively cheap as long as not rendered
<fantasai> TabAtkins: so should be able to handle large DOMs like this without too much trouble
<fantasai> TabAtkins: Maybe GitHub is an outlier, and shipping that much DOM is still a significant prolem that exceeds our expectations
<fantasai> TabAtkins: or maybe virtualization is still a problem andn our assumptions were wrong
<fantasai> TabAtkins: but we should figure that out
<TabAtkins> fantasai: so it sounds like we don't have consensus to adopt this. suggest we look into the reasons why people would be needing this.
<TabAtkins> emilio: realistically we could make the same argument about user-select
<fantasai> TabAtkins: user-select is more behavior thing, this is about making a slightly hacky solution (virtualization) less bad
<TabAtkins> emilio: I can find the other use-cases i find that were editing related
<TabAtkins> emilio: why are editors using a separate text area? If you're editing plain text...
<TabAtkins> i can find it and bring it back if it will change opinions
hftf commented 9 months ago

Thank you for discussing the issue.

To quickly respond to an idea in the log: while I don't have great difficulty accepting the "probably should have used ruby" argument, and per the spec the semantics of ruby are left very open, it may be worth noting a few things:

  1. Ruby is indeed already being used in the application that this use-case is from, but for marking up phonetic annotations (it's not shown in the first example/jsfiddle, but shown in the second example/jsfiddle without the numeric annotations). I know from other experimentation that nesting ruby annotations, esp. with unequal bases, is quite difficult to make work.
  2. Some annotations are intended to go "between" two words rather than be associated with any individual word. Imagine in the first example/jsfiddle adding another tick at the very end of the sentence with the text "100% 5": what word would this annotation attach to?
  3. The tree model of HTML/XML/CSS makes it quite tricky to annotate a span of markup arbitrarily (e.g. highlight a range of text and add a comment; OOXML e.g. uses milestone elements). Any existing method (ruby, positioned spans, tables) of interlinear annotation runs into issues of findability, copyability, and selectability anyway, not to mention line-wrapping or overlapping.
  4. There is another person's application that does use ruby for the word-associated annotations: example A. Compare to my example B (note that the ruby tags with phonetic annotations are hidden by CSS for the purpose of this application).

Hope this context helps a bit to understand one of my motivating use cases.

dbaron commented 9 months ago

I filed HTML inert attribute should make text not findable by find-in-page on Chromium about making the inert attribute follow the rule in the HTML spec discussed here.

dbaron commented 8 months ago

Also see the Chromium bug on find-in-page and ruby.

vmukhachev commented 6 months ago

@dbaron, amazing, it works now!

yisibl commented 1 week ago

Also see the Chromium bug on find-in-page and ruby.

This has been fixed in Chrome 132. https://chromiumdash.appspot.com/commit/e81612f61e1f7c6ab815e45621c53210e64e95b3