<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0"
    xmlns:dc="http://purl.org/dc/elements/1.1/"
    xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
    xmlns:admin="http://webns.net/mvcb/"
    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
    xmlns:content="http://purl.org/rss/1.0/modules/content/">

    <channel>
    
    <title>Filament Group, Inc: Lab</title>
    <link>/lab</link>
    <description>What we're thinking at Filament Group</description>
    <dc:language>en</dc:language>
    <dc:creator>scott@filamentgroup.com</dc:creator>
    <dc:rights>Copyright 2008</dc:rights>
    <dc:date>2008-03-20T20:08:00-05:00</dc:date>
    <admin:generatorAgent rdf:resource="http://expressionengine.com/" />
    

    <item>
      <title>Developing an accessible slider</title>
      <link>http://www.filamentgroup.com/lab/developing_an_accessible_slider/</link>
      <guid>http://www.filamentgroup.com/lab/developing_an_accessible_slider/#When:20:08:00Z</guid>
      <description><p>Creating accessible "web 2.0" applications can be a tricky process.  Many of the advanced widgets and controls we develop today don't exist in the current HTML specification &#8212; there is no "slider" or "accordion" or "menu" element, so we must create one from scratch using markup that isn't semantically correct (divs, spans, unordered lists and the like), and layer on the appearance and behavior using CSS and Javascript.  This works well when your audience is using a standards-compliant browser, but what about those using older browsers or mobile devices that only partially support the styles and scripts necessary for it to work?  And how do you make the fully functional version &#8212; a block of non-specific divs and spans &#8212; accessible to assistive technology, like screen readers?</p><p>The solution we devised is based on the core principle of progressive enhancement: start with basic, functional markup and then layer on complexity, if supported.  In most cases, <a href="/lab/delivering_the_right_experience_to_the_right_device/">coding for progressive enhancement</a> allows us to build a single code base for both the basic and enhanced versions; we then apply additional CSS and Javascript to create the richer experience for capable browsers.  But when we're developing the UI for a web application and creating widgets that capture data, we're often starting with form element markup that doesn't readily cooperate with CSS, or that doesn't have all the moving pieces necessary to create a more complex widget.</p>

<p>To solve this problem, we developed an "element API" &#8212; a script that combs a form element for relevant information (data values, key structural characteristics), and uses that information to build a new widget on the fly and insert it into the DOM. Below we describe a test case that outlines our process for making this work.</p>

<h2>An "element API"</h2>

<div class="example_right">
<img src="http://72.47.209.59/images/sliderconvert_sml.png"  alt="select element converted to slider widget" width="235" height="85" class="illustration" />
</div>

<p>Recently we designed and developed an interface that required a slider control, which allows users to choose one or a range of values on a continuum. Values on a slider can represent anything from hours on a clock to the volume on a music player to a complex, proprietary data set.  In its simplest form, the slider is displayed as an axis of values with a handle to drag and select a value, or two handles for selecting a range.</p>

<p>Because there is currently no slider element in HTML, the slider is made up of non-semantic markup (divs, spans), and requires advanced CSS (positioning, background images) and Javascript to work properly.  In the absence of CSS or Javascript, the slider is unusable, and the markup is meaningless to users navigating the page with keystrokes or screen readers.</p>

<p>For the slider to be usable in the absence of styles and scripts, we decided that alternate markup is necessary &#8212; rather, we applied the principals of progressive enhancement and looked for an analogous HTML form element that could do the job on its own, something with similar features and functionality that:</p>

<ul>
<li>supports selecting a single value, or a range,</li>
<li>provides feedback on the value selected, and</li>
<li>allows for a default value to be set.</li>
</ul>

<p>We chose the &lt;select&gt; form control because, like sliders, it natively performs the functions listed above, and also comes with the added bonus of grouping multiple options (with the &lt;optgroup&gt; tag) and clean management of large data sets.  Then, to make the slider we created a script &#8212; an element API, or connector script &#8212; that leveraged the structure, data values, and labels in the standard select element.  The select is served to all browsers, and if the browser can support the slider's advanced styles and scripts, it's hidden and a slider is inserted into the page.</p> 

<p>So we took a standard select element:</p>

<form action="#">
<fieldset>
	<p><select name="speed">
		<option value="Slower">Slower</option>
		<option value="Slow">Slow</option>
		<option value="Med">Med</option>
		<option value="Fast">Fast</option>
		<option value="Faster">Faster</option>
	</select></p>
</fieldset>
</form>

<pre>
&lt;select name=&quot;speed&quot;&gt;
	&lt;option value=&quot;Slower&quot;&gt;Slower&lt;/option&gt;
	&lt;option value=&quot;Slow&quot;&gt;Slow&lt;/option&gt;
	&lt;option value=&quot;Med&quot;&gt;Med&lt;/option&gt;
	&lt;option value=&quot;Fast&quot;&gt;Fast&lt;/option&gt;
	&lt;option value=&quot;Faster&quot;&gt;Faster&lt;/option&gt;
&lt;/select&gt;
</pre>

<p>And used it to create a slider when the browser is capable of rendering advanced CSS and Javascript:</p>

<iframe src="http://www.filamentgroup.com/examples/slider/" style="height: 14em"></iframe>

<pre>
&lt;div class=&quot;sliderControl&quot;&gt;
	&lt;ol class=&quot;xScale clearfix&quot;&gt;
		&lt;li class=&quot;Slower&quot;&gt;&lt;span&gt;Slower&lt;/span&gt;&lt;/li&gt;
		&lt;li class=&quot;Slow&quot;&gt;&lt;span&gt;Slow&lt;/span&gt;&lt;/li&gt;
		&lt;li class=&quot;Med&quot;&gt;&lt;span&gt;Med&lt;/span&gt;&lt;/li&gt;
		&lt;li class=&quot;Fast&quot;&gt;&lt;span&gt;Fast&lt;/span&gt;&lt;/li&gt;
		&lt;li class=&quot;Faster&quot;&gt;&lt;span&gt;Faster&lt;/span&gt;&lt;/li&gt;
	&lt;/ol&gt;
	&lt;div class=&quot;scale&quot;&gt;
		&lt;span style=&quot;left: 0pt;&quot;/&gt;
		&lt;span style=&quot;left: 31px;&quot;/&gt;
		&lt;span style=&quot;left: 62px;&quot;/&gt;
		&lt;span style=&quot;left: 93px;&quot;/&gt;
		&lt;span style=&quot;left: 124px;&quot;/&gt;
	&lt;/div&gt;
	&lt;div aria-valuemax=&quot;Faster&quot; aria-valuemin=&quot;Slower&quot; role=&quot;slider&quot; class=&quot;indicator1 sliderIndicator&quot; tabindex=&quot;1&quot; aria-valuetext=&quot;Slower&quot; aria-valuenow=&quot;Slower&quot;&gt;
		&lt;span class=&quot;indicatorFeedback1&quot;&gt;Slower&lt;/span&gt;
	&lt;/div&gt;
&lt;/div&gt;
</pre>

<h3>Need to capture a range of values?</h3>

<p>We developed the connector script to be smart &#8212; it acts on a single container element and detects the number of child select elements.  When a single select is found, the script injects a slider with one pull handle for choosing a single value on the continuum.  When a second, identical select element is found in the container, the script injects a slider with two pull handles for specifying a range of values as shown in the example below.  Users without advanced CSS and Javascript can simply choose the low and high end values from each select, respectively.</p> 

<iframe src="http://www.filamentgroup.com/examples/slider/index2.php" style="height: 15em"></iframe>


<h2>Our process</h2>

<h3>Start with solid markup</h3>

<p>When writing the markup for the select control, we paid particular attention to how the select's standard child elements, values, and text map to similar elements in the slider:</p>

<ul>
<li><b>the number of options (&lt;option&gt;)</b> is used to calculate the scale and distance between labels on the slider axis</li>
<li><b>option selected attributes (selected="selected")</b> are translated into default values on the slider</li>
<li><b>option value attributes (value="abc")</b> provide feedback in the form of a "tooltip" that sits above each slider handle</li>
<li><b>option text nodes (&lt;option&gt;Text&lt;/option&gt;)</b> become the labels along the slider axis</li>
<li><b>optgroup elements (&lt;optgroup&gt;)</b> are used for dividing the axis into regions, like AM and PM, and</li>
<li><b>optgroup label attributes (&lt;optgroup label="AM"&gt;)</b> are used to identify the axis regions.</li>
</ul>

<h3>Apply enhanced CSS and Javascript, if supported</h3>

<p>As the page loads, we test the browser to see if it's capable of rendering advanced styles and scripts correctly.  If it fails the test, nothing happens &#8212; the browser renders the simple, fully functional markup it started with.  But if it passes, the test script applies advanced styles and scripts for a richer, more interactive experience. That's when we use the script to hide the select and insert the slider.  (We describe how we test a browser's capabilities and provide an enhanced experience in <a href="/lab/delivering_the_right_experience_to_the_right_device/">Delivering the right experience to the right device</a>.)</p>

<p><em>Really important side note:</em> we wrote the connector script &#8212; a plugin based on an older version of the <a href="http://jquery.com/" class="external">jQuery library</a> &#8212; that specifically builds a slider from a select element.  The script that runs the slider is part of the <a href="http://interface.eyecon.ro/" class="external">Interface UI library</a>, also based on jQuery.  If you'd like to reproduce this code, we strongly recommend that you grab the latest version of jQuery and create a new slider &#8212; a good starting point may be the updated slider in  <a href="http://dev.jquery.com/view/trunk/ui/demos/ui.slider.html" class="external">jQuery's UI library</a>.  You're welcome to use our connector script as a model, just keep in mind that it will need to be updated and edited for production-ready code.</p>

<h3>Keep it accessible for all users</h3> 

<p>The slider markup is injected into the DOM immediately after the select element, and the select is hidden visually (it's still in the source).  Events assigned through the DOM allow the user to manipulate the slider, which in turn updates values in the hidden select element so that the correct select option is submitted with the form.  And since the select element is still technically on the page, users with assistive devices can use it in place of the slider.</p>

<iframe src="http://www.filamentgroup.com/examples/slider/index3.php" style="height: 25em"></iframe>


<p>We've also added attributes to the slider component as specified in the <a href="http://www.w3.org/TR/wai-aria/" class="external">WC3's ARIA spec</a>. ARIA attributes provide another layer of accessibility because they allow developers to declare the role of each non-semantic widget. Browsers such as IE8 and Firefox 3 have begun to support these features, so we're excited to begin using them in our applications.</p>

<p>A slider can be made ARIA-accessible by adding the following attributes to the slider handle (which in this case is a div element):</p>

<ul>
<li>tabindex allows the element to receive keyboard focus</li>
<li>role="slider" makes the assistive device aware of the slider control</li>
<li>aria-minvalue is the minimum value in the slider scale</li>
<li>aria-maxvalue is the maximum value in the slider scale</li>
<li>aria-valuenow is the currently selected value</li>
<li>aria-valuetext is a user-friendly equivalent of the currently selected value</li>
</ul>

<p>The markup with ARIA attributes:</p>
<pre>
&lt;div role="slider" aria-valuemin="6am" aria-valuemax="8pm" aria-valuetext="11am" aria-valuenow="11am" tabindex="1"&t;&lt;/div&gt;
</pre>

<p>The slider examples shown here are ARIA-accessible, and currently some key events are in but need more work to be fully functional.  Making the key events work correctly is something we consider to be a necessity, so it's something we'll continue to refine.</p>

<p>We're always looking for ways to improve our code and its accessibility &#8212; in particular, we're working on ways to make the "API" more generic &#8212; so If you have any ideas about how to fine tune this concept, <a href="#comment_form">please drop us a line</a>.</p></description>
      <dc:subject>accessibility, css, javascript, jQuery, progressive enhancement</dc:subject>
      <dc:date>2008-03-20T20:08:00-05:00</dc:date>
    </item>

    <item>
      <title>Markup &amp;amp; Style Society recap</title>
      <link>http://www.filamentgroup.com/lab/markup_and_style_recap/</link>
      <guid>http://www.filamentgroup.com/lab/markup_and_style_recap/#When:16:44:00Z</guid>
      <description><p>Along with the founders, Dan Cederholm and Ethan Marcotte, we hosted the latest meeting of the <a href="http://markupandstyle.org/" class="external">Markup & Style Society</a> in our office on South Street Thursday night.</p><p><img src="http://72.47.209.59/images/mss-crest.gif" width="179" height="101" style="float: right; margin-left: 15px;" />All told it was a great success &#8212; about fifty designers and developers from the area joined us to talk shop about building responsive, stretchy layouts, what it means to be a craftsman (or -woman) in this space, and a new method for applying progressive enhancement to web applications.  Some highlights:</p>

<p><b>Ethan Marcotte</b> (<a href="http://airbagindustries.com/" class="external">Airbag Industries</a>, <a href="http://unstoppablerobotninja.com/" class="external">Unstoppable Robot Ninja</a>), enlightened us in the ways of making a stretchy layout where all components &#8212; including static images, images generated from Flash (<a href="http://novemberborn.net/sifr3" class="external">sIFR</a>), and even embedded objects &#8212; resize with the browser.</p>

<p><b>Dan Cederholm</b> (<a href="http://simplebits.com/" class="external">SimpleBits</a>) reviewed how to apply grid-based design to stretchy layouts by using ems to specify size, and how to constrain the layout to the size of the browser window so that horizontal scrollbars don't appear (set the layout container's width to 100%).</p>

<p><b>Joshua Porter</b> (<a href="http://bokardo.com/" class="external">Bokardo Design</a>) discussed the importance of maintaining a craftsman's integrity when approaching web design and development work, and how that can have a positive effect on collaborations.</p>

<p>Our own <b>Scott Jehl</b> capped the night and presented a technique that we're refining to help us better apply progressive enhancement to our code.  It's a script called testUserDevice.js, and you can learn about how it works and download it from our lab article, <a href="/lab/delivering_the_right_experience_to_the_right_device/">Delivering the right experience to the right device</a> | <a href="/examples/testUserDevice/M&SS_slides_fg.pdf" class="external">Download Slides</a>  (1mb).</p>

<p>We were impressed with the knowledge, inspired by the enthusiasm, and energized by the positive feedback and new connections that we made.  Thanks to all who attended and shared their ninja secrets. And special thanks to the folks at <a href="http://www.freshview.com/" class="external">Freshview</a> for the pizza and beer.</p>

<p><a href="/examples/testUserDevice/M&SS_slides_fg.pdf" class="external"><img src="http://72.47.209.59/images/presoScreen.jpg" width="400" height="300" /></a></p>

</description>
      <dc:subject>progressive enhancement, ui design, web standards</dc:subject>
      <dc:date>2008-03-14T16:44:00-05:00</dc:date>
    </item>

    <item>
      <title>Delivering the right experience to the right device</title>
      <link>http://www.filamentgroup.com/lab/delivering_the_right_experience_to_the_right_device/</link>
      <guid>http://www.filamentgroup.com/lab/delivering_the_right_experience_to_the_right_device/#When:18:59:00Z</guid>
      <description><p>Inspired by Jeremy Keith's concept of <a href="http://domscripting.com/blog/display/41" class="external">Hijax</a>, we've adopted the practice of coding with progressive enhancement in mind to ensure optimal accessibility, compatibility with multiple browsers and platforms, and ease of maintenance for each site or web application. But how do you do that when so many browsers only partially support javascript and CSS techniques?  We met the challenge by developing a script to test the browser's ability to handle modern coding techniques, and ensure a usable experience for all.</p>
<h2>Why is progressive enhancement important?</h2>
<div class="example_right">
<a href="/examples/testUserDevice/M&SS_slides_fg.pdf" class="external">
<img src="http://72.47.209.59/images/presoScreen_sml.jpg" width="200" height="150" /></a>
<p>We presented this technique at the Markup &amp; Style Society on March 13, 2008. <a href="/examples/testUserDevice/M&SS_slides_fg.pdf" class="external">Download Slides</a> (1mb PDF)</p>
</div>
<p>In a word: accessibility.  Most of the web sites and applications we design and code are intended for a wide audience, be it a targeted segment of the general public, the client's own organization, or both, and our intention is to provide a usable experience to everyone.  In most cases that means developing front-end code that supports the required functionality and design elements on a variety of browsers and platforms, some of which are standards-compliant and render complex Javascript animations and visuals flawlessly, and some of which render those same modern script and style techniques poorly (and that's putting it kindly).  The ongoing challenge is to 
develop code that provides the richest experience to the broadest audience, and at the very least a clean and usable experience to those using non-compliant browsers.</p>

<p>Coding for progressive enhancement allows us to meet that challenge with a single code base.  (In some exceptional cases it may make sense to fork the code to meet the functional requirements of different devices, but most often we find that creating and maintaining multiple code bases is unnecessary when the it's written with progressive enhancement in mind.)</p>

<p>We start with plain, structured, semantic HTML and layer on functionality to provide an enhanced experience to capable browsers. The end result of this approach is:</p>

<ul>
<li><strong>Modern, standard-complaint browsers</strong> render a rich, interactive experience including accurate rendering of the visual designs with multi-column layouts, background colors and images, and Javascript-based interaction and animation.</li>

<li><strong>Depreciated, mobile or text-only browsers</strong> render clean, fully usable and well-formatted pages with minimal style and without interaction effects.  As an added benefit, this approach also makes it possible to provide a clean, well-structured experience for users accessing the sites from mobile devices, screen readers and other accessibility support aids.</li>
</ul>

<h2>How do you know if a browser supports advanced CSS and Javascript?</h2>
<p>There are a few well-known ways to prevent non-compliant browsers from rendering particular styles, like using <a href="http://www.ericmeyeroncss.com/bonus/trick-hide.html" class="external">tricky reference syntax</a>, or doing <a href="http://www.quirksmode.org/js/support.html" class="external">object detection</a> to prevent a browser from executing a specific function.  But we found ourselves running into cases of partial support, where a few browsers would support some but not all of the latest CSS or DOM specification correctly.</p>

<p>Rather than complicate our markup and scripts with numerous exceptions or resort to the <a href="http://www.quirksmode.org/js/support.html" class="external">less reliable method</a> of browser version sniffing, we decided to take matters into our own hands and created a comprehensive test to determine if a browser is capable of doing what we want it to do: floated column layouts, interactive widgets, animation effects, and so on.  If the browser passes, we apply all of our styles and complex interactions; if the browser fails, it skips the fancy CSS and Javascript and renders a basic, clean &#8212; and fully usable &#8212; version of the site.</p>

<h2>Our solution: use javascript to detect CSS</h2>
<p>We can figure out which browsers support the richest experience by a process of elimination. To begin, if javascript is disabled, the test won't run and the page loads with basic HTML and styles.  But if javascript is enabled, we can run the test and apply styles using CSS, and then test their display accuracy using common javascript equivalents. For example, we can set the width on an element with css and then check its width using offsetWidth. Or we could float two elements and then evaluate their offsetTop values for equality.</p>

<h2>What we test for</h2>
<p>Immediately after the body element is ready, <a href="http://72.47.209.59/examples/testUserDevice/testUserDevice_UNPACKED.js" class="external">testUserDevice.js</a> evaluates a device's ability to handle the following css properties properly:</p>
<ul>
	<li><strong>Box model:</strong> make sure the width and padding of a div add up properly using offsetWidth</li>
	<li><strong>Positioning:</strong> position a div and check its positioning using offsetTop and offsetLeft</li>
	<li><strong>Float:</strong> float 2 divs next to each other and evaluate their offsetTop values for equality</li>
	<li><strong>Clear:</strong> test to make sure a list item will clear beneath a preceding floated list item</li>
	<li><strong>Overflow:</strong> wrap a tall div with a shorter div with overflow set to 'auto', and test its offsetHeight</li>
	<li><strong>Line-height (including unitless):</strong> test for proper handling of line-height using offsetHeight, primarily to rule out Firefox 1.0</li>
</ul>
<p>It also tests the following javascript capabilities:</p>
<ul>
	<li>Basic DOM traversal</li>
	<li>Window Resize Detection</li>
	<li>Printing</li>
	<li>A little additional object detection to rule out certain browsers that have known CSS bugs that cannot be easily tested for, like faulty background-image rendering in Netscape 7.0</li>
</ul>

<p>If the browser fails any of the above tests, the script will return false and the browser will render the clean, well-structured markup on the page with few styles and no interaction effects &#8212; users will still have access to all of the content, but will just experience a plainer version of it.</p>

<p>Generally, these tests are set up to target known issues of devices we do not intend to support, but they are performed in a way that is unbiased to the device being tested and will work with future devices as well.</p>

<h2>What happens when a device passes?</h2>
<p>Upon successful completion of the test, advanced styles and interaction effects are applied to the basic markup through the DOM:</p>
<ul>
        <li>Any script passed in as an argument will be forwarded along to execute on DOM ready. (The test script contains a library-independent DOM-ready function but it will use jQuery's instead if it is available.)</li>
	<li>A class of "enhanced" is assigned to the body element to be used for optional CSS scoping (such as: <code>body.enhanced {background: red;}</code>)</li>
	<li>Any links to alternate stylesheets that have a class of "enhanced" will be enabled. In order for this to work, <a href="http://www.w3.org/TR/html401/present/styles.html#h-14.3.2" class="external">each alternate stylesheet must have a title attribute</a>.</li>
	<li>Any links to stylesheets that have a class of "basicNoCascade" will be disabled. This is optional depending on whether your enhanced stylesheets cascade or conflict with your basic sheets.</li>
        <li>A cookie is set (enhanced = true) to notify the script on future page loads that the browser has already passed and can receive an enhanced experience.</li>
</ul>
<p>Users with successful browsers will experience the design as intended, with the complete and intact visual design and complex interactivity.</p>

<h2>Usage</h2>
<p>To apply <a href="http://72.47.209.59/examples/testUserDevice/testUserDevice_UNPACKED.js" title="testUserDevice.js">testUserDevice.js</a>, simply grab the file linked below and link to it in the head of your html file. Enclose any DOM-related script executions within the following function:</p>
<pre>
 enhancedDomReady(function(){
  <span class="comment">//put scripts here to be executed after the 
  //dom is ready and the browser has passed the test</span>
 });
</pre>

<h2><a href="http://72.47.209.59/examples/testUserDevice/testUserDevice_UNPACKED.js" title="testUserDevice.js">Download Script: testUserDevice.js</a></h2>
<h2>Results Matrix</h2>
<p>By running this test, we're able to ensure that all browsers render a usable experience to our entire audience &#8212; the only difference is that browsers that fail render well-structured HTML with minimal styling and no interaction effects, while browsers that pass render the enhanced experience with rich visuals and fully interactive elements. The following tables represent the division of browsers:</p>


<table>
  <tr>
    <th>Platform</th>
    <th>Browser</th>
    <th>Version</th>
    <th>Pass/Fail</th>
  </tr>
  <tr>
    <td>Linux Fedora Core 4</td>
    <td>Firefox</td>
    <td>1.5</td>
    <td>Pass</td>
  </tr>
  <tr>
    <td>Linux Fedora Core 4</td>
    <td>Firefox</td>
    <td>2.0</td>
    <td>Pass</td>
  </tr>
  <tr>
    <td class="fail">Linux Fedora Core 4</td>
    <td class="fail">Konqueror</td>
    <td class="fail">3.4</td>
    <td class="fail">Fail</td>
  </tr>
  <tr>
    <td>Linux Fedora Core 4</td>
    <td>Mozilla</td>
    <td>1.7</td>
    <td>Pass</td>
  </tr>
  <tr>
    <td class="fail">Mac OSX 10.2</td>
    <td class="fail">Explorer </td>
    <td class="fail">5.1</td>
    <td class="fail">Fail</td>
  </tr>
  <tr>
    <td>Mac OSX 10.3</td>
    <td>Camino</td>
    <td>1.0</td>
    <td>Pass</td>
  </tr>
  <tr>
    <td class="fail">Mac OSX 10.3</td>
    <td class="fail">Explorer </td>
    <td class="fail">5.2</td>
    <td class="fail">Fail</td>
  </tr>
  <tr>
    <td>Mac OSX 10.3</td>
    <td>Firefox</td>
    <td>1.5</td>
    <td>Pass</td>
  </tr>
  <tr>
    <td>Mac OSX 10.3</td>
    <td>Firefox</td>
    <td>2.0</td>
    <td>Pass</td>
  </tr>
  <tr>
    <td class="fail">Mac OSX 10.3</td>
    <td class="fail">Mozilla</td>
    <td class="fail">1.6</td>
    <td class="fail">Fail</td>
  </tr>
  <tr>
    <td class="fail">Mac OSX 10.3</td>
    <td class="fail">Mozilla </td>
    <td class="fail">1.7</td>
    <td class="fail">Fail</td>
  </tr>
  <tr>
    <td class="fail">Mac OSX 10.3</td>
    <td class="fail">Netscape</td>
    <td class="fail">7.2</td>
    <td class="fail">Fail</td>
  </tr>
  <tr>
    <td>Mac OSX 10.3</td>
    <td>Opera</td>
    <td>8.5</td>
    <td>Pass</td>
  </tr>
  <tr>
    <td>Mac OSX 10.3</td>
    <td>Opera</td>
    <td>9.0</td>
    <td>Pass</td>
  </tr>
  <tr>
    <td>Mac OSX 10.3</td>
    <td>Safari</td>
    <td>1.2</td>
    <td>Pass</td>
  </tr>
  <tr>
    <td>Mac OSX 10.3</td>
    <td>Safari</td>
    <td>1.3</td>
    <td>Pass</td>
  </tr>
  <tr>
    <td>Mac OSX 10.4</td>
    <td>Camino</td>
    <td>1.0</td>
    <td>Pass</td>
  </tr>
  <tr>
    <td class="fail">Mac OSX 10.2</td>
    <td class="fail">Explorer </td>
    <td class="fail">5.1</td>
    <td class="fail">Fail</td>
  </tr>
  <tr>
    <td class="fail">Mac OSX 10.2</td>
    <td class="fail">Explorer </td>
    <td class="fail">5.2</td>
    <td class="fail">Fail</td>
  </tr>
  <tr>
    <td>Mac OSX 10.4</td>
    <td>Firefox </td>
    <td>1.5</td>
    <td>Pass</td>
  </tr>
  <tr>
    <td>Mac OSX 10.4</td>
    <td>Firefox </td>
    <td>2.0</td>
    <td>Pass</td>
  </tr>
  <tr>
    <td class="fail">Mac OSX 10.4</td>
    <td class="fail">Mozilla </td>
    <td class="fail">1.6</td>
    <td class="fail">Fail</td>
  </tr>
  <tr>
    <td class="fail">Mac OSX 10.4</td>
    <td class="fail">Mozilla </td>
    <td class="fail">1.7</td>
    <td class="fail">Fail</td>
  </tr>
  <tr>
    <td class="fail">Mac OSX 10.4</td>
    <td class="fail"> Netscape  </td>
    <td class="fail">7.2</td>
    <td class="fail">Fail</td>
  </tr>
  <tr>
    <td>Mac OSX 10.4</td>
    <td> Opera </td>
    <td>8.5</td>
    <td>Pass</td>
  </tr>
  <tr>
    <td>Mac OSX 10.4</td>
    <td> Opera </td>
    <td>9.0</td>
    <td>Pass</td>
  </tr>
  <tr>
    <td>Mac OSX 10.4</td>
    <td>Safari</td>
    <td>2.0</td>
    <td>Pass</td>
  </tr>
  <tr>
    <td>Windows 2000 Professional</td>
    <td>AOL </td>
    <td>9.0</td>
    <td>Pass</td>
  </tr>
  <tr>
    <td class="fail">Windows 2000 Professional</td>
    <td class="fail">Explorer</td>
    <td class="fail">5.0</td>
    <td class="fail">Fail</td>
  </tr>
  <tr>
    <td class="fail">Windows 2000 Professional</td>
    <td class="fail">Explorer</td>
    <td class="fail">5.5</td>
    <td class="fail">Fail</td>
  </tr>
  <tr>
    <td>Windows 2000 Professional</td>
    <td>Explorer</td>
    <td>6.0</td>
    <td>Pass</td>
  </tr>
  <tr>
    <td>Windows 2000 Professional</td>
    <td>Firefox</td>
    <td>1.5</td>
    <td>Pass</td>
  </tr>
  <tr>
    <td>Windows 2000 Professional</td>
    <td>Firefox</td>
    <td>2.0</td>
    <td>Pass</td>
  </tr>
  <tr>
    <td class="fail">Windows 2000 Professional</td>
    <td class="fail">Mozilla</td>
    <td class="fail">1.6</td>
    <td class="fail">Fail</td>
  </tr>
  <tr>
    <td>Windows 2000 Professional</td>
    <td>Mozilla</td>
    <td>1.7</td>
    <td>Pass</td>
  </tr>
  <tr>
    <td class="fail">Windows 2000 Professional</td>
    <td class="fail">Netscape</td>
    <td class="fail">4.7</td>
    <td class="fail">Fail</td>
  </tr>
  <tr>
    <td class="fail">Windows 2000 Professional</td>
    <td class="fail">Netscape</td>
    <td class="fail">6.2</td>
    <td class="fail">Fail</td>
  </tr>
  <tr>
    <td class="fail">Windows 2000 Professional</td>
    <td class="fail">Netscape</td>
    <td class="fail">7.2</td>
    <td class="fail">Fail</td>
  </tr>
  <tr>
    <td>Windows 2000 Professional</td>
    <td>Opera</td>
    <td>8.5</td>
    <td>Pass</td>
  </tr>
  <tr>
    <td>Windows 2000 Professional</td>
    <td>Opera</td>
    <td>9.0</td>
    <td>Pass</td>
  </tr>
  <tr>
    <td class="fail">Windows 98</td>
    <td class="fail">Explorer</td>
    <td class="fail">4.0</td>
    <td class="fail">Fail</td>
  </tr>
  <tr>
    <td>Windows Vista</td>
    <td>Explorer</td>
    <td>7.0</td>
    <td>Pass</td>
  </tr>
  <tr>
    <td>Windows Vista</td>
    <td>Opera</td>
    <td>9.0</td>
    <td>Pass</td>
  </tr>
  <tr>
    <td class="fail">Windows XP</td>
    <td class="fail">Explorer</td>
    <td class="fail">3.0</td>
    <td class="fail">Fail</td>
  </tr>
  <tr>
    <td class="fail">Windows XP</td>
    <td class="fail">Explorer</td>
    <td class="fail">4.0</td>
    <td class="fail">Fail</td>
  </tr>
  <tr>
    <td class="fail">Windows XP</td>
    <td class="fail">Explorer</td>
    <td class="fail">5.0</td>
    <td class="fail">Fail</td>
  </tr>
  <tr>
    <td class="fail">Windows XP</td>
    <td class="fail">Explorer</td>
    <td class="fail">5.5</td>
    <td class="fail">Fail</td>
  </tr>
  <tr>
    <td>Windows XP</td>
    <td>Explorer</td>
    <td>6.0</td>
    <td>Pass</td>
  </tr>
  <tr>
    <td>Windows XP</td>
    <td>Explorer</td>
    <td>7.0</td>
    <td>Pass</td>
  </tr>
  <tr>
    <td class="fail">Windows XP</td>
    <td class="fail">Netscape</td>
    <td class="fail">4.0</td>
    <td class="fail">Fail</td>
  </tr>
  <tr>
    <td class="fail">Windows XP</td>
    <td class="fail">Netscape</td>
    <td class="fail">6.2</td>
    <td class="fail">Fail</td>
  </tr>
  <tr>
    <td class="fail">Windows XP</td>
    <td class="fail">Netscape</td>
    <td class="fail">7.0</td>
    <td class="fail">Fail</td>
  </tr>
  <tr>
    <td class="fail">Windows XP</td>
    <td class="fail">Netscape</td>
    <td class="fail">7.1</td>
    <td class="fail">Fail</td>
  </tr>
  <tr>
    <td class="fail">Windows XP</td>
    <td class="fail">Netscape</td>
    <td class="fail">7.2</td>
    <td class="fail">Fail</td>
  </tr>
  <tr>
    <td>Windows XP</td>
    <td>Netscape</td>
    <td>8.0</td>
    <td>Pass</td>
  </tr>
  <tr>
    <td class="fail">Windows XP</td>
    <td class="fail">Opera</td>
    <td class="fail">7.5</td>
    <td class="fail">Fail</td>
  </tr>
  <tr>
    <td>Windows XP</td>
    <td>Opera</td>
    <td>8.0</td>
    <td>Pass</td>
  </tr>
  <tr>
    <td>Windows XP</td>
    <td>Opera</td>
    <td>8.5</td>
    <td>Pass</td>
  </tr>
  <tr>
    <td>Windows XP</td>
    <td>Opera</td>
    <td>9.0</td>
    <td>Pass</td>
  </tr>
  <tr>
    <td>Windows XP</td>
    <td>Firefox</td>
    <td>1.0</td>
    <td>Pass</td>
  </tr>
  <tr>
    <td>Windows XP</td>
    <td>Firefox</td>
    <td>1.5</td>
    <td>Pass</td>
  </tr>
  <tr>
    <td>Windows XP</td>
    <td>Firefox</td>
    <td>2.0</td>
    <td>Pass</td>
  </tr>
  <tr>
    <td class="fail">Windows XP</td>
    <td class="fail">Mozilla</td>
    <td class="fail">1.6</td>
    <td class="fail">Fail</td>
  </tr>
  <tr>
    <td>Windows XP</td>
    <td>Mozilla</td>
    <td>1.7</td>
    <td>Pass</td>
  </tr>
</table></description>
      <dc:subject>accessibility, css, javascript, jQuery, progressive enhancement, usability</dc:subject>
      <dc:date>2008-03-07T18:59:00-05:00</dc:date>
    </item>

    <item>
      <title>Automated image preloading for a snappy UI</title>
      <link>http://www.filamentgroup.com/lab/automated_image_preloading_for_a_snappy_ui/</link>
      <guid>http://www.filamentgroup.com/lab/automated_image_preloading_for_a_snappy_ui/#When:18:56:00Z</guid>
      <description><p>This article describes a solution we've developed that automates the age-old task of preloading images in web applications. It uses javascript and is packaged as a jQuery plugin, but the concept could easily be ported to other libraries or plain old Javascript as well.</p><h2>Why is preloading important?</h2>
<p>Web applications tend to involve a multitude of background images for elements and states that aren't in view when the page loads. In traditional web apps these images are used for rollover states for links and buttons, but Ajax applications have expanded the list to include images for inline messaging, tooltips, toggled content, overlay panels, and even entire pages of content that could potentially wind up in an interface. In order to create a snappy desktop-like experience on the web, images must be preloaded so that there is no blinking or fragmented loading.  We found that our current options for preloading images were both insufficient and time-consuming, and it was clear that we needed to find a new approach.</p>

<h2>How preloading is usually done</h2>
<p>Developers tend to employ a couple of common practices:</p>
<ul>
<li><a href="http://www.alistapart.com/articles/sprites" title="CSS sprites" class="external"><strong>CSS Sprites:</strong></a> Combine all states of an image (default, rollover, active) into a single image file and use CSS to position and crop it into place. While this solves the problem of preloading image states that aren't visible when the page first loads, it doesn't address how to preload background images that appear when new content is loaded via Ajax.</li>

<li><strong>Using JavaScript to create image objects from filenames:</strong> Create an array of background-image filenames that need preloading, then loop through that array to create an image object for each image file.  This ensures that images are cached and ready for later use, but often the number of images required in a complex Ajax application can be up to 50, 100, or more. On top of that, inevitable design changes throughout a development process mean constantly updating and adding file paths, which would lead most developers to simply not do it.</li>
</ul>

<p>A typical array of images for preloading with JavaScript:</p>
<pre>
var imagesToLoad = 
  [
     'image1.gif', 
     'image2.gif', 
     'image3.gif', 
     'etc...'
  ];
</pre>

<h2>How is this script different?</h2>
<p>Our script parses through linked and imported stylesheets and creates an array of all the image urls they contain.  Then it loops through the array of urls and creates an image object for each one so they'll be cached and ready for later use. <em>Sound familiar?</em> That's because it's nearly the same as the traditional JavaScript approach, but with the major added advantage of automation. Using this script means we only have to worry about specifying background images and states in our CSS files, and the script takes care of the rest.</p>

<h3>Take it straight from the source:</h3>
<pre>
/*
 * --------------------------------------------------------------------
 * jQuery-Plugin "preloadCssImages"
 * by Scott Jehl, scott@filamentgroup.com
 * http://www.filamentgroup.com
 * reference article: http://www.filamentgroup.com/lab/automated_image_preloading/
 * demo page: http://www.filamentgroup.com/examples/preloadImages/
 * 
 * Copyright (c) 2008 Filament Group, Inc
 * Licensed under GPL (http://www.opensource.org/licenses/gpl-license.php)
 *
 * Version: 1.0, 31.05.2007
 * Changelog:
 * 	02.20.2008 initial Version 1.0
 * --------------------------------------------------------------------
 */
$.preloadCssImages = function(settings){
	//overrideable defaults
	settings = jQuery.extend({
		 imgDir: 'images'
	}, settings);

	//dump all the css rules into one string
	var sheets = document.styleSheets;
	var cssPile = '';
	for(var i = 0; i&lt;sheets.length; i++){
		var thisSheetRules = document.styleSheets[ i ].cssRules;
		for(var j = 0; j&lt;thisSheetRules.length; j++){
			cssPile+= thisSheetRules[ j ].cssText;
		}
	}
	//parse string for image urls and load them into the DOM
	var allImgs = [];//new array for all the image urls  
	var imgUrls = cssPile.match(/[^\/]+\.(gif|jpg|jpeg|png)/g);//reg ex to get a string of between a "/" and a ".filename"
	if(imgUrls != null && imgUrls.length&gt;0 && imgUrls != ''){//loop array
		var arr = jQuery.makeArray(imgUrls);//create array from regex obj	 
		$(arr).each(function(k){
			allImgs[ k ] = new Image(); //new img obj
			allImgs[ k ].src = settings.imgDir +'/'+ this;	
		});
	}
	return allImgs;
}
</pre>

<h3>How do I use it?</h3>
<p>Paste the code above into your JavaScript file and run <strong><code>$.preloadCssImages()</code></strong> when the DOM is ready. Don't forget that you'll also need to reference the <a href="http://jquery.com/" class="external" title="jQuery library">jQuery javascript library</a> in your page. By default, the script assumes a root directory called 'images'. This default directory can be overridden by passing a different imgDir value to the settings object like so: <code>$.preloadCssImages({ imgDir: 'myImagesDirectory' });</code></p>


<h3>Time for a demo</h3>
<p>The example below uses our script to parse through a <a href="http://72.47.209.59/examples/preloadImages/demoStyles.css" class="external">sample stylesheet</a> which we've linked to the page. The sample stylesheet has background image rules for elements that don't actually exist on the page, so the images specified are not currently loaded. Clicking the button below will load them into the DOM. For example purposes, we've written the loaded images into the page as well.</p>

<iframe src="/examples/preloadImages/" style="height:8em"></iframe>

<h2>Download <a href="/examples/preloadImages/scripts/preloadCssImages.jQuery.js" class="external">preloadCssImages.jQuery.js</a></h2>
<p>This script is a jQuery plugin, meaning is is dependant on the incredible <a href="http://www.jquery.com" class="external">jQuery javascript library</a>. If you feel particularly adventurous, this script could be easily ported to another library or written in plain old JavaScript as well. Feel free to grab the script and try it for yourself. We're always looking for ways to improve our scripts, so if you encounter any issues or have any questions or suggestions please <a href="#comment_form">leave a comment</a> below.</p>

<h2>Future plans for preloadCssImages.jQuery.js</h2>
<p>Currently this plugin assumes that all images are held in a single directory. Down the road, we would like to extend the script so that image paths are worked out in relation to the location of the CSS file, enabling images to be loaded from different directories on a server.</p>

</description>
      <dc:subject>css, javascript, jQuery</dc:subject>
      <dc:date>2008-03-06T18:56:00-05:00</dc:date>
    </item>

    <item>
      <title>Creating accessible charts using canvas and jQuery</title>
      <link>http://www.filamentgroup.com/lab/creating_accessible_charts_using_canvas_and_jquery/</link>
      <guid>http://www.filamentgroup.com/lab/creating_accessible_charts_using_canvas_and_jquery/#When:19:04:00Z</guid>
      <description><p>Data visualization in HTML has long been tricky to achieve. Past solutions have involved non-standard plugins, proprietary behavior, and static images. But this has changed with the recent growth in support for the new HTML Canvas element, which provides a native drawing API that can be addressed with simple Javascript. This article is a proof of concept for visualizing HTML table data with the canvas element.</p>

<p>The idea of visualizing HTML table data has been a hot topic lately. The first mention of it that we have seen was Christian Heilmann's <a href="http://yuiblog.com/blog/2008/01/17/tables-and-charts/" class="external">YUI blog entry</a>, which provides a clean solution for the problem using the Yahoo library. The idea is a good one: having the data on the page in a table allows it to be accessible, and the chart can be shown as a visual enhancement. Our attempt at solving the problem uses jQuery and provides several types of graphs, such as Pie, Line, Area, and Bar.</p>

<h2>So how does it work?</h2>
<h3>First the markup:</h3>
<p>We start with a regular old HTML data table like the one shown below:</p>

<pre>
&lt;table id=&quot;dataTable&quot; summary=&quot;Member Data from 2000 to 2006&quot;&gt;
	&lt;caption&gt;Member Data from 2000 to 2006&lt;/caption&gt;
	&lt;thead&gt;
		&lt;tr&gt;
			&lt;td&gt;&lt;/td&gt;
			&lt;th id=&quot;2000&quot;&gt;2000&lt;/th&gt;
			&lt;th id=&quot;2001&quot;&gt;2001&lt;/th&gt;
			&lt;th id=&quot;2002&quot;&gt;2002&lt;/th&gt;
			&lt;th id=&quot;2003&quot;&gt;2003&lt;/th&gt;
			&lt;th id=&quot;2004&quot;&gt;2004&lt;/th&gt;
			&lt;th id=&quot;2005&quot;&gt;2005&lt;/th&gt;
			&lt;th id=&quot;2006&quot;&gt;2006&lt;/th&gt;
		&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tfoot&gt;
		
	&lt;/tfoot&gt;
	&lt;tbody&gt;
		&lt;tr&gt;
			&lt;th headers=&quot;members&quot;&gt;Mary&lt;/th&gt;
			&lt;td headers=&quot;2000&quot;&gt;150&lt;/td&gt;
			&lt;td headers=&quot;2001&quot;&gt;160&lt;/td&gt;
			&lt;td headers=&quot;2002&quot;&gt;40&lt;/td&gt;
			&lt;td headers=&quot;2003&quot;&gt;120&lt;/td&gt;
			&lt;td headers=&quot;2004&quot;&gt;30&lt;/td&gt;
			&lt;td headers=&quot;2005&quot;&gt;70&lt;/td&gt;
			&lt;td headers=&quot;2006&quot;&gt;70&lt;/td&gt;
		&lt;/tr&gt;
		&lt;tr&gt;
			&lt;th headers=&quot;members&quot;&gt;Tom&lt;/th&gt;
			&lt;td headers=&quot;2000&quot;&gt;3&lt;/td&gt;
			&lt;td headers=&quot;2001&quot;&gt;40&lt;/td&gt;
			&lt;td headers=&quot;2002&quot;&gt;30&lt;/td&gt;
			&lt;td headers=&quot;2003&quot;&gt;45&lt;/td&gt;
			&lt;td headers=&quot;2004&quot;&gt;35&lt;/td&gt;
			&lt;td headers=&quot;2005&quot;&gt;49&lt;/td&gt;
			&lt;td headers=&quot;2006&quot;&gt;70&lt;/td&gt;
		&lt;/tr&gt;
		&lt;tr&gt;
			&lt;th headers=&quot;members&quot;&gt;Brad&lt;/th&gt;
			&lt;td headers=&quot;2000&quot;&gt;10&lt;/td&gt;
			&lt;td headers=&quot;2001&quot;&gt;00&lt;/td&gt;
			&lt;td headers=&quot;2002&quot;&gt;10&lt;/td&gt;
			&lt;td headers=&quot;2003&quot;&gt;85&lt;/td&gt;
			&lt;td headers=&quot;2004&quot;&gt;25&lt;/td&gt;
			&lt;td headers=&quot;2005&quot;&gt;79&lt;/td&gt;
			&lt;td headers=&quot;2006&quot;&gt;70&lt;/td&gt;
		&lt;/tr&gt;
		&lt;tr&gt;
			&lt;th headers=&quot;members&quot;&gt;Kate&lt;/th&gt;
			&lt;td headers=&quot;2000&quot;&gt;40&lt;/td&gt;
			&lt;td headers=&quot;2001&quot;&gt;80&lt;/td&gt;
			&lt;td headers=&quot;2002&quot;&gt;90&lt;/td&gt;
			&lt;td headers=&quot;2003&quot;&gt;25&lt;/td&gt;
			&lt;td headers=&quot;2004&quot;&gt;15&lt;/td&gt;
			&lt;td headers=&quot;2005&quot;&gt;119&lt;/td&gt;
			&lt;td headers=&quot;2006&quot;&gt;200&lt;/td&gt;
		&lt;/tr&gt;		
	&lt;/tbody&gt;
&lt;/table&gt;
</pre>

<p>For the charts, we place Canvas elements in the markup with class names that are descriptive of their chart type and source.</p>

<pre>
&lt;canvas id=&quot;chart1&quot; class=&quot;fgCharting_src-dataTable_type-pie&quot;&gt;&lt;/canvas&gt;
</pre>

<p>As you can see, we've created somewhat of a custom syntax in our class names. The syntax begins with "fgCharting" and is followed by key/value pairs which are separated using underscores and matched using dashes. Using this syntax, the above class name tells our script that the source ("src") is a table with an ID of "dataTable", and our chart type ("type") is Pie. <em><strong>Note:</strong> There are many other ways this could be handled, and including the chart settings in the markup may not be the best separation of markup and behavior, but for the purposes of this example it seems to work well.</em></p>

<h3>And now for the Scripting:</h3>
<p>Once we have jQuery and our charting library attached, we can convert our canvas elements into charts with the following line of javascript:</p>

<pre>
$.fgCharting();
</pre>

<h2>A live demo</h2>
<p>The following demo uses the markup and scripting mentioned above. For example purposes, the following table is editable, so if you change the values the Pie will redraw in real time!</p>

<iframe src="/examples/charting/" name="example1" style="height: 78em;"></iframe>

<h2>Cool! What about different charts?</h2>
<p>We've developed several other types that can be specified using our library; these are:</p>
<ul>
<li>line</li>
<li>filledLine</li>
<li>additiveLine</li>
<li>additiveFilledLine</li>
<li>pie</li>
<li>bar</li>
<li>additiveBar</li>
</ul>

<p>Since these charts involve different groupings of data, our script organizes the table data in multiple ways. For example, Pie charts need the total table sum, each member's individual total, and each member's name. However, line, bar, and area (filled) charts need to know each member's value at every point on the X scale. Because of these differences, our script collects an object of the following properties and passes it along to the chart builder:</p>

<ul>
<li><strong>members:</strong> member names</li>
<li><strong>allData:</strong> array of every value in the table</li>
<li><strong>dataSum:</strong> sum of all members in the allData array</li>
<li><strong>topValue:</strong> highest value in the table</li>
<li><strong>memberTotals:</strong> array of totals for each member</li>
<li><strong>yTotals:</strong> array of y-axis totals</li>
<li><strong>topYtotal:</strong> highest value in the yTotals array</li>
<li><strong>xLabels:</strong> labels for the X axis of line, bar, and area charts</li>
<li><strong>yLabels:</strong> labels for the Y axis of line, bar, and area charts</li>
<li><strong>yLabelsAdditive:</strong> y labels for the Y axis of additive charts</li>
</ul>

<h2>More chart types: <em>(data table hidden visually)</em></h2>
<p>The following example shows some more examples of charts that our library can generate.</p>
<iframe src="/examples/charting/index2.php" name="example2" style="height: 96em;"></iframe>

<h2>Grab our script</h2>
<p>You can download our charting library source here: <a href="/examples/charting/scripts/fgCharting.jQuery.js" class="external">fgCharting.jQuery.js</a></p>
<p><strong>Note:</strong> Be sure to download the <a href="http://www.jquery.com" class="external">jQuery</a> javascript library as well, as our charting library depends on it!</p>

<h2>Browser support</h2>
<p>Canvas is not natively supported in Internet Explorer, but lucky for us, the smart folks at Google have made a patch that uses purely javascript to port Canvas support to IE! We've included their library for our examples and it can be downloaded here: <a href="http://excanvas.sourceforge.net/" class="external">ExplorerCanvas</a>.</p>

<h2>Looking ahead</h2>
<p>There are many charting libraries out there today that use Canvas and many of them go well beyond what we've demonstrated above. We feel that the major advantage of this technique is that the data is accessible to users on any device. Looking ahead, we hope to develop a library that is much more focused on retrieving the table data in a way that is similar to accessing a database with SQL statements. This library would then allow its data to be sent to more advanced charting libraries such as <a href="http://code.google.com/p/flot/" class="external">Flot</a>, to create truly dynamic data visualizations.</p>





</description>
      <dc:subject>accessibility, canvas, javascript, jQuery, progressive enhancement, web standards</dc:subject>
      <dc:date>2008-03-05T19:04:00-05:00</dc:date>
    </item>

    <item>
      <title>Retaining scalable interfaces with pixel&#45;to&#45;em conversion</title>
      <link>http://www.filamentgroup.com/lab/retaining_scalable_interfaces_with_pixel_to_em_conversion/</link>
      <guid>http://www.filamentgroup.com/lab/retaining_scalable_interfaces_with_pixel_to_em_conversion/#When:19:02:00Z</guid>
      <description><p>This script was developed to allow for quick conversion between pixel and em values so that page scalability can be retained throughout the course of a web application. It appends a method to the native string object and leverages the jQuery library for its rapid selectors.</p>
<h2>Why Ems, Anyway?</h2>
<p>In CSS layouts, ems are often used in place of pixels to allow elements and text to scale in unison. Although pixels tend to be easier to use and more precise, many browsers such as Internet Explorer can not scale text that is set in pixels. By using ems for not only our text, but also the heights and widths of structural elements, we can allow parts of the page layout to scale in proportion to the text size.</p>

<h2>How do they work?</h2>
<p>In brief, an em is a relative unit that is equivalent to the height of a font. Since most browsers' default font size is 16px, we can assume that 1em is equal to 16px; meaning that 12px is equal to 0.75em, and 10px type is equal to 0.625em. As you can see, it can be quite tedious to calculate em values this way, and luckily a <a href="http://clagnut.com/blog/348/" class="external">method was developed by clagnut</a> to alleviate the problem. By simply setting the body element's font size to 62.5%, the value of 1em becomes 10px. This allows for nice and easy calculations to ems by simply dividing a pixel value by 10.</p>

<p>The inconveniences of using ems do not stop there however, since the value of 1em can vary depending on parent/child relationships in the DOM. For every element on the page, the value of 1em is calculated based on the font size of its parent element. This means that while a paragraph may have a font size of 1.2em and appear to be 12px tall, all of its children will exist in a world where 1em is equal to 12px instead of 10. This sounds like a similar situation to where we started.</p>

<h2>Where Ems are Often Abandoned</h2> 
<p>As confusing as managing an em-based stylesheet might get though, it usually doesn't cause any major setbacks to web developers. We find that the problems more often occur when elements are inserted or modified with javascript. During animation effects or modifications to the DOM, many javascript libraries style elements using pixels to avoid the possibility of conflicts. While pixels are often desired and are a good default, we usually want our modifications to fit within a scalable interface. For this reason, we've come up with a method that converts pixel values to ems on the fly, and always calculates within the scope it is given.</p>

<h2>So how does it work?</h2>
<p>When called, pxToEm converts a given pixel value to ems. By default, it uses the body's font size for scope, but a scope property can be passed to handle conversions that are relative to another element's font size.</p>

<h3>Sample Output:</h3>
<pre>
<code>
var pixelValue = 256; 
var emValue = pixelValue.pxToEm(); 
==> returns '25.6em'
</code>
</pre>

<p>The sample above may look like a simple division of 10, but the script actually checks the font size of the body before calculating so it will work in many environments. To demonstrate how scope is used, consider the following example which uses a scope property.</p>

<h3>Sample Output Using a Scope Element:</h3>
<pre>
<code>
var pixelValue = 256;
var scopeElement = $(myElement); //element being used for scope. It has a font size of 14px.
var emValue = pixelValue.pxToEm({'scope': scopeElement}); 
==> returns string "18.29em"
</code>
</pre>

<p>We can see that pxToEm has used the font size of the scope element for its calculation above. Using a scope parameter would be useful for figuring out dimensions when inserting an element into the scope element.</p>

<h2>But What About Ems to Pixels?</h2>
<p>Don't worry, we didn't leave you hangin'! A second optional property called 'reverse' defines the direction of the conversion. Simply pass a reverse parameter as true and pxToEm will convert your value to pixels. The following calculator demonstrates the flexibility and capabilities of this plugin.</p>

<h2>Demo Calculator</h2>
<iframe src="/examples/pxToEm/" style="height:28em"></iframe>


<h2>Sweet! How do I use it?</h2>
<p>First, you'll need to be using the jQuery javascript library, which is free and can be downloaded here: <a href="http://www.jquery.com" class="external">jQuery.com</a>. Then grab one of the javascript files linked below and either paste its contents into your javascript file or link to it as a standalone. </p>

<h3>Syntax and options</h3>
<p>Unlike a jQuery plugin, pxToEm is a string/number method and is not meant to be applied to a jQuery object. Instead, you will apply it as a method on a variable that references either a number or numeric string. pxToEm has defaults that can be overridden via the options argument. These settings should be passed in as an object as shown below:</p>

<pre>
<code>
myValue.pxToEm({
   scope: 'h3',
   reverse: true
});

</code>
</pre>

<h3>Available Options</h3>
<ul>
<li><strong>Scope:</strong> jQuery object or selector string, defaults to 'body'</li>
<li><strong>Reverse:</strong> Boolean, defaults to true</li>
</ul>

<h4>Download it!</h4>
<ul>
<li><a href="/examples/pxToEm/pxToEm.js">pxToEm.js</a></li>
</ul></description>
      <dc:subject>css, javascript, jQuery</dc:subject>
      <dc:date>2008-03-04T19:02:00-05:00</dc:date>
    </item>

    <item>
      <title>What we&#8217;re thinking</title>
      <link>http://www.filamentgroup.com/lab/what_were_thinking/</link>
      <guid>http://www.filamentgroup.com/lab/what_were_thinking/#When:17:37:00Z</guid>
      <description><p>We're always thinking about better ways to present information, streamline workflows, and develop applications. <strong>Welcome to our lab.</strong></p></description>
      <dc:subject></dc:subject>
      <dc:date>2007-11-14T17:37:00-05:00</dc:date>
    </item>

    <item>
      <title>Styling the button element with sliding doors</title>
      <link>http://www.filamentgroup.com/lab/styling_the_button_element_with_sliding_doors/</link>
      <guid>http://www.filamentgroup.com/lab/styling_the_button_element_with_sliding_doors/#When:19:06:00Z</guid>
      <description><p>Particle Tree recently posted <a href="http://particletree.com/features/rediscovering-the-button-element/" class="external">an article</a> describing a technique for styling the HTML button element. For those not familiar, form buttons are notoriously difficult to customize because they <a href="http://www.456bereastreet.com/archive/200410/styling_even_more_form_controls/" class="external">render differently</a> across browsers and platforms. The typical solutions are to use the default button style that the browser provides, or use an image input, which may look fine but requires that you create a unique background image with text "baked in" for each type of button (i.e., "Enter", "Send message") and its rollover state.</p><p>While Particle Tree's technique works well, we needed a more flexible solution that accommodated a wider range of styles. We're often designing and developing complex applications with buttons that are styled with background images, background colors, icons, and sometimes a combination of all three.  Ideally, our buttons would:</p>

<ul>
<li>use the <a href="http://alistapart.com/articles/slidingdoors/">sliding doors</a> method introduced on A List Apart, </li>
<li>allow us to use HTML text for the button labels so that we could reuse the same button style many times without having to cut unique images for each, and</li>
<li>do not require JavaScript for form submission or rollovers.</li>
</ul>

<p>To meet these conditions we developed the following technique &#8212; a cross-browser method for styling button elements with sliding doors.</p>

<h2>Examples</h2>
<p>Each button shown uses the same markup and style &#8212; only the label text is different.</p>
<iframe src="/examples/buttonElement/" name="example1" style="height:10em"></iframe>


<h3>Images & Markup</h3>
<p>We cut two images for each state, default and hover (4 images total). The first pair form the left side of the button, the second form the right side.</p>

<div class="exampleImgs">
<p>Left corners:</p>
<p><img src="/examples/buttonElement/images/btn_blue_left.gif" /><br />
<img src="/examples/buttonElement/images/btn_blue_left_hover.gif" /></p>

<p>Right corners:</p>
<p><img src="/examples/buttonElement/images/btn_blue_right.gif" /><br />
<img src="/examples/buttonElement/images/btn_blue_right_hover.gif" /></p>
</div>

<p>(We'd like to convert these states into two sprites, where the default and hover state for each are burned into a single background image that is repositioned on hover. Initial testing for that idea yielded inconsistent results &#8212; if you have any success with this, <a href="#comment_form">please drop us a line</a>.)</p>

<p>Button markup consists of a button tag around a span tag, and label text is written into the span.  Both tags are necesary to support the two sliding door background images: the button tag's background image is shorter with right corners, and the span's background image is the larger with left corners.  We found in our tests that it's best to cut the right image at least as wide as it is tall to avoid gaps between the doors.</p>

<p>And last but not least, the "submitBtn" class is assigned to the button tag (styles for the span tag are assigned with descendant selectors):</p>

<pre>
&lt;button value=&quot;submit&quot; class=&quot;submitBtn&quot;&gt;&lt;span&gt;Submit&lt;/span&gt;&lt;/button&gt;
</pre>


<h3>CSS</h3>
<pre>
button { 
  border:0; 
  cursor:pointer; 
  font-weight:bold; 
  padding:0 20px 0 0; 
  text-align:center; 
}
button span { 
  position:relative; 
  display:block; 
  white-space:nowrap; 
  padding:0 0 0 20px; 
}

/*blue buttons*/
button.submitBtn { 
  background:url(images/btn_blue_right.gif) right no-repeat; 
  font-size:1.3em; 
}
button.submitBtn span { 
  height:50px; 
  line-height:50px;
  background:url(images/btn_blue_left.gif) left no-repeat;
  color:#fff; 
}
button.submitBtn:hover {
	background:url(images/btn_blue_right_hover.gif) right no-repeat; 
}
button.submitBtn:hover span {
	background:url(images/btn_blue_left_hover.gif) left no-repeat; 
}
</pre>

<h4>CSS for IE 6 and 7</h4>
<p>We recommend referencing these in a dedicated IE stylesheet using <a href="http://www.quirksmode.org/css/condcom.html" class="external">conditional comments</a>.</p>	
<pre>
button { 
  width:auto; 
  overflow:visible; 
}
button span { 
  margin-top:1px; 
}
</pre>

<h3>Supported Browsers</h3>
<p>So far we've tested: IE 6, IE7, Firefox (Mac + PC), Safari, Opera, Camino</p>

<h3>Caveats</h3>
<p>IE 6 does not support the ":hover" pseudoclass on elements other than anchor tags.  To get the hover to work in IE6, you'll need to duplicate the :hover styles and assign them a class name, and then script a function to toggle that class on/off.</p>


<h3>Credits</h3>
<p>This technique was motivated by the Particle Tree article <a href="http://particletree.com/features/rediscovering-the-button-element/">Rediscovering The Button Element</a>. The "width: auto;" workaround for IE is a technique we discovered at <a href="http://jehiah.cz/archive/button-width-in-ie">Jehia.cz</a>.</p>
</description>
      <dc:subject>css, ui design, visual design</dc:subject>
      <dc:date>2007-05-23T19:06:00-05:00</dc:date>
    </item>

    
    </channel>
</rss>