It is precisely in knowing its limits that Philosophy existsImmanuel Kant
Also relates to DOM Scripting
One of the stumbling blocks for achieving Triple A Conformance of the WCAG 1.0 is Checkpoint 10.4 regarding placeholder text for form controls:
Until user agents handle empty controls correctly, include default, place-holding characters in edit boxes and text areas.Checkpoint 10.4 Web Content Accessibility Guidelines 1.0
This is actually an interim solution to accomodate certain legacy assistive technologies that can not handle empty form controls. However, accessibility can be improved if, in meeting this checkpoint, the placeholder text is informative text that assists the user with the information they should enter. For example:
<input type="text" id="name" name="name"
value="Please enter your name"/>
<input type="text" id="tel" name="tel"
value="Your Phone Number - 01234 123123"/>
This information can be valuable to the user where a complex form is layed out with tables and the label may be detached from the field it relates to. To ease the form completion process a Javascript event may be attached to the form field to clear the placeholder text when focus is received.
<input type="text" id="name" name="name"
value="Your name"/
onfocus="if(this.value=='Your name')this.value=''"/>
With a multi-field form the inclusion of a large number of onfocus event handlers will bloat the HTML so this behaviour should be defined in a separate script file.
var helpers = ['Please enter your name', '…', … ];
function addFieldListeners() {
var elems = document.forms[0].elements;
for (var i = 0; i < elems.length; i++) {
if (elems[i].type == "submit") {continue;}
elems[i].onfocus = function(evt) {
evt = (evt) ? evt :
(window.event) ? window.event : null;
if (evt) {
var elem = (evt.target) ? evt.target :
(evt.srcElement) ? evt.srcElement : null;
if (elem) {
var value = elem.value;
for (var i = 0, m = helpers.length; i < m; i++) {
if (value == helpers[i]) {
elem.value = "";
}
}
}
}
}
}
}
Here an anonymous function is assigned to each form field and when focus is recieved the value is
tested against an array of predefined placeholder text strings. This code could be cleaned up by assigning a
new array search function to the Array object prototype property, and a global function for retreiving the element that
received the event (since other behaviour in the document may require this). This solution will suffice, with
new placeholders just added to the helpers array, but in larger projects this in itself can
become quite a tiresome process - take a content management system as an obvious example.
Working on a CMS solution just the other day I thought about using the title attribute of the input field to store the placeholder text. My initial thinking was that this could still provide the helper information to the user after they had set focus on the field. If they were jumping around a large form, the user should not be expected to remember the helper text once it has been cleared. Plus the purpose of the title attribute is to provide additional information for the element - exactly what the helper/placeholder text is doing in this scenario. So, this time, using the closure technique discussed previously, the following:
<input type="text" id="name" name="name"
accesskey="n"
title="Please enter your name"
value="Please enter your name" />
could be handled with the following field listener:
function FieldListener(elem) {
this.elem = elem;
this.helper = "";
var me = this;
this.init = function() {
this.helper = this.elem.getAttribute('title');
// Scott Andrew's addEvent method at
// www.scottandrew.com/weblog/articles/cbs-events
addEvent(this.elem, "focus", this.clear);
addEvent(this.elem, "blur", this.redisplay);
}
this.clear = function(evt) {
if (me.helper == me.elem.value) {
me.elem.value = "";
}
}
this.redisplay = function(evt) {
if (me.elem.value == "") {
me.elem.value = me.helper;
}
}
}
The FieldListener object stores the title attribute value in a member variable when it is instantiated, then when the field receives focus, the field value is compared against this member variable. Functionality can be extended by redisplaying the placeholder text if the field is still empty when the user moves focus elsewhere - the FieldListener.redisplay() function achieves this. This event listener can be bound to each form field (along with other behaviours - eg pseudo CSS, validation) as follows:
function register(collection) {
var i, elem, listener;
for (i = 0; elem = collection.item(i++); ) {
if (elem.nodeName == "INPUT" &&
elem.getAttribute("type") != "text")
{continue;}
listener = new FieldListener(elem);
listener.init();
}
}
function __init() {
if (document.getElementsByTagName) {
var input_flds = document.getElementsByTagName('input');
register(input_flds);
var textarea_flds = document.getElementsByTagName('textarea');
register(textarea_flds);
}
else {
nastyHackToHandleNonW3CDom();
}
}
// see Simon Willison's addLoadEvent entry at
// http://simon.incutio.com/archive/2004/05/26/addLoadEvent
addLoadEvent(__init);
An alternative function would need to be provided for legacy browsers that do not support DOM2 (Netscape 4.x, MSIE 4.x). Perhaps just selecting the placeholder text on field focus so the user can delete it if they wish to (DOMElement.select()) may suffice. To round off, this modular solution provides a simple automated approach to handling placeholder text that does not require the author to expicitly register the text within the Javascript code - the whole process is automated based on the value of the title attribute.
Posted on Jul 01, 2004 at 16:34:43. [Comments for Automating Placeholder Text In HTML Forms- 4]
Also relates to CSS Design
Defining CSS layouts with negative margins requires a high level of precision to ensure that all siblings are cleared effectively. Pie-fecta was the earliest example of this technique, demonstrating a complex set of dependant CSS rules. But, this should not make the technique so daunting that it is ignored. Ryan Brill's recent publication provides an insight into the simpler side of the technique. Only glimpsed at in his article, negative margins offer one huge benefit that should put table-based design to rest once and for all - flexible document structure.
As a scenario take the following document structure that defines the main content areas for a three column layout:
<div>
<div id="center"> </div>
<div id="left"> </div>
<div id="right"> </div>
</div>
Since the central column contains the main content, I have chosen to lead with it in the document structure for accessibility and SEO. The left column contains the navigation menu, and the right column a subsidiary menu/content (or perhaps advertising). Deeper into the site hierarchy, I decide to utilise the right column to bind additional information to the central column (eg links to related articles, or recent material). However, the document structure will now be detached since the main navigation (in the left column) separates the two bound columns. While this is of little relevance on a styled page where the columns are always in the same position, it is counter-intuitive for assitive devices or an intelligent search bot, where the style rules do not apply. The solution is to flip the left and right columns in the document tree. And the good news is with negative margins this can be achieved without changing a single rule in the underlying CSS!
So now it is time for the mathematics. I started this entry by emphasising the importance of precision, and there is no better way to ensure this than some CSS algebra.
α = column 1 width (#middle)
β = column 2 width (#left)
γ = column 3 width (#right)
Δ = predefined balancing unit
#middle {
float:left;
width:α;
margin:0 [-(α+(β-Δ))] 0 β;
}
#left {
float:left;
width:β;
margin:0 0 0 -Δ;
}
#right {
float:right;
width:γ;
}
The middle column is given a negative right margin to the value of its own width (α) plus the left margin (β) less a predefined unit (Δ). This provides the entire width of the parent container less one unit on the left for the middle column's siblings. The left column is floated with a negative left margin to the value of the predefined unit to place it flush left to the parent. The right column is simply floated right. The predefined unit is arbitrary, but obviously should be less than the width of the left column - I generally use a unit of 1 (eg 1em, 1px, 1%). The underlying premise behind this principle is explained in the CSS2 Specification.
A float can overlap other boxes in the normal flow (e.g. when a normal flow box next to a float has negative margins) Visual Formatting Model, CSS2 Specification
Now, the right and left column can be reversed in the document tree without any need for additional rules or any detrimental affect on the presentation. A clearing element will apply to all three columns - allowing any column to be longest (resolving the inherent problem with absolute positioning).
Here are a few examples:
These examples have been tested across all the major PC browsers, but I have not had an opportunity (or time) to test them on Mac and Linux. The only major bug arises in IE6 for a contained liquid width (ironically not IE5.x). There is also a gotcha involving preformatted text in the IE browsers for both liquid and fixed widths (explained in the above examples). The only hack required accounts for the IE Doubled Float-Margin Bug by declaring the containers' display inline.
Any layout containing floats has potential for browsers discrepancies (eg Peekaboo bug and IE Float Margin as above) and potential self-destruction. So far on quite complex test examples I have found this technique to work adequately cross browser. Plus, in theory the technique can also be applied to sub-containers - so long as the formula is balanced the columns can be cleared.
As for colouring the columns, the Faux Columnstechnique or a similar set of containing wrappers is required. IMHO, such non-semantic containers should be avoided in the document. This can be resolved by utilising presentational javascript. The presentation should first be made accessible to users with no javascript, then an onload event handler can be attached to the window object which performs the wrapping. Here is a little example, which I intend to write up soon - the Elastic Fantastic.
Posted on Jul 01, 2004 at 00:59:57. [Comments for CSS Negative Margins Algebra- 1]
Also relates to DOM Scripting
Thanks to Simon Willison's interesting post on closures in Javascript I recently rediscovered
W3Future's article on applying closures to event handling methods. This article provides a very illuminating resolution
to the common problem in separating the behaviour of a web page from the structure - the method assigned as the event handler to an object does not contain a reference to the object itself (at least not in IE).
Traditionally this could be solved with a cross browser concoction of event.target, window.event.srcElement and bubble management.
The closure paradigm is a very adaptable and dynamic solution, that not only allows clean cross browser access to the source element, but is readily extensible in an object oriented environment:
function EventHandler(elem) {
this.elem = elem;
this.evt = "";
this.register = function(handler, fn) {
addEvent(this.elem, handler, fn);
}
this.invoke = function(evt) {}
this.cancel = function() {}
}
function FieldHandler(elem) {
var me = this;
this.base = EventHandler;
this.base(elem);
this.mouseon = function(evt) {
me.invoke(evt);
}
this.mouseoff = function(evt) {
me.invoke(evt);
}
}
FieldHandler.prototype = new EventHandler;
handle = new FieldHandler(DOMElement);
handle.register('mouseover', handle.mouseon);
handle.register('mouseout', handle.mouseoff);
The me variable provides access each instance of the FieldHandler object, which would otherwise be unavailable. (Note EventHandler::register it uses Scott Andrew's
Cross Browser Event Handling routine
to assign the event listeners.) Another use might be to assign the callback function for the event at runtime based on the event type:
function EventHandler(elem, me) {
var me = this || null;
// …
this.invoke = function(evt) {
me.evt = (evt) ? evt :
((window.event) ? window.event : null);
me.assign();
}
this.assign() = function() {}
// …
}
function FieldHandler(elem) {
this.base(elem, me);
// …
this.assign() = function() {
switch(this.evt.type) {
case 'mouseover':
this.mouseon();
break;
case 'mouseout':
this.mouseout();
break;
}
}
// …
}
// …
handle.register('mouseover', handle.invoke);
handle.register('mouseout', handle.invoke);
The one stumbling block I fell over briefly was the cancelling of an event. A typical example being a stylesheet switcher where a link is supplied to switch the CSS on
the server where Javascript is not available. In a Javascript environment the HTTP request should be cancelled. Sadly, using event attachment to assign handlers, return false will not cancel the operation.
Information on this hurdle appears to be lacking on the web, but fortunately the solution was nestled in the DOM2 Events Specification:
this.cancel = function() {
if (this.evt) {
if (this.evt.preventDefault) {
this.evt.preventDefault();
}
this.evt.returnValue = false;
}
}
In the W3C event model preventDefault called anywhere within an event processing tree will cancel the default event. For the Exploders falsify the returnValue property for the event.
These are very basic examples, but just in an afternoon I discovered immense power in this method without the need to hack cross browser
scripts (I have tested the method successfully across all the major PC browsers - IE5.x, IE6, Moz, Opera). I have started work on integrating the EventHandler class
into my form validation scripts and will hopefully present this as a more detailed and explanatory article when I find more time. The biggest benefit of the method is it allows for
the behavioural scripts to be totally detached from the mark-up for a web document, thus only serving javascript content where it can be handled while achieving a more lightweight document.
Posted on Jun 20, 2004 at 03:39:51. [Comments for Accessible Javascript Event Handling- 6]
Also relates to Web Standards
Yes, it is official! The Guild of Accessible Web Designers (GAWDS) makes its launch today, thanks to the dedicated work of Jim Bryne and the rest of the GAWDS members.
Accessibility goes far beyond preparing Web sites for disabled people. Accessibility is now shorthand for the adoption of core standards that benefit every user of the Internet and impact the bottom line of every business. GAWDS intends to promote these standards to instill in Web designers the high level of competence and professionalism required to unlock the full potential of the Internet. Jim Bryne, GAWDS Founder
While the public readily understands how inaccessible Web sites limit the flow of information to people with disabilities, many business owners fail to see the detrimental effects of inaccessible or non standards-based design on their bottom line. The number of user agents that still tolerate sloppy, invalid markup is shrinking. With the emergence of new technologies and devices, this means that client and consumer audiences are also shrinking for businesses that rely on old-style, idiosyncratic Web sites that make it difficult to parse content for re-use.Derek Featherstone, GAWDS Founding Member
Read the full press release to gain an insight into the objectives of GAWDS to bring Web Standards and Accessibility to the forefront of web design and development, and peruse the opinions of a number of members on the future and importance of accessibility. Then, once you have got a feel for the Guild, why not have a go at the site redesign competition to win a great prize and ultimate kudos!
Posted on May 26, 2004 at 04:00:33. [Comments for GAWDS Cracks The Whip- 0]
Also relates to Web Standards and Apache, Firefox and Co
This is a very annoying quirk that took me far too long to track down! When calling pages on my test platform using a new caching system and a package of builder classes for parsing XML based metadata a second call for a page was being made to the server. In short, the page in question was that defined as next in the relative links:
<link rel="next"
href="/uri_of_page/"
title="Description of the page/>
At first I thought this was down to a coding error in one of the PHP classes. Fortunately browsing the HTTP headers and a timely flick through the HTML 4.01 Specification abated my growing frustration. The specification states the following for the next link type:
Refers to the next document in a linear sequence of documents. User agents may choose to preload the "next" document, to reduce the perceived load time. http://www.w3.org/TR/html401/types.html#type-links
Well it is the second sentence that is clearly significant here. The second call for a page to the server abides to the above recommendation. In fact on further scrutiny I discovered this problem is distinctive to Mozilla family which utilise the link toolbar (I did not take further time out to test on Opera).
I see a major conflict in this. The relative links have been adopted as important elements for accessible navigation and are a recommended technique for achieving several guidelines in the WCAG at level 2 and 3. Yet, as long as user-agents abide to the above statement regarding the next link type, there is a conflict of interest between attaining accessibility and maintaining reliable web server logs! This is especially so with Webalizer, the most popular open source software for producing tabular and graphical statistics from Apache's Common Logfile Format. For each pre-loading call to the webserver will register an additional page hit for that page in the access log. If the user actually visits the page via the next link a second page impression will be registered!
Fortunately for once, Exploder is beneficial here, since it has no idea whatsoever about relative links, and therefore the above over-logging will not occur. Sadly this may explain why on a number of my clients sites (this site included) Mozilla and co are falsely striving into the lead on the browser stakes! One solution may be to flush out the pre-loading entries by looking for calls for two separate pages from the same IP address within a second or two of each other. If I can find a minute may call for some Awk and Sed.
Posted on May 21, 2004 at 23:42:26. [Comments for Next Link Misleads Logs- 0]