Sorry for the issue title, it was just a good opportunity.
So, the following testcase:
<style>
body { margin: 0 }
a, head, link { display: block }
a, link { width: 100px; height: 100px; background-color: red }
:link { background-color: blue }
:visited { background-color: purple }
</style>
<link href="unvisited"></a>
<link href="">
<a href="unvisited"></a>
<a href=""></a>
Renders as follows in UAs:
I think per spec (https://drafts.csswg.org/selectors-4/#location) Firefox and WebKit are right. However, I don't see any use-case for letting <link>s match :visited, and I have an internal use-case in Firefox where Blink or Edge's behavior would save us some trouble (https://bugzilla.mozilla.org/show_bug.cgi?id=1495621#c20).
Arguably that Firefox case can't arise in the web, and we can work around it in different ways, but I wonder if there'd be interest here in either making <link>s never match :visited, or making them not match any of :link / :visited / :any-link.
I don't think there is any sensible definition of what it means for a <link> to be visited. E.g., is a <link rel="stylesheet"> visited once you download a stylesheet? That's the only "visited" state that makes sense for that type of link, but I doubt that's what the browsers are checking.
From a user perspective, it's also not very helpful for <link> to match :link, despite the names. A :link style is supposed to indicate to the user that I can activate this element to trigger a hyperlink navigation. And while an author may choose to render a <link> element with CSS, it doesn't make it a navigable hyperlink.
@AmeliaBR LINK elements are used for things other than style sheets. For example, rel=next/prev.
Also, this works, and creates a navigable link.
<!DOCTYPE html>
<html>
<link title="Test" href="test" rel="next">
<style>
html, head, link { display: block; }
link::before { content: "test"; }
</style>
http://software.hixie.ch/utilities/js/live-dom-viewer/?%3C!DOCTYPE%20html%3E%0A%3Chtml%3E%0A%20%20%3Clink%20title%3D%22Test%22%20href%3D%22test%22%20rel%3D%22next%22%3E%0A%20%20%3Cstyle%3E%0A%20%20%20%20html%2C%20head%2C%20link%20%7B%20display%3A%20block%3B%20%7D%0A%20%20%20%20link%3A%3Abefore%20%7B%20content%3A%20%22test%22%3B%20%7D%0A%20%20%3C%2Fstyle%3E
Personally, I don't think it's reasonable to say that :link/:visited don't apply to LINK elements. They are hyperlinks, even if they're not visible by default. If browser don't want to deal with rendering them, they can specify link { display: none !important; } in their UA style sheet.
@fantasai I know about next/previous rel values, but I don't think it's specified anywhere that they should create navigable links if displayed. Neither Chrome nor pre-Chromium Edge turn your test case into a navigable link.
If there are use cases for turning a displayed <link> with certain rel values into a navigable hyperlink, like Firefox does, then an issue should be raised with HTML.
On this issue, my conclusion therefore is qualified based on the behavior: if force-displaying a <link> creates a navigable hyperlink, it should match :link and :any-link and :visited if appropriate. If it's not navigable, then it shouldn't match the pseudoclasses.
@AmeliaBR I don't understand why you think not rendering an element should make pseudo-classes not apply. Selectors aren't just about CSS. FWIW, the HTML spec is very explicit that they should match: https://html.spec.whatwg.org/multipage/semantics-other.html#pseudo-classes
@fantasai, I never said that selector matching should depend on whether the element renders or not. It's about whether the element (if it is rendered) actually _acts_ like a link from a user perspective: can you click it, or tab to it and press enter, and trigger navigation.
Whether or not a <link> has this behavior seems to be the underlying discrepancy between browsers, and the styling differences fall out from that. I wouldn't want to ask browsers to harmonize their styling unless they first harmonize the behavior. And that's something for the HTML spec to clarify.
@AmeliaBR The HTML spec doesn't need clarification, it's very explicit about whether :link and :visited match LINK elements. There is zero ambiguity here.
Zero ambiguity, sure. The argument, tho, is that the definition is wrong/useless, and I agree. Having :link apply to <link> doesn't seem like a useful behavior, and the fact that it then raises these questions of what it means for a <link> to be visited just makes it worse.
We should pursue changing the HTML definition so that :link only applies to <a>.
(In other words, a <link> can reasonably be argued to be neither visited nor unvisited; it doesn't have a "visited-ness" at all. Thus neither of :link nor :visited should apply (and neither should :any-link, then).)
I think as of http://trac.webkit.org/projects/webkit/changeset/244642 WebKit will also stop matching :visited on link elements.
@rniwa, do you know what's the reasoning for changing that?
I guess the not recomputing :visited could prevent privacy leaks, though you can always create a new <a> element?
Edit: Right, but that doesn't work. Nice.
@Emilio : oh, that's surprising. That's probably an unintentional change if any. FWIW, my testing at r244643 says WebKit still does blue, purple, blue, purple.
Arguably that Firefox case can't arise in the web,
Arguably it could be a real problem:
document.querySelectorAll(":link")[0] returns a <link> in Firefox and Safari and <a> in Chromium
I'm implementing the pseudo selectors in blink which should make it have the same behavior as webkit: https://groups.google.com/a/chromium.org/g/blink-dev/c/l3Qw9cWYPUA
Most helpful comment
Zero ambiguity, sure. The argument, tho, is that the definition is wrong/useless, and I agree. Having :link apply to
<link>doesn't seem like a useful behavior, and the fact that it then raises these questions of what it means for a<link>to be visited just makes it worse.We should pursue changing the HTML definition so that :link only applies to
<a>.(In other words, a
<link>can reasonably be argued to be neither visited nor unvisited; it doesn't have a "visited-ness" at all. Thus neither of :link nor :visited should apply (and neither should :any-link, then).)