@@ -1956,35 +1956,187 @@ The Hyperlink Pseudo-class: '':any-link''</h3>
1956
1956
<h3 id="link">
1957
1957
The Link History Pseudo-classes: '':link'' and '':visited''</h3>
1958
1958
1959
- User agents commonly display unvisited <a href="#the-any-link-pseudo">hyperlinks</a> differently from
1960
- previously visited ones. Selectors
1961
- provides the pseudo-classes <dfn id='link-pseudo'>:link</dfn> and
1962
- <dfn id='visited-pseudo'>:visited</dfn> to distinguish them:
1963
-
1964
- <ul>
1965
- <li> The '':link'' pseudo-class applies to links that have
1959
+ User agents commonly display unvisited <a href="#the-any-link-pseudo">hyperlinks</a>
1960
+ differently from previously visited ones.
1961
+ Selectors provides the pseudo-classes
1962
+ <dfn id='link-pseudo'>:link</dfn> and <dfn id='visited-pseudo'>:visited</dfn>
1963
+ to distinguish them.
1964
+ Roughly:
1965
+
1966
+ * The '':link'' pseudo-class applies to links that have
1966
1967
not yet been visited.
1967
- <li> The '':visited'' pseudo-class applies once the link has
1968
+ * The '':visited'' pseudo-class applies once the link has
1968
1969
been visited by the user.
1969
- </ul>
1970
1970
1971
1971
After some amount of time, user agents may choose to return a
1972
1972
visited link to the (unvisited) '':link'' state.
1973
1973
1974
- The two states are mutually exclusive.
1974
+ The two states are mutually exclusive
1975
+ (no element can ever match '':link:visited'' ),
1976
+ but their actual interaction is more complex than that,
1977
+ for privacy reasons explained below.
1978
+
1979
+ In full, the behavior is actually that the '':link'' pseudo-class applies to all links,
1980
+ but the '':visited'' pseudo-class applies the following behavior and restrictions:
1981
+
1982
+ <div algorithm=":visited styling">
1983
+ To <dfn>apply :visited styling</dfn> to an element |el|:
1984
+
1985
+ 1. Check to see if |el| has a <a>relevant link</a> .
1986
+ The <dfn for=":visited">relevant link</dfn> for an element
1987
+ is the element itself,
1988
+ if it's an element that would match '':link'' ,
1989
+ or else the closest ancestor that would match '':link'' .
1990
+
1991
+ If |el| does not have a <a>relevant link</a> ,
1992
+ then '':visited'' has no effect on the element.
1993
+
1994
+ 2. Otherwise, compute |el|’s style,
1995
+ treating only its <a>relevant link</a> as matching '':visited''
1996
+ (and thus, not '':link'' ).
1997
+ All other links must be treated as matching '':link'' .
1998
+
1999
+ 3. From the styling results,
2000
+ record the values of the <dfn lt="allowed :visited property">allowed :visited properties</dfn> :
2001
+
2002
+ * 'color'
2003
+ * 'background-color'
2004
+ * the 'border-color' sub-properties
2005
+ * 'outline-color'
2006
+ * 'column-rule-color'
2007
+ * 'fill-color'
2008
+ * 'stroke-color'
2009
+
2010
+ These are |el|’s <dfn lt=":visited style">:visited styles</dfn> .
2011
+
2012
+ 4. If |el|’s <a>relevant link</a> is actually visited,
2013
+ then for the <a>allowed :visited properties</a> ,
2014
+ use |el|’s <a>:visited styles</a> for any purposes
2015
+ that won't allow the document itself to tell what the style is;
2016
+ in all other contexts,
2017
+ use the normal, all-'':link'' , styling.
2018
+ </div>
1975
2019
1976
2020
<div class="example">
1977
- The following selector represents links carrying class
1978
- <code> footnote</code> and already visited:
2021
+ For example, with the following common example style sheet:
2022
+
2023
+ <pre class=lang-css>
2024
+ :link { color: blue; }
2025
+ :visited { color: purple; }
2026
+ </pre>
2027
+
2028
+ Visited links show up as purple only for rendering to the screen.
2029
+ If the document uses JS to query the element’s style,
2030
+ it will instead report ''color: blue'' ,
2031
+ as if the element only matched '':link'' .
1979
2032
1980
- <pre> .footnote:visited </pre>
2033
+ Similarly, if HTML's <{canvas}> element develops an ability to render HTML to the canvas with CSS styling,
2034
+ then either the links would be styled blue
2035
+ (because by default, <{canvas}> gives the document the ability to inspect the results),
2036
+ or the visited links will be purple,
2037
+ but <{canvas}> will restrict the page's ability to inspect the pixels of the result.
1981
2038
</div>
1982
2039
1983
- Since it is possible for style sheet authors to abuse the :link and :visited pseudo-classes
1984
- to determine which sites a user has visited without the user's consent,
1985
- UAs may treat all links as unvisited links
1986
- or implement other measures to preserve the user's privacy
1987
- while rendering visited and unvisited links differently.
2040
+ <div class=example>
2041
+ The special '':visited'' behavior also means
2042
+ that a single element might be styled by a mix of '':link'' and '':visited'' rules.
2043
+ For example:
2044
+
2045
+ <pre class=lang-css>
2046
+ :link {
2047
+ color: blue;
2048
+ background-image: url("unvisited.png");
2049
+ }
2050
+ :visited {
2051
+ color: purple;
2052
+ background-image: url("visited.png");
2053
+ }
2054
+ </pre>
2055
+
2056
+ With this style sheet,
2057
+ a visited link will be colored purple,
2058
+ but have the "unvisited.png" background,
2059
+ because 'background-image' is not one of the <a>allowed :visited properties</a> ,
2060
+ and so whatever value it gets from a '':visited'' style
2061
+ is not recorded in the element's <a>:visited styles</a> .
2062
+ </div>
2063
+
2064
+ <div class=example>
2065
+ Another consequence of the special '':visited'' behavior
2066
+ is that some selectors that look reasonable
2067
+ will never match.
2068
+ For example:
2069
+
2070
+ <pre class=lang-css>
2071
+ :visited + span { color: red; }
2072
+ </pre>
2073
+
2074
+ Even tho this style sheet is applying an <a>allowed :visited property</a> to the <code> span</code> element,
2075
+ the <code> span</code> ’s <a>relevant link</a> can never be its previous sibling
2076
+ (it can only be the <code> span</code> or one of its ancestors).
2077
+ Since the [=apply :visited styling|:visible styling algorithm=]
2078
+ only checks if the element's <a>relevant link</a> is '':visited''
2079
+ (and treats all other links on the page as unvisited),
2080
+ this selector will never actually match anything.
2081
+ </div>
2082
+
2083
+ <details class=note>
2084
+ <summary> Why does '':visited'' have this strange behavior and restrictions?</summary>
2085
+
2086
+ Originally, '':link'' and '':visited'' did indeed work in the simple way
2087
+ described at the beginning of this chapter,
2088
+ like two ordinary mutually-exclusive pseudo-classes.
2089
+ It was eventually discovered, however,
2090
+ that this allowed pages to determine what other sites a user had visited,
2091
+ by listing a bunch of links off-screen
2092
+ and using JS to tell whether they were styled with '':link'' or '':visited'' .
2093
+
2094
+ This was bad both for user's privacy
2095
+ (for obvious reasons, sharing a user's browsing history with everyone is bad)
2096
+ and for their security
2097
+ (phishing attacks could, for example, tell which bank website a user visited,
2098
+ and render their phishing page to match that bank specifically,
2099
+ making it more likely to fool the user).
2100
+
2101
+ Rendering visited links in a different style was too useful to throw away entirely,
2102
+ so instead user agents developed the above algorithm
2103
+ to "lie" about the style in some contexts,
2104
+ but still rendering the link with '':visited'' styles normally,
2105
+ without paying too much extra computation time.
2106
+
2107
+ The very limited list of <a>allowed :visited properties</a>
2108
+ further limits the possibility of a page figuring things out.
2109
+ If '':visited'' could apply any property,
2110
+ pages could still,
2111
+ for example,
2112
+ apply a particular 'background-image' only when a link is visited,
2113
+ and then record whether that image was loaded from their server,
2114
+ giving them the exact information we were trying to hide!
2115
+ Similarly, any layout-affecting property,
2116
+ like 'width' ,
2117
+ might affect the positions of <em> other</em> elements on the page;
2118
+ lying about these knock-on effects to hide the styling
2119
+ would be much more expensive for the user agent.
2120
+ Limiting it just a handful of properties that can only apply colors
2121
+ ensures that as little information is leakable as possible.
2122
+ </details>
2123
+
2124
+ User agents may treat all links as unvisited at all times.
2125
+ (In particular, they can offer a user preference for this,
2126
+ allowing the user to decide whether the benefit of seeing when a link has been visited
2127
+ is more or less important
2128
+ than the possibility of that information being leaked to random pages on the internet.)
2129
+
2130
+ If the user agent uses some form of "link pre-loading"
2131
+ to find resource urls in a stylesheet
2132
+ and begin loading them before it's known that they'll actually be used on the page,
2133
+ they might find a url that would only be applied by an element matching '':visited''
2134
+ (which is impossible, as '':visited'' rules can't cause any properties to apply that load images).
2135
+ User agents with this behavior must ensure that either
2136
+ such urls are <em> never</em> loaded (preferable),
2137
+ or at least that such urls are loaded at the same time
2138
+ regardless of whether a link is visited or not.
2139
+
1988
2140
1989
2141
<h3 id="the-local-link-pseudo">
1990
2142
The Local Link Pseudo-class: '':local-link''</h3>
0 commit comments