Skip to content

[selectors] Match local links #2010

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
LeaVerou opened this issue Nov 25, 2017 · 9 comments
Closed

[selectors] Match local links #2010

LeaVerou opened this issue Nov 25, 2017 · 9 comments

Comments

@LeaVerou
Copy link
Member

In navigation menus, tables of contents etc there's often a need to highlight the links that point to the current page or a part thereof.
While this is needed in almost every website, it currently cannot be done without JS, server-side coding, or horrible hacks.
Selectors4 used to define a :local-link pseudo-class to solve this issue, but was removed in the latest ED due to lack of interest. IMO that was a good decision, as it was overcomplicated and didn't even cover all common use cases. For example, it ignored fragment identifiers, so it was useless for intra-page navigation.

What about a :local-link pseudo-class that works like the following:

  1. If the link target does not match the current document URL ignoring any fragment identifiers, the pseudo-class does not match.
  2. If the link target contains a fragment identifier, the fragment identifier must match that of the current document URL, otherwise the pseudo-class does not match. If the link target does not contain a fragment identifier, step 1 is sufficient.

This definition works for both intra-page navigation as well as navigation across pages, and doesn't have all the path segment complexity of :local-link(). Furthermore, authors don't have to think what kind of matching they need — it just works.

@LeaVerou LeaVerou added the selectors-4 Current Work label Nov 25, 2017
@patrickdark
Copy link
Contributor

I believe it's considered bad practice to link a page to itself, so a:not([href]) should suffice in that case.

Intra-page links can be addressed with a[href^="#"] or a[href*="#"].

@LeaVerou
Copy link
Member Author

LeaVerou commented Dec 7, 2017

I believe it's considered bad practice to link a page to itself, so a:not([href]) should suffice in that case.

We tend to value reality over philosophical purity.
Pretty much every website does this at some point, usually via navigation menus.
Forcing them to add more templating logic or JS to detect which page is the current one and remove the href there is exactly what I'm trying to avoid with this proposal.

Intra-page links can be addressed with a[href^="#"] or a[href*="#"].

If they are part of a navigation menu, they also include a path to the current page, see above re: that.
Also, the latter would match any link with a hash, not necessarily one to the current page.

@fantasai
Copy link
Collaborator

fantasai commented Jan 3, 2018

I'm in favor of accepting the proposal, fwiw.

@css-meeting-bot
Copy link
Member

The Working Group just discussed [selectors] Match local links, and agreed to the following resolutions:

  • RESOLVED: Accept the proposal with an added note
The full IRC log of that discussion <dael> Topic: [selectors] Match local links
<florian> +1 especially given that selectors are fragile and don't fallback very well, we shouldn't add more opportunities for authors to shoot themselves in the foot
<dael> github: https://github.com//issues/2010
<dael> fantasai: The proposal is summarized in leaverou comment. It's common for authors to want to style the current location differently. They currently have to do something custom. Would be nice to have a selector to say this link is pointing to this page.
<dael> fantasai: We previously had a local link psuedo class. We dropped it. leaverou 's is different because it also accounts for fragment identifiers. If it does have a frag. id it must match that of the URL.
<dael> fantasai: I think it makes sense.
<dael> dbaron: I think it needs a clear processing for what happens if the page's uri changes.
<tantek> is it like :target in that regard?
<dael> fantasai: It's a dynamic pseudo.
<dael> dbaron: Does that cause anything interesting to happen with things like push state that change the url.
<dael> fantasai: I have no idea. If it changes the uri [missed]
<dael> tantek: That's the kind of thing :target will need to answer as well.
<fantasai> If the current URL changes , then what :local-link matches changes; but :local-link can't cause the current URL to change.
<dael> dbaron: I think :target isn't defined well as well. I think if this goes into spec it should point out existing features that could cause pages uri to change.
<dael> tantek: I think that should happen regardless.
<dael> tantek: If :target doesn't express the history state that's an issue regardless.
<dael> dbaron: I remember a lack of interop with dynamic changes originally, I don't know about now.
<dael> tantek: My point is it shouldn't be different then the :target impl.
<dael> dbaron: My point is the spec should point out to impl things that could cause the uri to change. If the spec designers don't know that they should figure it out so it gets impl right.
<dael> fantasai: You're asking for a note?
<dael> dbaron: Yes.
<dael> fantasai: Okay that's fine.
<dael> Rossen_: So the note you're referring to is?
<dael> fantasai: Providing the information to point out all the things that could poss. change the URL.
<dael> Rossen_: Sounds more normative thent he note.
<dael> florian: Point is to find these spec if you're not aware of them.
<dael> tantek: It's the kind of thing that's good as a note to start, but could turn into test cases. So it sounds normative-like but doesn't need to be.
<dael> florian: I'ts a back reference to existing prose.
<florian> +1 to test cases
<dael> tantek: An expanstion to what we thing the normative thing is. Either way you can make test cases.
<dael> fantasai: You can make test cases easier because you have a list of what they should be.
<dael> Rossen_: So I'm hearing people are in favor of the proposal for a local link as spec by leaverou with the additional requirement as well as at the very least put a note and point back to :target and hope things are spec well as to what could cause a URL change and make the pseudo class invalidated.
<dael> Rossen_: Anything else to add/change on this proposal before we resolve?
<dael> Rossen_: Obj?
<dael> RESOLVED: Accept the proposal with an added note

@LeaVerou
Copy link
Member Author

LeaVerou commented Jan 4, 2018

Ahem

In any case, glad to see it was accepted, though I would have wanted to participate in the discussion.

Btw, history.pushState() does not affect :target in current browsers. Which is a bit of a PITA and always seemed like a bug to me.

@jayaddison
Copy link

Hi @patrickdark @LeaVerou - I'm interested in the :local-link pseudo-selector for a use-case related to Sphinx single-page-HTML builds -- where most, if not all hyperlinks are local.

I understand that the feature was proposed for selectors-4, then withdrawn and deferred to selectors-5 and has been restored to selectors-4 with the suggested modifications (but remains pending in 5?).

I think the use-case is a fairly good match, although it has some quirks - it's about identifying 'current page' hyperlinks with a table-of-contents menu (seems to match the description here).

I'll probably spend a bit more time to collect thoughts, etc and then will open a question on the relevant mailing list, but wanted to register my interest here first.

@LeaVerou
Copy link
Member Author

At this point, this is already in the spec and is waiting for implementations, so your best bet is to raise developer awareness so that browsers can prioritize it. Unless you think it should work differently, here's not much we can do 😕

(And I agree with you this is sorely needed!)

@jayaddison
Copy link

Thank you! There are two things I'm seeking clarification on: one is about how the feature works, and the second is a process question about whether the selectors-4 spec supersedes selectors-5.

The use-case relates to table-of-contents hyperlinks, and it would be convenient to use CSS selectors to choose hyperlinks where the browser can remain within the current document (simply scrolling/moving to the hyperlink fragment if it is present, or top of the page for same-document links that have no fragment).

Given that the spec here (S4) changed to include anchor equality in the comparison -- from the original (deferred to S5) where it did not -- my sense about the hyperlink-matching logic specified in each would work for a hypothetical scenario is:

Browser location:   index.html#toc-item-2
CSS selector:       a:local-link

Selected?
 S5 S4      Anchor Target (a href)
----------------------------------
[x] [ ]     index.html
[x] [x]     index.html#toc-item-2
[x] [ ]     index.html#toc-item-5

(I place S5 before S4 in the column to reflect their chronological publication order)

In the use case I'm investigating, the S5 behaviour initially seems like what is required - a way to select links that should not require the browser to navigate to a different page.

In terms of compatibility, it feels to me that S5 in combination with the :target pseudo-selector could provide the results specified by S4 -- a selector of a:local-link:target, for example, to describe links that are to the current document and that are also the current browser navigation location.

I can't see an equivalent compatibility route if S4 is implemented first -- it selects fewer items, and so there is not a way to expand that out to achieve the S5 results.

@jayaddison
Copy link

The section I wrote about compatibility is wrong, I think. Quoting again:

In terms of compatibility, it feels to me that S5 in combination with the :target pseudo-selector could provide the results specified by S4 -- a selector of a:local-link:target, for example, to describe links that are to the current document and that are also the current browser navigation location.

I can't see an equivalent compatibility route if S4 is implemented first -- it selects fewer items, and so there is not a way to expand that out to achieve the S5 results.

I'm not sure that I can phrase this clearly, but I'll try: in both the S4 and S5 specifications: a:local-link:target would evaluate to hyperlinks that point to the current page (and/or fragment) and that are also themselves the element identified by the browser navigation location (including fragment).

Basically, I had misunderstood the use of :target as allowing filtering of the target of hyperlinks.

Given that, I think that S4 and S5 specifications are distinct, but overlapping (S4 is more precise than S5). And that reduces my concern about compatibility.

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

No branches or pull requests

5 participants