Launchpad for textual, graphical, and interactive browsers

Rabbit or duckI think Launchpad is missing fundamental HTML, CSS, and JavaScript to support the three classes of browser with which someone might visit Launchpad. There are inconsistencies in pages you might visit, and some parts might not work because Launchpad does not have a “proven way” to solve a problem. I am most concerned about the rules of when something should be shown or hidden.

Launchpad intends to look good in graphical browsers, and gracefully degrade for textual browsers. Launchpad intends to be usable by everyone, and interactive browsers get enhanced features that makes the site easier to work with. We expect everyone who works with Launchpad regularly to use an interactive browser which provides information as needed and the best performance to complete a task. Essential tasks must be performable by textual browsers.

The three classes of browser Launchpad developers need to design for

Textual browsers convey all information with text, layout is less important and graphics are irrelevant. Textual browsers might be text-based browsers like W3m or Lynx, or it might be a screen-reader like Orca with a graphical browser. Textual browsers can also be bots, or even the test browser used by Launchpad’s test suite. All essential information must be expressible as text.

Graphical browsers use CSS-based engines to layout text and graphics in two dimensions. Chromium and Firefox are two of many browsers that might be used. Launchpad wants to use CSS 3, but it cannot be required since some browsers like Internet Explorer 8 use CSS 2. There is also the concern that all browsers have CSS and HTML bugs that require some care when crafting a page.

Interactive browsers support JavaScript to change the page content based on user actions. Again, Chromium and Firefox are two of many browsers that might be used, but a minority of users choose to use platform browsers like Internet Explorer, Safari, or Konqueror. Launchpad wants to use EcmaScript level 5, but will accept ES 3 with proper design.

Showing the essential, offering the optional, and hiding the unneeded

Consider the case for reporting a bug. This is an essential task everyone must be able to perform with the browser that they have available. Some steps in reporting a bug are optional, and might even be considered a distraction. Reporting a bug can take many minutes, but it can be made faster by showing or updating information at the moment of need.

Launchpad commonly makes links to add/report something like this:

<a class="sprite add" href="+action"></a>

The markup relies on CSS to show an icon in the background of the space allocated to the link. There is no text to convey the action is “Report a bug”. We have struggled to make this markup work in all browsers. I personally do not think this markup is legal. Anchors may be empty because they can have name attributes without href attributes. The HTML specification does not state an empty anchor with a href must be rendered. Older versions of webkit and khtml certainly do not render the sprite because there is no content to show. This markup is missing a description of what the link does.

Launchpad makes some links for its test browser that just happen to work brilliantly with textual browsers:

<a class="sprite add" href="+action"><span class="invisible-link">Report a bug</span></a>

Graphical browsers see an icon, and textual browsers see text. Well, this is not exactly true. Older webkit browsers do not show text or icon because there is no text to render. We use JavaScript to add an additional CSS class to the page so that a special CSS rules can add content before the hidden text to make the link visible. The “invisible-link” name is bad though, we do want the link visible, we just want a icon shown when the browser supports it. Like the previous example, graphical browsers still do not see a description of what the link does.

Launchpad commonly uses expanders to hide and show optional content. The blocks look something like this:

    <div class="collapsible">Options
        <div class="unseen">bug tags [ ]</div>
    </div>

Textual browsers can read the hidden content; they can set bug tags. Interactive browsers see “Options” and can reveal the content to set bug tags. Graphical browsers (or a browser where JavaScript failed) just see “Options”, it is not possible to set bug tags. The “unseen” CSS class could have been added after the script executed in the interactive browser to ensure it was hidden only if the browser could reveal it.

There is a problem with this example:

    <input id="update-page" class="unseen" type="submit" name="update-page" value="Update Page" />
    <img id="updating-content" class="unseen" src="/@@/spinner" />

Launchpad does not have classes that distinguish between interactive content that is “unseen” and graphical content that is “unseen”. The first line means interactive browsers cannot see the input element, and the second line means graphical browsers cannot see the img element. This ambiguity leads to cases where content that should be seen is missing, or vice versa.

Launchpad needs classes that mean what we intend

I image four classes are need to handle the cases for the three classes of browser.
readable
Textual browser can read or speak the content.
Graphical and interactive browsers to not show the content.
eg. links with sprites.
enhanceable
Textual and Graphical browsers can read, speak, and see the content.
Interactive browsers do not show the content, but can reveal it.
eg. expanders that show additional information or optional fields.
replaceable
Textual and Graphical browsers can read, speak, and see the content.
Interactive browsers do not see the content because it is superseded.
eg. forms that reload the page.
revealable
Textual and graphical browsers cannot read, speak, or see the content.
Interactive browsers do not show the content, but can reveal it.
eg. spinners that show loading in-page content.

The CSS classes need to interact with other classes on the page that help identify the class of browser:

readable
May need aural CSS to ensure it can be read and spoken.
enhanceable
No special properties needed.
enhanceable hidden
Scripts add the hidden class at the end of a successful setup because the content can be shown.
enhanceable shown
Scripts add the shown class at the end of a successful setup because the content can be hidden.
replaceable
No special properties needed.
replaceable hidden
Scripts add the hidden class at the end of of a successful setup because the content was replaced by interactive content.
revealable
The is not displayed because the browser must prove it can interact with it.
revealable shown
Scripts add the shown class at the end of a successful setup because the browser has demonstrated it can interact with the content.

Both the single “enhanceable” and “revealable” could be omitted because they are redundant with “enhanceable shown” and “revealable hidden”. I think the habit of placing classes that hide and show content in the page templates is dangerous. There are lots of cases where the page assumes a state before the class of browser is known. Page templates that use either “unseen”, or the  “hidden” class assume an interactive browser. It is not clear if textual and graphical browsers work by design, or by accident.

2 Responses to “Launchpad for textual, graphical, and interactive browsers”

  1. gz Says:

    Great analysis of the classes of classes needed. I wonder if the naming should reflect more clearly that it’s a 2×2 table of fallback/enhancement with non-graphical/non-interactive. What’s the argument for having ‘revealable’ present in the markup served, rather than just generated by the interaction when required?

  2. Curtis Hovey Says:

    Yes, I think 2×2 might help. Lp plans for the middle state of graphical, but it might also be easier to solve this by creating markup for textual browsers, that is enhanced by CSS for graphical browsers, that is then enhanced by script for interactive browsers.

    The ‘revealable’ case is largely driven by the many fragments that want to show things are happening at the moment content is being loaded. I think the Lp spinner is 80% or more of the cases. The spinner is bogus in this case because it is decoupled from the script that is actually doing the loading — hence some browsers perpetually show a spinner because series timeline script aborted because the canvas is required. So ‘revealable’ is not needed if the script makes all its markup. Some of the arguments for the convenience of embedding the markup can be solved using the type=”text/x-template” technique.

Leave a Reply