www.webdeveloper.com
Page 1 of 4 123 ... LastLast
Results 1 to 15 of 46

Thread: Finally, Accessible DHTML Tabs

  1. #1
    Join Date
    Feb 2003
    Location
    Michigan, USA
    Posts
    5,774

    Finally, Accessible DHTML Tabs

    Accessible Tabs 1.0

    I hate sites whose pages are cluttered with links and graphics. Too much information. Too much scrolling. It's like the designer sneezed on a piece of paper and said, "that looks pretty good." Tabbed interfaces are a great way to dynamically hide and show content, but every implementation of tabs have left accessibility concerns, even the A List Apart article "Let Them Eat Cake."

    Accessibility Concerns with Tabs
    1. Must be keyboard navigable
    2. Since people using screen readers might not know they are using tabs, how do you jump them to the tabs after they are done reading the content in a tab box?
    3. At the end of a long tab box, what's the easiest method of jumping to the next tab? Scrolling back up? Using a jump link?
    4. The script cannot manipulate the tag styles directly. It should only change class names so user agents in different media can decide how best to display these tabs. Tabs should be media independant.
    5. What if you want to bookmark the page on the current tab?
    6. What happens if I want more than one set of tabs on the same page?


    1. Keyboard Navigation
    This is pretty easy to solve. Most tab solutions use the anchor element, or the common <a> tag as the tabs. Using these for the tabs was a no-brainer. However, a little care has to be taken when using <A> tags, since they actually represent a link to another document, or to an anchor point on the current page.

    The href for each tab link jumps to the appropriate tab box, making the tab links DO something if JavaScript is disabled. And with a little JavaScript, the link click can be disabled so the page doesn't reload. Problem 1 solved.


    2. How to Get Back to the Tabs
    No DHTML tabs I've seen so far provide an easy way to jump the user back up to the tabs using the keyboard. At first I thought access keys would be perfect, but instead opted for another link tag. It is placed below the markup for the entire tab structure so it provides "back to top" functionality when scripting is disabled, and also when it is enabled.

    3. Navigating Long Tab Boxes
    Scrolling is kind of a pain, especially if you can't see well or don't have a scroll wheel on your mouse. If a tab box is particularly long, it would be annoying to scroll back up to the tabs, and switch to the next tab. This was easily solved by placing links at the bottom of each tab box that, when clicked, switch to the next tab, AND jump the system focus to the new tab box. This scrolls the top of the tab box into view after switching to the new tab.

    4. JavaScript Doesn't Mess With the Style
    Since JavaScript can be read by any device that supports it, conceivably a hand held device could handle tabs too, but it might not be the best method for displaying that information on a 2 or 3 inch wide screen. The script must be media independant. The JavaScript only changes class names so CSS styles handle the visual changes, from non-tabbed, to tabbed, to switching tabs, every step of the way.

    Now, user agents in any media can use the script to change the class names. Tabs will appear only if CSS styles for that media have been written, otherwise the page acts like the JavaScript never existed.


    5. Bookmarking Tabs
    "Let Them Eat Cake" from A List Apart made a great point. If you've got a long page, break it up and use JavaScript to hide and show only what you need. A problem creeps up when you want to bookmark the page on a certain tab. This implementation searches for the ID of a tab box in the window location when the page loads, then switches to the appropriate tab.

    6. Support For Multiple Tab Boxes
    Lastly, a tab class was created so you can have any number of tab structures on the same page. In Accessible Tabs 1.0, you can even nest tabs, however if you bookmark a tab, only one tab gets switched active. If you bookmarked a tab inside of a tab, the proper tabs wouldn't be made active. Right now this only works if you bookmark a page one tab deep.

    (Keep reading below...)

  2. #2
    Join Date
    Feb 2003
    Location
    Michigan, USA
    Posts
    5,774
    The Markup Needed For Accessible Tabs 1.0

    The markup structure below is what you need to create the tabs:

    HTML Code:
    <div class="tabWrapper" id="example">
     <ul class="tabbedNavOff" id="example_tabs">
      <li><a class="" id="tabsample1" href="#firstTabBox" onclick="return Example.switchTab(this.id,false)"><span><span>Tab #1</span></span></a></li>
      <li><a class="" id="tabsample2" href="#secondTabBox" onclick="return Example.switchTab(this.id,false)"><span><span>Tab #2</span></span></a></li>
      <li><a class="" id="tabsample3" href="#thirdTabBox" onclick="return Example.switchTab(this.id,false)"><span><span>Tab #2</span></span></a></li>
     </ul>
     <div class="tabSpacerOff" id="example_spacer">&nbsp;</div>
     
     <div class="tabBox" id="firstTabBox">
      <div class="tabBoxGutter">
       Content of the tab box.
      </div>
      <p class="tabBoxNav">
       <a href="#secondTabBox" class="tabBoxNavRight" onclick="return Example.switchTab('tabsample2', true);">Next &gt;&gt;</a>
       <span class="tabSpacer">&nbsp;</span>
      </p>
     </div><!-- end firstTabBox -->
     
     <div class="tabBox" id="secondTabBox">
      <div class="tabBoxGutter">
       Content of the tab box
      </div>
      <p class="tabBoxNav">
       <a href="#firstTabBox" class="tabBoxNavLeft" onclick="return Example.switchTab('tabsample1', true);">&lt;&lt; Previous</a>
       <a href="#thirdTabBox" class="tabBoxNavRight" onclick="return Example.switchTab('tabsample3', true);">Next &gt;&gt;</a>
       <span class="tabSpacer">&nbsp;</span>
      </p>
     </div><!-- end secondTabBox -->
     
     <div class="tabBox" id="thirdTabBox">
      <div class="tabBoxGutter">
       Content of the tab box
      </div>
      <p class="tabBoxNav">
       <a href="#secondTabBox" class="tabBoxNavLeft" onclick="return Example.switchTab('tabsample2', true);">&lt;&lt; Previous</a>
       <span class="tabSpacer">&nbsp;</span>
      </p>
     </div><!-- end thirdTabBox -->
    </div><!-- end example -->
    <p class="tabOptionsOff" id="example_options"><a href="#example">Tab options</a></p>
    (Keep reading below...)

  3. #3
    Join Date
    Feb 2003
    Location
    Michigan, USA
    Posts
    5,774
    The CSS Needed For Accessible Tabs 1.0

    (Save as TAB_styles.css)

    Code:
    /*
    * This File: TAB_styles.css
    * Contains all CSS declarations to visually format Accessible Tabs. Contains
    * CSS 1.0 and 2.0 styles and is hidden from 4.0 and older browsers by being
    * imported via the @import method.
    *
    * Version - Accessible Tabs: 1.0
    * By Greg Burghardt
    * greg_burghardt@yahoo.com
    */
    
    /* The UL element containing the tabs when JavaScript is enabled. */
    .tabbedNavOn {
     list-style-type: none;
     margin: 0;
     padding: 0;
    }
    
    /*************** Common styles for both .tabOff and .tabOn *****************/
    .tabbedNavOn a {
     display: block;
    }
    
    .tabbedNavOn a:link,
    .tabbedNavOn a:visited,
    .tabbedNavOn a:active,
    .tabbedNavOn a:hover,
    .tabbedNavOn a:focus {
     text-decoration: none;
    }
    
    .tabbedNavOn a span {
     display: block;
    }
    
    .tabbedNavOn a span span {
     padding: .33em .75em;
    }
    /*************** End common styles for .tabOff and .tabOn ******************/
    
    /* This class is a tab when it is not active. */
    .tabOff {
     cursor: pointer;
     cursor: hand;
     display: block;
    }
    
    /* Non active Tab text color when in the visited and non visited states. */
    .tabOff:link,
    .tabOff:visited {
     color: #c60;
    }
    
    /* Non active tab background color & graphic when in the visited or non
    * visited states. */
    .tabOff:link span,
    .tabOff:visited span {
     background: #FFC489 url(images/Tab_Left.gif) no-repeat scroll 0 0;
    }
    
    /* Non active tab's right background graphic when the tab is in a visited or
    * non visited state. */
    .tabOff:link span span,
    .tabOff:visited span span {
     background: transparent url(images/Tab_Right.gif) no-repeat scroll 100% 0;
    }
    
    /* Non active tab's text color in the active, focus, an hover states. */
    .tabOff:active,
    .tabOff:focus,
    .tabOff:hover {
     color: #fff;
    }
    
    /* Non active tab's background color and left background graphic when in the
    * active, focus and hover states. */
    .tabOff:active span,
    .tabOff:focus span,
    .tabOff:hover span {
     background: #f93 url(images/Tab_Left.gif) no-repeat scroll 0 -500px;
    }
    
    /* Non active tab's background graphic when in the active, focus and hover
    * states. */
    .tabOff:active span span,
    .tabOff:focus span span,
    .tabOff:hover span span {
     background: transparent url(images/Tab_Right.gif) no-repeat scroll 100% -500px;
    }
    
    /* This class is a tab that is switched "on" */
    .tabOn {
     cursor: default;
     display: block;
    }
    
    /* Active tab text color when in the visited and non visited states. */
    .tabOn:link,
    .tabOn:visited,
    .tabOn:active,
    .tabOn:hover {
     color: #fff;
    }
    
    /* Active tab background color & graphic when in the visited, non visited,
    * active, and hover states. */
    .tabOn:link span,
    .tabOn:visited span,
    .tabOn:active span,
    .tabOn:hover span {
     background: #c60 url(images/Tab_Left.gif) no-repeat scroll 0 -1000px;
    }
    
    /* Active tab's right background graphic when in the visited, non visited,
    * active, and hover states. */
    .tabOn:link span span,
    .tabOn:visited span span,
    .tabOn:active span span,
    .tabOn:hover span span {
     background: transparent url(images/Tab_Right.gif) no-repeat scroll 100% -1000px;
    }
    
    /* The active tab when it has the system focus. */
    .tabOn:focus {
     color: #fff;
    }
    
    /* The active tab's BG color & graphic when it has the system focus. */
    .tabOn:focus span {
     background: #f93 url(images/Tab_Left.gif) no-repeat scroll 0 -500px;
    }
    
    /* The active Tab's right BG graphic when it has the system focus. */
    .tabOn:focus span span {
     background: transparent url(images/Tab_Right.gif) no-repeat scroll 100% -500px;
    }
    
    .tabbedNavOn li {
     float: left;
     margin-right: 1px;
    }
    
    /* Tab boxes when JavaScript is disabled. */
    .tabBox {
     font-family: "Palatino Linotype", Palatino, Georgia, "Times New Roman", Times, serif;
     font-size: 1.25em;
    }
    
    .tabBox .tabBoxNav {
     display: none;
    }
    
    /* Hide the tab boxes when they are turned off. */
    .tabBoxOff {
     display: none;
    }
    
    /* The tab box is switched "on" */
    .tabBoxOn {
     background-color: #FFEEDB;
     margin-top: -1px;
     zoom: 1;
    }
    
    /* Padding and borders around the tab content. */
    .tabBoxOn .tabBoxGutter {
     border: 1px solid #c60;
     padding: 0 12px;
    }
    
    /* The tab's bottom text links for Next and Previous */
    .tabBoxOn .tabBoxNav {
     background-color: #c60;
     display: block;
     margin: 0;
     padding: .33em 5px 0 5px;
    }
    
    /* The tab's bottom text links when the link is visited and non visited. */
    .tabBoxOn .tabBoxNav a:link,
    .tabBoxOn .tabBoxNav a:visited {
     color: #fff;
     text-decoration: none;
    }
    
    /* The tab's bottom text links when the link is active, hovered on, or has
    * the system focus. */
    .tabBoxOn .tabBoxNav a:active,
    .tabBoxOn .tabBoxNav a:hover,
    .tabBoxOn .tabBoxNav a:focus {
     color: #fff;
     text-decoration: underline;
    }
    
    /* Gap below the tab's bottom links, and the bottom of the tab box. */
    .tabBoxOn .tabBoxNav .tabSpacer {
     height: .33em;
    }
    
    .tabBoxOn .tabBoxNavLeft {
     float: left;
     padding-right: 5px;
    }
    
    .tabBoxOn .tabBoxNavRight {
     float: right;
     padding-left: 5px;
    }
    
    /* When JavaScript is disabled, hide the link to jump back to the tabs. */
    .tabOptionsOff {
     display: none;
    }
    
    /* The link to jump back to the tabs when JavaScript is enabled. */
    .tabOptionsOn {
     margin: 0;
    }
    
    .tabOptionsOn a {
     margin: -1.5em 0 0 0;
     position: absolute;
     text-align: center;
     width: 100%;
    }
    
    .tabOptionsOn a:link,
    .tabOptionsOn a:visited {
     color: #fff;
     z-index: -1;
    }
    
    .tabOptionsOn a:active,
    .tabOptionsOn a:focus,
    .tabOptionsOn a:hover {
     color: #fff;
     z-index: 1;
    }
    
    /* Spacer DIV under the tabs when JavaScript is disabled. */
    .tabSpacerOff {
     display: none;
    }
    
    /* Spacer DIV under the tabs when JavaScript is enabled. The 1px font size
    * fixes an IE-Win bug that sizes the height too high in certain cases. */
    .tabSpacerOn {
     background-color: #c60;
     clear: both;
     font-size: 1px;
     height: 2px;
     overflow: hidden;
     width: 350px; /* Width required by Safari and IE5-Mac */
    }
    
    /* The DIV tag that encapsulates one entire tab structure. */
    .tabWrapper {
     position: relative;
     width: 350px;
     z-index: 1;
    }
    (Keep reading below...)

  4. #4
    Join Date
    Feb 2003
    Location
    Michigan, USA
    Posts
    5,774
    The JavaScript Needed For Accessible Tabs 1.0

    (Save as TAB_Function_Lib.js)

    Code:
    /****************************************************************************
    * Accessible Tabs 1.0
    * Written by Greg Burghardt
    * greg_burghardt@yahoo.com
    *
    * This was created as open source software and is free to download and
    * distribute. Please include this JavaScript code in its entirety. 
    ****************************************************************************/
    
    // Determines whether any occurence of the TAB class can parse the window
    // location to detect if a tab box should be switched to active. When false,
    // the TAB.detectTabByURL() function will search the window location for a
    // page anchor and switch the proper tab and tab box on if that ID is found
    // in the this.tabBoxIDs[] array.
    var TAB_Found_In_URL = false;
    
    
    
    /****************************************************************************
    * Declare the TAB class.
    ****************************************************************************/
    function TAB() {
     // Version string
     this.version = "Accessible Tabs: Version 1.0";
     
     // Detect standard DOM
     this.DOM     = document.getElementById;
     
     this.name              = "";          // ID of tab wrapper
     this.isInitialized     = false;       // Whether or not the initialization function has been called
     this.tabIDs            = new Array(); // Array of IDs for individual tabs
     this.tabNodes          = new Array(); // Node references to tab links
     this.activeTabID       = "";          // ID of the active tab
     this.activeTabIndex    = 0;           // Array indice of the active tab
     this.boxIDs            = new Array(); // Array of tab box IDs
     this.boxNodes          = new Array(); // Array of node references to tab boxes
     this.makeUniformHeight = false;       // Flag to make all tab boxes a uniform height
     this.size              = 0;           // Number of tab boxes in tab structure
     this.tabSpacerID       = "";          // ID of the spacer DIV under the tabs
     this.tabRootID         = "";          // ID of the OL or UL tag which directly holds the tabs
     this.tabOptionsID      = "";          // ID of the element containing the tab options link at the bottom
     
     
     
     /***************************************************************************
     * Declare the prototypes for the member functions.
     ***************************************************************************/
     if (typeof(_tab_prototype_called) == 'undefined') {
      _tab_prototype_called = true;
      TAB.prototype.initialize         = initialize;
      TAB.prototype.initializeWithIDs  = initializeWithIDs;
      TAB.prototype.uninitialize       = uninitialize;
      TAB.prototype.switchTab          = switchTab;
      TAB.prototype.detectTabByURL     = detectTabByURL;
      TAB.prototype.getVersion         = getVersion;
      TAB.prototype.getTabIndexByID    = getTabIndexByID;
      TAB.prototype.getTabBoxIndexByID = getTabBoxIndexByID;
     }
     
     
     
     /***************************************************************************
     * Initializes the tab box. It does not take any parameters and assumes
     * you've given the data structure a name, at least one ID for a tab, the
     * active tab's ID and at least one tab box ID. This function activates the
     * default tab (as denoted by this.activeTabID).
     ***************************************************************************/
     function initialize() {
      if (this.DOM &&
          this.name         != "" &&
          this.tabIDs[0]    != "" &&
          this.boxIDs[0]    != "" &&
          this.tabSpacerID  != "" &&
          this.tabOptionsID != "" &&
          this.tabRootID    != "") {
       // Get a node reference to the tabs' root element and activate it
       var TabRoot = document.getElementById(this.tabRootID);
       TabRoot.className = "tabbedNavOn";
       
       this.size = this.tabIDs.length;
       
       this.activeTabID = this.tabIDs[0];
       
       for (var i = 0; i < this.size; i++) {
        this.tabNodes[i] = document.getElementById(this.tabIDs[i]);
        this.boxNodes[i] = document.getElementById(this.boxIDs[i]);
        
        if (this.tabNodes[i].id == this.activeTabID) {
         this.boxNodes[i].className = "tabBoxOn";
         this.tabNodes[i].className = "tabOn";
         this.activeTabIndex = i;
        } else {
         this.boxNodes[i].className = "tabBoxOff";
         this.tabNodes[i].className = "tabOff";
        }
       }
       
       TabRoot = document.getElementById(this.tabSpacerID);
       if (TabRoot != "undefined")
        TabRoot.className = "tabSpacerOn";
       
       TabRoot = document.getElementById(this.tabOptionsID);
       if (TabRoot != "undefined")
        TabRoot.className = "tabOptionsOn";
       
       TabRoot = null;
       this.isInitialized = true;
       // If a page anchor pointing to a tab box exists in the window location,
       // find it and switch to the proper tab.
       this.detectTabByURL();
      }
     }
     
     
     /***************************************************************************
     * Initializes the entire tab structure by passing variables to this function
     * for all needed IDs
     ***************************************************************************/
     function initializeWithIDs(Name, RootID, SpacerID, OptionsID) {
      if (this.DOM) {
       this.name         = Name;
       this.tabRootID    = RootID;
       this.tabSpacerID  = SpacerID;
       this.tabOptionsID = OptionsID;
       
       this.initialize();
      }
     }
     
     
     
     /***************************************************************************
     * Removes all node references for this instance of the TAB class. This
     * should occur when the window.onunload event is fired to clean up any node
     * references that might be double-referenced, which should prevent memory
     * leaks in Internet Explorer 5.01 - 6.0.
     ***************************************************************************/
     function uninitialize(override) {
      if (this.isInitialized || override) {
       for (var i = 0; i < this.size; i++) {
        this.tabNodes[i] = null;
        this.boxNodes[i] = null;
       }
       this.isInitialized = false;
      }
     }
     
     
     
     /***************************************************************************
     * Switches to a new tab. Gets the ID of the active Tab and whether or not a
     * null value should be returned to nullify a tab link's click (and
     * consequent browser location change).
     ***************************************************************************/
     function switchTab(ActiveID, ReturnValue) {
      if (this.isInitialized) {
       this.activeTabID = ActiveID;
       this.tabNodes[this.activeTabIndex].className = "tabOff";
       this.boxNodes[this.activeTabIndex].className = "tabBoxOff";
       
       for (var i = 0; i < this.size; i++) {
        if (this.tabNodes[i].id == this.activeTabID) {
         this.tabNodes[i].className = "tabOn";
         this.boxNodes[i].className = "tabBoxOn";
         this.activeTabIndex = i;
         if (ReturnValue != null)
          return ReturnValue;
        }
       }
       return true;
      }
     }
     
     
     
     /***************************************************************************
     * Detects if a tab box has been referenced in the window location and
     * switches to the correct tab. This makes it so you can bookmark the page
     * under a given tab, and return to the page via the bookmark or link and
     * have the appropriate tab active.
     ***************************************************************************/
     function detectTabByURL() {
      if (!TAB_Found_In_URL) {
       var fullurl = "" + window.location;
       var hashPos = 0;
       var activeTabBoxID = "";
       var newActiveTabIndex = 0;
       
       hashPos = fullurl.indexOf("#");
       
       if (hashPos > 0) {
        // Get the page anchor, which is the ID of the soon-to-be active tab box.
        activeTabBoxID = fullurl.substring(hashPos + 1, fullurl.length);
        newActiveTabIndex = this.getTabBoxIndexByID(activeTabBoxID);
        
        if (newActiveTabIndex > -1) {
         // Switch to the appropriate tab.
         this.switchTab(this.tabIDs[this.getTabBoxIndexByID(activeTabBoxID)], null);
         
         // Prevent other occurences of the TAB class from trying to detect the
         // active tab if a URL has a page anchor in it.
         TAB_Found_In_URL = true;
        }
       }
      }
     }
     
     
     
     /***************************************************************************
     * Returns the current version of Accessible Tabs.
     ***************************************************************************/
     function getVersion() {
      return this.version;
     }
     
     
     
     /***************************************************************************
     * Given a tab's ID, this will return it's indice in the TAB.tabIDs array.
     ***************************************************************************/
     function getTabIndexByID(id) {
      for (var i = 0; i < this.size; i++) {
       if (this.tabIDs[i] == id)
        return i;
      }
      return -1;
     }
     
     
     
     /***************************************************************************
     * Given a tab boxe's ID, this will return it's indice in the TAB.tabBoxIDs
     * array.
     ***************************************************************************/
     function getTabBoxIndexByID(id) {
      for (var i = 0; i < this.size; i++) {
       if (this.boxIDs[i] == id)
        return i;
      }
      return -1;
     }
    }
    
    
    
    /****************************************************************************
    * Global tab function to uninitialize an array containing instances of the
    * TAB class. This is mainly to prevent memory leaks in Internet Explorer.
    * This function should always be used when the page unloads.
    ****************************************************************************/
    function TAB_GLOBAL_UNINITIALIZE(Tabs) {
     for (i = 0; i < Tabs.length; i++) {
      Tabs[i].uninitialize(true);
     }
    }
    (Keep reading below...)

  5. #5
    Join Date
    Feb 2003
    Location
    Michigan, USA
    Posts
    5,774
    Implementing Accessible Tabs 1.0

    Once you've got the markup, CSS and JavaScript in place, follow the steps below to set the tab box up for use.

    Step 1. Create as many tabs and tab boxes as you want. You can give any of the HTML tags custom IDs. Only the class names matter.

    Step 2. Declare an instance of the TAB class, and give it the information it needs. This will be added to the HTML file.

    HTML Code:
    </div><!-- end example -->
    <p class="tabOptionsOff" id="example_options"> ... </p>
    <script type="text/javascript">
    <!--
    
    // Declare a new instance of the TAB class
    var Example = new TAB();
    
    // Set IDs needed to create tab structure.
    Example.name         = "example";
    Example.tabSpacerID  = "example_spacer";
    Example.tabOptionsID = "example_options";
    Example.tabRootID    = "example_tabs";
    
    // IDs of the tabs themselves
    Example.tabIDs[0] = "tabsample1";
    Example.tabIDs[1] = "tabsample2";
    Example.tabIDs[2] = "tabsample3";
    
    // IDs of the tab boxes
    Example.boxIDs[0] = "firstTabBox";
    Example.boxIDs[1] = "secondTabBox";
    Example.boxIDs[2] = "thirdTabBox";
    
    // Initialize the tabs
    Example.initialize();
    
    // -->
    </script>
    var Example = new TAB(); This declares a new instance of the TAB class. You can reference all properties and methods for the tabs by using the keyword Example.

    Example.property;
    Example.method();

    If you had a series of tabs for types of products, whose tabs are category names, you could call this instance of the TAB class ProductCategories.

    var ProductCategories = new TAB();

    Then you could access the class properties and methods by typing ProductCategories.property or ProducCategories.method(). Now, back to our Example tabs.

    Example.name: The ID of the DIV tag that encapsulates all of the tabs and tab boxes.

    Example.tabSpacerID: The ID of the spacer DIV under the Tabs.

    Example.tabOptionsID: The ID of the link at the bottom of the tab box structure that allows you to jump back to the tabs.

    Example.tabRootID: The ID of the UL or OL tag that contains the tabs.

    Example.tabIDs: This is an array containing the IDs of all the tabs.

    Example.boxIDs: Another array that contains IDs to all of the tab boxes.

    A quick note about the .tabIDs and .boxIDs arrays. They are called synchronous arrays, meaning the information in a .tabIDs array slot is related to the information in the same array slot in the .boxIDs array. For instance, the ID in .tabIDs[0] is the ID of the first tab. The ID stored in .boxIDs[0] is the ID of the first tab box. The ID of a tab, and the ID of its cooresponding tab box must be in the same index number of the .tabIDs and .boxIDs arrays.

    Example.initialize(); This takes the information you gave the tab class, and activates the whole tab structure including setting the default tab, which is the first item in the .tabIDs array.

    If all goes well, your tabs should show up on screen just fine.


    Cleaning Up After Internet Explorer

    The MSDN article "Understanding And Solving Internet Explorer Leak Patterns" states that the basis for most memory leaks in the popular browser are a result of a DOM node being double-referenced. If you store a reference to one DOM node in two variables, Internet Explorer will not release that memory back to the operating system when the page unloads. For this reason, a TAB global function was created to clean up any node references used in Accessible Tabs when the page unloads. Simply insert the code below in the body tag of the HTML document:

    HTML Code:
    <body onunload="TAB_GLOBAL_UNINITIALIZE(Array(Example));">
    The TAB_GLOBAL_UNINITIALIZE() function taks an array of the TAB classes you declared on the page. For instance, say you have three instances of the TAB class on your page to create three tabbed interfaces.
    Code:
    <script type="text/javascript">
    <!--
    var ProductTypes = new TAB();
    // -->
    </script>
    
    ...
    
    <script type="text/javascript">
    <!--
    var SiteHighlights = new TAB();
    // -->
    </script>
    
    ...
    
    <script type="text/javascript">
    <!--
    var TechSupportOptions = new TAB();
    // -->
    </script>
    The onunload event handler in the body tag would be set up as follows:
    HTML Code:
    <body onunload="TAB_GLOBAL_UNINITIALIZE(Array(ProductTypes, SiteHighlights, TechSupportOptions));">
    This will nullify any node references on those three instances of the TAB class.

    (Keep reading below...)

  6. #6
    Join Date
    Feb 2003
    Location
    Michigan, USA
    Posts
    5,774
    Current Issues With Accessible Tabs 1.0

    There are still a couple things I'd like to build into this tab class. The biggest thing I'd like to do is add support to bookmark a page more than one tab deep. This would involve adding a .parentTab property, which could be a reference to another instance of the TAB class on the page. In this case, you could bookmark the current page any number of tabs deep.

    The .detectTabByURL() function could recursively go up the chain of tabs and switch that tab on, but I decided to release what I've got so far to the public. Chances are real good that you won't need to nest tab boxes.

    Lastly, I'd like to build in support for making each tab box within a set of tabs equal heights. It would be set with the .makeUniformHeight property, but currently this does nothing.

    If you have any additional concerns about the functionality or accessibility of this script, please reply to this thread.


    Download An Example And PSD File

    Attached to this post is a ZIP file that contains the CSS, JavaScript, HTML, and image files used as an example. I've also included the PSD file I used to create the tab graphics. Feel free to edit them as needed, and keep in mind that you may not need the graphics the same widths that I used.
    Attached Files Attached Files
    Last edited by toicontien; 05-18-2006 at 11:39 AM.

  7. #7
    Join Date
    Mar 2006
    Posts
    540
    All I can say to all that is wow! I am sure that is very important code so I saved it. Looks like it will save me months of work. Thanks a lot toicontien. That was extremely nice of you. Rianna

  8. #8
    Join Date
    Feb 2003
    Location
    Michigan, USA
    Posts
    5,774

  9. #9
    Join Date
    Mar 2006
    Posts
    540
    Thank you toicontien, how nice! Looks like it will be awile until I am caught up to speed but have your info in case I need help. Thanks again. Rianna

  10. #10
    Join Date
    Feb 2006
    Location
    Atlanta
    Posts
    218

    Well...

    What in the heck does this do?

    i could do this

    <a href="#1">This is horrible</A>
    Tons of stuff
















    <a name="1"></A>
    More stuff

  11. #11
    Join Date
    Nov 2002
    Location
    Nashua, NH
    Posts
    3,195
    Good job

    Just couple of things I do not quite agree with.
    1. "Finally" in the thread title: http://demos.klproductions.com/betas...ltabsbeta.html

    2. Your mark-up. While mark-up of the tabs is debatable (I am proponent of the fact that tab itself is the header for its content, but separating them into a navigation block also has its merits), the set of tabs is a list with each tab being a list item.

  12. #12
    Join Date
    Feb 2003
    Location
    Michigan, USA
    Posts
    5,774
    But the solution you linked to doesn't degrade when javascript is disabled

    Actually, I considered using headings for the tabs, but in the end I found this to be a much more flexible solution. It was really inspired by the A List Apart article "Let Them Eat Cake" -- and in some ways could be considered an expansion of that method. I wanted something that: A) Screen readers could easily navigate; B) Is keyboard accessible; C) Does not require JavaScript to view the content of the tab structure; D) All styling is controlled by the style sheets; and E) is bookmarkable.

    No styling is applied by JavaScript to the DOM. Class names get switched, so if a device happens to support the W3C DOM, but doesn't have as powerfull a display as a desktop monitor, styles can simply be omitted for that device's media type. The operation of the tabs is completely transparent to devices that do not receive style sheets with the proper styles written.

    This can also be used to break up a large page into sections, not just small tidbits of information.

    It is an interesting thought about each tab box being a list item. I can see that being good for tab structures where the information is closely related and where there isn't much information, but when the tab structure contains lots of information, or complex information, I see having a separate navigation system being the optimal approach. I guess it all boils down to how you're using a tab structure: To break up small pieces of related information, or break up a longer page into more human readable chunks.

    I might make an Accessible Tabs Lite

  13. #13
    Join Date
    Nov 2002
    Location
    Nashua, NH
    Posts
    3,195
    Looked more closely at your code and have a couple of questions:

    What is the advantage of
    Code:
    if (typeof(_tab_prototype_called) == 'undefined') {
      _tab_prototype_called = true;
      TAB.prototype.initialize         = initialize;
      /*more*/
     }
    
    function initialize()
      { /*body*/}
    versus (IMHO straight forward)
    Code:
    function TAB()
      { /*constructor*/
      } 
    
    TAB.prototype.initialize = function()
      { /*method*/
      }
    What is the advantage of providing IDs for every tab and its content and then using them to initialize object properties, versus relying on defined HTML structure (mark up you spacer as hr):
    Code:
    /* Tabs Wrapper is passed to constructor */
    new TAB(document.getElementById('example'));
    
    /* In constructor: */
    function TAB(wrapper)
      { 
        this.tabContentNodes = new Array();
        for(var i=0; i<wrapper.childNodes.length; i++)
           { if(/ul/i.test(wrapper.childNodes[i].nodeName)) 
                  this.tabRoot = wrapper.childNodes[i];
              if(/div/i.test(wrapper.childNodes[i].nodeName))
                   this.tabContentNodes.push(wrapper.childNodes[i];
    
           }
      }
    Last edited by Vladdy; 04-04-2006 at 01:06 AM.

  14. #14
    Join Date
    Feb 2003
    Location
    Michigan, USA
    Posts
    5,774
    Quote Originally Posted by Vladdy
    Looked more closely at your code and have a couple of questions:

    What is the advantage of
    Code:
    if (typeof(_tab_prototype_called) == 'undefined') {
      _tab_prototype_called = true;
      TAB.prototype.initialize         = initialize;
      /*more*/
     }
    
    function initialize()
      { /*body*/}
    To be quite honest, this was my first experiment with JavaScript classes. I read an article about this on about.com or javascript.com. Something like that. And they used the if (typeof(...)) code, so I did. I could go back and just to CLASS.prototype.FUNCTION and it would work just as well.

    Quote Originally Posted by Vladdy
    What is the advantage of providing IDs for every tab and its content and then using them to initialize object properties, versus relying on defined HTML structure...
    "Relying on defined HTML structure(s)" is exactly why I opted to not do that. With a little extra footwork on the JavaScript side, this implimentation of DHTML tabs should be markup independant. If you want to use a different tag structure, you can. Each tab box doesn't have to be a DIV tag. It could be a FIELDSET tag in a large form. It could be a table in a series of tables condensed into a tab structure: http://www.mygoodfriends.com/ (You'll have to be a logged in member to view the example). So I should add an E) Be fairly markup independant.

  15. #15
    Join Date
    Sep 2006
    Posts
    1

    Question How To change the tab name dynamically

    Hi .. I am Mohan Dass. I have created the tab concept. But i want to do one intresting thig in this... if any one know the idea pleaset tell to me.. my id is:indrajith_md@yahoo.co.in.
    That is i would like to change the name of the tabs at run time.. i.e i like to change the tab name dynamically.. as i wish... if any one have knowledge or any idea please sent ot me...

Thread Information

Users Browsing this Thread

There are currently 1 users browsing this thread. (0 members and 1 guests)

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
HTML5 Development Center



Recent Articles