bryanmcquade / scroll-to-css-selector

Explainer for supporting CSS selectors when navigating to a URL fragment
61 stars 1 forks source link

Supporting CSS selectors when navigating to a URL fragment

Introduction

To enable users to easily navigate to specific content in a web page, we propose adding support for using a CSS selector to specify the indicated part of the document.

Web standards currently specify support for scrolling to anchor elements with name attributes, as well as DOM elements with ids, when navigating to a fragment. While named anchors and elements with ids enable scrolling to limited specific parts of web pages, not all documents make use of these elements, and not all parts of pages are addressable by named anchors or elements with ids.

Motivating Use Cases

When following a link to read a specific part of a web page, finding the relevant part of the document after navigating can be cumbersome. This is especially true on mobile, where it can be difficult to find specific content when scrolling through long articles or using the browser's "find in page" feature. Fewer than 1% of clients use the "Find in Page" feature in Chrome on Android.

To enable scrolling directly to a specific part of a web page, we propose generalizing the existing support for scrolling to elements based on the fragment identifier. We believe this capability could be used by a variety of websites (e.g. search engine results pages, Wikipedia reference links), as well as by end users when sharing links from a browser.

Search Engines

Search engines, which link to pages that contain content relevant to user queries, would benefit from being able to scroll users directly to the part of the page most relevant to their query.

For example, Google Search currently links to named anchors and elements with ids when they are available. For the query "lincoln gettysburg address sources", Google Search provides a link to the named anchor #Lincoln’s_sources for the wikipedia page for Gettysburg Address as a "Jump to" link:

Example "Jump to" link in search results

However, there are many pages with relevant sub passages with no named anchor or id, and search engines cannot provide a "Jump to" link in such cases.

Referencing / sharing a specific passage in a web page

When referencing a specific section of a web page, for example as part of sharing that content via email or on social media, it is desirable to be able to link directly to the specific section. If a section is not linkable by a named anchor or element with id, it is not currently possible to share a link directly to a specific section. Users may work around this by sharing screenshots of the relevant portion of the document (preventing the recipient of the content from engaging with the actual web page that hosts the content), or by including extra instructions to scroll to a specific part of the document (e.g. "skip to the sixth paragraph"). We would like to enable users to link to the relevant section of a document directly. Linking directly to the relevant section of a document preserves attribution, and allows the user following the URL to engage directly with the original publisher.

Proposed Solution

We propose generalizing existing support for scrolling to elements as part of a navigation, by adding support for specifying a CSS selector in the fragment of a web page URL, and using the element specified by the CSS selector as the indicated part of the document. The user agent would then follow the existing logic for scrolling to the fragment identifier as part of performing a navigation.

This extends the existing support for scrolling to anchor elements with name attributes, as well as DOM elements with ids, to scrolling to other elements in a web page. Browsers would first attempt to find an element that matches the fragment using the existing support for elements with id attributes and anchor elements with name attributes. If no matches are found, and a valid CSS selector is specified in the fragment, browsers would next attempt to find an element that matches that CSS selector.

Browsers that support scroll anchor serialization may wish to implement this feature using the browser’s scroll anchor serialization and restoration implementation, as scroll anchor serialization provides a mechanism to scroll to an element identified by a CSS selector.

Encoding the scroll target in the URL fragment

We propose encoding a Complex CSS Selector in the URL fragment, prefixed with the targetElement= string. For example, #targetElement=.myclass would cause the first element with classname myclass to be selected as the indicated part of the document. Any Complex CSS Selector would be supported.

Though existing HTML support for id and name attributes specifies the target element directly in the fragment, most other mime types make use of this x=y pattern in the fragment, such as Media Fragments (e.g. #track=audio&t=10,20), PDF (e.g. #page=12) or CSV (e.g. #row=4).

Example fragments

URL Fragment Element selected Example matching HTML
#targetElement=#maincontent>p:nth-of-type(3) | 3rd paragraph element within an element with id "maincontent" | <div id=maincontent><p>1st pgh<p>2nd pgh<p>Target pgh</div>
#targetElement=img[src$="img.jpg"] | img element, with a src URL attribute ending in "img.jpg" | <img src=img.jpg> or <img src=http://example.com/dir/img.jpg>
#targetElement=span.foo.bar | span element, with classes "foo" and "bar" | <span class="foo bar">target span</span>
#targetElement=a[href="http://example.com/"] | link element, with an href URL attribute of "http://example.com/" | <a href=[http://example.com/](http://www.example.com/)>target link</a>
#targetElement=#article>div.intro>h2+p | Paragraph immediately following h2 element, within a div with class "intro", with parent with id "article" | <div id=article><div class=intro><h2>Title</h2><p>Target pgh...

URL fragment encoding

In order to specify a CSS selector in the fragment of a web page URL, the author must encode the selector in a way that produces a valid URL fragment.

The URL standard specifies that a fragment can contain URL code points, as well as UTF-8 percent encoded characters. Characters in the fragment percent encode set must be percent encoded.

What this means in terms of the spec's processing model is that we will look at the already-parsed URL record, which has done any applicable percent-decoding for us, and directly use the result as a CSS selector.

Alternatives Considered

Increase use of elements with named anchors / id attributes in existing web pages

As an alternative, we could ask web developers to include additional named anchor tags in their pages, and reference those new anchors. There are two issues that make this less appealing. First, legacy content on the web won’t get updated, but users consuming that legacy content could still benefit from this feature. Second, it is difficult for web developers to reason about all of the possible points other sites might want to scroll to in their pages. Thus, to be most useful, we prefer a solution that supports scrolling to any point in a web page.

JavaScript-based API (instead of URL fragment)

We also considered specifying the target element via a JavaScript-based navigation API, such as via a new parameter to location.assign(). It was concluded that such an API is less useful, as it can only be used in contexts where JavaScript is available. Sharing a link to a specific part of a document is one use case that would not be possible if the target element was specified via a JavaScript API. Using a JavaScript API is also less consistent than existing cases where a scroll target is specified in a URL, such as the existing support in HTML, as well as support for other document formats such as PDF and CSV.

Future Work

In addition to scrolling to a specific element in a document, it is sometimes desirable to scroll to a specific part of content within an element (for example, a sentence of text within a large paragraph element). In subsequent work, we would like to add support for specifying optional scroll target text within a target scroll element. A user would be able to specify a substring of text within the target element as part of the URL fragment, and the user agent would scroll to that substring within the target element upon navigation. For example, if a user wishes to reference a sentence of text within a paragraph (example), they could specify both the target element, along with a substring of text ("they were going to know me as Zanyiwe Madikizela" in the linked example). This ‘scroll to text’ behavior has been proposed in previous draft RFCs and other proposals.

We are not aware of any existing specifications for matching a substring of text within a document. While a basic character-by-character comparison may suffice for some use cases, we may also wish to support cases where the text spans multiple DOM nodes. For example, given the snippet of HTML <div>The quick brown fox <b>jumps</b> over the lazy dog</div>, in order to match the string "The quick brown fox jumps", the text matching algorithm needs to understand how to match text that spans multiple nodes in the DOM. If no existing specs are available for matching text, this behavior may need to be specified as part of standardization of scrolling to text.

Finally, we hope to support highlighting of the target element and/or target text upon scroll. Some sites already provide support for this in their CSS, but it is not supported consistently across the web. For example, StackOverflow highlights an answer if its identifier is specified in the fragment of the URL (example).

Additional Considerations

Browser compatibility and fallback behavior

A browser that doesn’t yet support this feature will attempt to match a CSS selector encoded in the URL fragment using the existing logic to find a potential indicated element. A fragment-encoded CSS selector is prefixed with ‘targetElement=’, which is unlikely to appear in an id or name attribute, so we do not expect a matching element to be found in these cases. Thus, browsers that do not support this feature should fall back to the default behavior of not scrolling the document.

Potential for documents to change, and selectors to no longer match

If a web page is modified, existing links to that page with CSS selectors encoded in the fragment may either (a) no longer find a matching element, in which case the browser will not scroll (default/existing behavior), or (b) match an unintended element. To minimize the likelihood of matching unintended elements, we intend to publish recommendations for creating stable CSS selectors, based on work to serialize and restore scroll anchors.

Developer Opt Out

Web developers may wish to disable scrolling to an element specified by a CSS selector on their pages. For example, a site may have a message at the top of the page that they want to make sure all users see as part of visiting that page. As such, we plan to provide an opt-out to developers, perhaps using a <meta> tag, which disables this feature on that page.

Relation to existing support for navigating to a fragment

Browsers currently support scrolling to elements with ids, as well as anchor elements with name attributes. This proposal is intended to extend this existing support, to allow navigating to additional parts of a document. As Shaun Inman notes, supporting scrolling to CSS selectors is "not meant to replace more concise, author-designed urls" using id attributes, but rather "enables a site’s users to address specific sub-content that the site’s author may not have anticipated as being interesting".

Related Work / Additional Resources

Using CSS Selectors as Fragment Identifiers

Simon St. Laurent and Eric Meyer proposed using CSS Selectors as fragment identifiers (last updated in 2012). Their proposal differs only in syntax used: St. Laurent and Meyer proposed specifying the CSS selector using a #css(...) syntax, for example #css(.myclass). This syntax is based on the XML Pointer Language (XPointer) Framework, an "extensible system for XML addressing" ... "intended to be used as a basis for fragment identifiers". XPointer does not appear to be supported by commonly used browsers, so we have elected to not depend on it in this proposal.

Shaun Inman and others later implemented browser extensions using this #css() syntax for Firefox, Safari, Chrome, and Opera, which shows that it is possible to implement this feature across a variety of browsers.

Scroll Anchoring

Scroll to text

Other