This is a proposal to extend CSS and HTML to allow applications to define their own media features. Browsers would then provide an API to their extensions and add-ons, allowing them to control the values of those features on a per-tab basis.
This document presents five solutions to a problem faced by this project. Three are considered inadequate, but have been tried with varying degrees of success. One is an improved solution that may be objected to on non-technical grounds. Finally, an ideal solution is presented that would exploit the proposed extension to media features.
We wanted webmasters to be able to retain in-band navigation alongside their sitemaps, for visitors that don’t have browsers capable of viewing the sitemaps. However, visitors that do see the sitemaps don’t want to see the duplicate in-band navigation, so we needed a way to switch off the in-band navigation while the sitemap is presented.
Furthermore, we wanted to support a scale of display levels, whereby a sitemap isn’t simply displayed or hidden. Instead, there are degrees of availability of the sitemap, and the author may choose to reveal more page content to compensate for gradual unavailability.
Several solutions have been devised and tried with varying success. All have their drawbacks.
<link rel="stylesheet">
Under this solution, as soon as possible when a page is loaded, a stylesheet is added to the page by inserting a <link rel="stylesheet">
element into the page.
The author specifies the URI in the sitemap.
If the sidebar is closed, the <link>
must be removed.
If the sidebar is opened (again), it must be (re-)added.
The extension must be able to locate the <head>
element in the page, and either add a <link>
child, or identify the one it added earlier and remove it.
The author must write additional styles in a separate file, e.g.:
/* sitemap-styles.css */ #in-band-nav { display: none; }
…and link to it in the sitemap:
<sitemap ...> <style href="sitemap-styles.css" /> ... </sitemap>
This technique was found to be prone to flicker when moving between pages in the same site, as the page was partially rendered before the insertion could be done. It also requires the author to provide an extra stylesheet, rather than including his sitemap-specific styles in existing sheets. Furthermore, it forces the browser add-on to make a judgement about where to insert the styles in the cascading order, rather than leaving it up to the author.
Under this solution, the Firefox extension uses part of Firefox’s extension API to control user stylesheets. Again, the user specifies the additional sheet’s URI in the sitemap.
The extension must fetch the linked stylesheet, sanitize the content and protect it so that it will only apply to pages on the site, and then use the Stylesheet Service to inject it into the cascade.
The author must write additional styles in a separate file, e.g.:
/* sitemap-styles.css */ #in-band-nav { display: none !important; }
…and link to it in the sitemap:
<sitemap ...> <style href="sitemap-styles.css" /> ... </sitemap>
The main advantage here is that, when navigating within a site (i.e., between two pages declaring the same sitemap), the additional sheet is already in place as you move to the second page. Therefore, there can be no flicker.
However, it has some major flaws:
As part of a user stylesheet, the rules appear very early in the cascading order, and so are overridden by later rules, such as the author’s main page styles.
The author is forced to work around this by adding !important
to the sitemap rules.
User stylesheets apply to the whole browser, not just a single tab.
Other tabs are therefore polluted with the same styles, even though they are meant to apply to only some tabs.
Tabs showing unrelated pages have to be protected by wrapping the author’s styles in @-moz-document url-prefix
declarations, which does not necessarily match the author’s definition of what pages belong to a site.
Even tabs showing pages in the same site are all forced to show the additional styles, or all to show none, even though some of those tabs may be showing the sidebar while others are not.
As with injecting <link rel="stylesheet">
, it also requires the author to provide an extra stylesheet, rather than including sitemap styles in existing sheets.
This technique allows the author to employ class-based styling, whereby the sitemap add-on makes dynamic changes to the HTML to trigger the author’s CSS to hide the in-band navigation.
Under this solution, the author specifies rules in the sitemap directing the add-on to alter the HTML, specifically the classes that apply to a given element. The HTML document does not change structurally, but rather the value of a single attribute is modified, in an author-defined manner.
The extension must extract parameters from the <class-change>
element in the sitemap, use the XPath expression within it to locate the specified element within the page (usually <body>
), parse the space-separated class list in its class
attribute, and replace that list with class names of the forms sitemap-over-N and sitemap-under-M.
The author must write additional styles in any sheet that the page uses, with a selector that depends on injected classes, e.g.:
/* sitemap.css */ body.sitemap-over-49 #in-band-nav { display: none; } /* other styles not related to sitemaps */ ...
<html> <head> ... <link rel="stylesheet" href="sitemap.css"> </head> <body> ... </body> </html>
…and specify in the sitemap the way to modify each page:
<sitemap ...> <class-change xmlns:html="http://www.w3.org/1999/xhtml" elem="/html:html/html:body" attr="class" prefix="sitemap" /> ... </sitemap>
The main advantage here is that the sitemap styles can be embedded in the author’s existing stylesheets, so he has control over cascading order, and does not need to provide an extra file. The changes also apply to the content of only the relevant tabs. Also, this mechanism was designed from the outset to support multiple display levels.
The main disadvantage is that changes can only be applied some time after loading, with the risk of flicker. In its defence, perhaps because there are no structural changes to the HTML, this occurs fast enough to avoid flicker. However, it may still depend too much on local factors, such as browser efficiency and computer speed.
A base set of media features is defined for some media types, and it is observed in many modern browsers that these are effectively variable characteristics of a browser tab that can change dynamically and effect an immediate change in the styles that get applied. For example, an author could have his page use a multi-column layout only if enough horizontal space (say, 60em) is available for it, defaulting to a simpler layout if not:
/* ... single-column layout... */ /* Access the 'width' media feature... */ @media (min-width: 60em) { /* ... multi-column layout ... */ }
This technique can also be used in fail-safe manner, as the example shows. That is, if encountered by a browser that does not understand the media feature, all the styles guarded by it are disabled.
We could use this technique to avoid all problems encountered by the other solutions described above, if only we could define a new media feature, say sitemap-presence
, whose value is one of the display levels.
As a sitemap becomes available or unavailable, or as it is displayed or hidden, the extension must update the current display level for the tab, and report it to the browser with a call such as:
tab.setFeature('sitemap-presence', 67);
The author must write additional styles in any sheet that the page uses, with a selector that depends on the new media feature, e.g.:
@media (min-sitemap-presence: 50) { #in-band-nav { display: none; } }
The two problems here are one of standardization, and one of its acceptance by browser implementors.
We must persuade standards bodies that sitemap-presence
is a generally useful feature, which depends on browser implementors being prepared to agree on it and implement it.
Furthermore, the browser implementors must provide a way for the sitemap add-ons to control this new media feature as a variable. (This doesn’t have to be the same across all browsers, as it’s part of the browser/add-on API, which is already browser-specific.)
This isn’t going to happen without some prior momentum behind the navigational sitemap concept, which isn’t going to exist without at least one working implementation already supporting it; a chicken-and-egg problem.
The ideal solution would require a standardized extension to HTML and CSS, i.e., support of namespaces in media-query features.
What if media features were not set in stone, and various, unrelated applications and bodies could devise their own arbitrary media features without further standardization and implementation? The usual way to permit this, as seen in XML and CSS, is to allow users to define new namespaces, identified by URI, and then let the user owning that namespace populate it as he sees fit.
CSS already supports the definition of mappings between local prefixes and global namespace URIs, and these prefixes can then be used on element and attribute names within an XML (or XML-like) document. By allowing such prefixes to be used on media features too, we immediately deal with the standardization issue, and have a way to express sitemap styles concisely, and entirely in CSS.
As a sitemap becomes available or unavailable, or as it is displayed or hidden, the extension must update the current display level for the tab, and report it to the browser with a call such as:
tab.setFeature('http://standard-sitemap.org/2007/ns', 'presence', 67);
The author must write additional styles in any sheet that the page uses, enclosed in a media query that depends on the current display level, e.g.:
@namespace ssp url(http://standard-sitemap.org/2007/ns); @media (ssp|min-presence: 50) { #in-band-nav { display: none; } }
As soon as setFeature
is called, dependent styles applied to the content of the tab are immediately affected.
If the user navigates to another page in the site, the value of the variable persists, and the styles continue to apply to the subsequent page, so there should be no flicker on internal navigation.
If the user navigates from one page with a sitemap to a page that has no sitemap, that page will not need any sitemap-dependent styles, so the fact that the present value persists for a short moment before being corrected by the add-on will not cause any flicker. If the user navigates to a page using a different sitemap, there will only be flicker if the site warrants a different display level.
Do you carry any weight in the community of Web standardization? Can you promote this? Can you devise more (and more compelling) use cases that would help to convince others of the general utility of such a feature? Can you propose anything better?
All five solutions are summarized below in terms of six desirable properties.
Class injection is the best solution that can be achieved without standardization. Even its one fault, the risk of flicker, appears not to manifest on sufficiently capable devices, perhaps aided by its minimalistic approach to alteration of the DOM.
Devising a new media feature for a specific application solves the flicker problem, but depends on standardization. This is mitigated by standardizing on a generic, extensible mechanism for devising new features, based on URI namespaces. Devising a sitemap feature then becomes a mere application of this mechanism, which is suitable for other applications.
Solution | Properties | |||||
---|---|---|---|---|---|---|
Combination of sitemap and non-sitemap styles in same sheet | Tab isolation | Elimination of flicker risk on internal navigation | Author-defined cascade | Avoidance of standardization | Avoidance of ad-hoc standardization | |
<link> injection | (forced at end) | |||||
user-stylesheet injection | (forced at start) | |||||
class injection | ||||||
ad-hoc standardized media feature | ||||||
namespaced media feature | (requires standardization of a more generic mechanism) |