Closed Bug 1674988 Opened 3 months ago Closed 1 month ago

:link pseudoselector is applied to visited links, against spec

Categories

(Core :: CSS Parsing and Computation, defect)

Firefox 82
defect

Tracking

()

RESOLVED INVALID

People

(Reporter: bart, Unassigned)

Details

User Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:82.0) Gecko/20100101 Firefox/82.0

Steps to reproduce:

I applied different properties to <a> elements in such a way that I can see each applicable style all at once, on the same element.

https://codepen.io/tremby/pen/ExyRgLo

Actual results:

:link and :visited are both applied at the same time for visited links. In this example after clicking the link it is both underlined (:link) and green (:visited).

Expected results:

According to the spec at https://drafts.csswg.org/selectors-4/#link and https://drafts.csswg.org/selectors-3/#link

"The :link pseudo-class applies to links that have not yet been visited"
while
"The :visited pseudo-class applies once the link has been visited by the user".

These sound mutually exclusive, and like the :link pseudoclass should no longer apply once the :visited pseudoclass applies.

Is the spec just badly worded? (Should :link just say "applied to links which have href attributes"? This is how it seems to behave.) Or is it a browser bug? Or do browsers ignore the spec here on purpose? (Why?)

The same behaviour can be seen in Chrome.

For security we're not willing to change anything except the link colour on visited (and we'll even lie about that if you try to check it programatically). If we do anything else we'd end up with being able to write programs that could check whether you've visited a link by checking the page rendering time of a page that has thousands of identical links.

So if any specification says anything that contradicts that we'll purposefully violate it to protect your privacy.

I already read about that here: https://developer.mozilla.org/en-US/docs/Web/CSS/:visited where it says more than text colour can be changed: "color, background-color, border-color, border-bottom-color, border-left-color, border-right-color, border-top-color, column-rule-color, outline-color, text-decoration-color, and text-emphasis-color."

Whether or not that's out of date, the :visited rule I have in my snippet sets only the color property, and that is indeed getting set when I expect it to.

I'm expecting the :link rule (underline, in my case) to be removed once the link is visited, since the spec and the MDN page both say that :link should only be applied to unvisited links.

Do I understand correctly that the privacy issue therefore also affects :link?

I updated my snippet so no disallowed properties are being set either on :link or on :visited. Now, <a> is underlined, :link gets a light grey background colour, and :visited gets green text.

I would expect the light grey background to disappear when the link is visited.

Or are you saying that literally the only thing allowed to change between visited and unvisited states is the text colour? If so, maybe the docs on MDN can be updated accordingly? The :link and :visited docs are misleading -- they seem to say only one of :link or :visited can apply at a time, where clearly Firefox is applying both sets of rules at once when the link is visited.

Sorry for being unclear. You can only change colours. You can't add or remove things such as underlines to differentiate unvisited from visited.

It seems change was the important word.

Before this comment I had these rules:

a { no background colour set }
a:link { background-color: gainsboro; }
a:visited { color: green; }

When the link was visited, I was getting both the background colour and the text colour set. This ought to be impossible according to the docs. Put differently, when visited, both :link and :visited were applied to my link.

I saw your word "change" and wondered if it made a difference if <a> already had a background colour set, and so I would be changing it. So I set this:

a { background-color: antiquewhite; }
a:link { background-color: gainsboro; }
a:visited { color: green; }

Now when unvisited the background colour is gainsboro and the text is black, then when visited the background colour is antiquewhite and the text is green. So the :link pseudoclass is now being removed when the link becomes visited, as I expected it to be all along.

So it seems that the browser refuses to remove :link if it would cause anything but colours to change (and changes in transparency, i.e. the background being applied where there was none before, are not allowed) and will apply both :link and :visited in that case. If only colours will change, :link will be removed and :visited added. Is this correct? Maybe this is what you were saying all along and I didn't follow.

Regardless, this behaviour is subtle and weird, and I wonder if the docs can be improved accordingly.

Bugbug thinks this bug should belong to this component, but please revert this change in case of error.

Component: Untriaged → CSS Parsing and Computation
Product: Firefox → Core

The reason why we're using the :link background is because the :visited background would be transparent. Using a transparent background would have different performance characteristics from using the :link background and reveal your browser history. So we don't and use the "background-as-if-unvisited", which in this case comes from a :link rule.

Status: UNCONFIRMED → RESOLVED
Closed: 1 month ago
Resolution: --- → INVALID

Okay, that makes sense; thank you. If I shuffle around some style rules I can indeed get it to only apply :visited and not :link.

However, this is all undeniably very complicated and unintuitive. It could do with some much better documentation, and I don't think an outsider like me can possibly understand how it works well enough to write that documentation. I wonder if one of the developers might be willing to update the MDN docs related to :link and :visited etc? At present they are vague and misleading, at least in my opinion.

You need to log in before you can comment on or make changes to this bug.