Put your text ad here
WestNIC provides reliable web hosting services
The W3C is planning a new set of CSS level 3 properties that browser vendors have implemented as proprietary extensions. This article shows how to detect and use these CSS3 extension styles through browsers' document object model.
The Javascript for this article, css3-ExtensionStyles.js, is provided under a Creative Commons License. It identifies and distinguishes browsers' proprietary CSS extensions and assign styles to them. The working version of the script implements box-shadow and border-radius properties, with test cases for opacity, background-size and text-overflow.
CSS allows browser vendors to implement proprietary extensions to standard style properties with a hyphen prefix to the property name. Browser vendors have taken this principle and added their own browser identification scheme, so Firefox uses a -moz- prefix, Opera uses -o- and Safari and Google Chrome use -webkit-. Internet Explorer uses -ms-.
The CSS properties of each HTML element in the DOM are represented by a child style object. Every style object contains the full set of CSS properties that apply to the element and these properties can be probed using Javascript.
The names of browsers' extension styles follow a naming scheme equivalent to the CSS property names in camel case with one notable exception. Firefox uses MozBorderRadius for its -moz-border-radius property. Safari uses WebkitBoxShadow for its -webkit-box-shadow property. Internet Explorer does not prefix its DOM style properties, it uses a lower case initial.
| Browser | CSS extension prefix | DOM style extension prefix |
|---|---|---|
| Firefox |
-moz-
|
Moz
|
| Safari |
-webkit-
|
Webkit
|
| Chrome |
-webkit-
|
Webkit
|
| Opera |
-o-
|
O
|
| Internet Explorer |
-ms-
|
None: lower case initial |
The Code Style site has rounded corners on several navigation menu boxes and a subtle drop shadow on thumbnail images. These style declarations are included in the standard livery style sheet, CSStdLiveryCommon.css using their W3C property names: box-shadow and border-radius.
.Thumbnail {
box-shadow: 0px 1px 3px #DDD;
}
#Footbar, .MenuBox, FAQSearchBox,
.RgtBox, .Information, .NavBar {
border-radius: 5px;
}
dl.TOC {
border-top-left-radius: 0px;
border-top-right-radius: 10px;
border-bottom-left-radius: 0px;
border-bottom-right-radius: 10px;
}
Pending approval of the CSS3 standard, browsers do not support these official property names and browsers' proprietary extension names fail CSS validation. To overcome this temporary impasse Code Style uses the css3-ExtensionStyles.js script to apply these styles to selected elements using standard DOM methods. The notes below explain the key variables and functions of the CSS3 extension styles script.
The extension styles script iterates through an array of known extension style prefixes to find the relevant case. When the relevant style property name is identified by the getExtensionStyleNamegetExtensionStyleName() method (see below) it is stored in the AGENT_STYLE array for quick look-up later.
/** * The browser extension prefixes to check. * Moz = Firefox * Webkit = Safari, Chrome * O = Opera * Khtml = Konqueror (no operable styles confirmed) */ var PREFIXES = new Array('Moz', 'Webkit', 'O', 'Khtml'); /** * The user agent extension style property name store. */ var AGENT_STYLE = new Array();
The extension style property names are deduced by concatenating the standard DOM property name for the style with the relevant prefix. A set of constants is declared to represent the standard property names, and to mark those which are not supported by a particular browser.
/** * A constant to mark and check un-supported extension styles. */ var NOT_SUPPORTED = 'not supported'; /** * The CSS3 box shadow DOM style property name. */ var BOX_SHADOW = 'BoxShadow'; /** * The CSS3 border radius DOM style property name. */ var BORDER_RADIUS = 'BorderRadius';
Standard DOM element selection methods are used to get document node sets and assign the extension styles to them. To improve performance, the selected node sets are stored in one of three arrays for quick look-up. The setExtensionStyleById() method stores node sets by ID name in the PAGE_ID_ELEMENTS array for example.
/** * The page elements store for quick look-up. */ var PAGE_ELEMENTS = new Array(); /** * The page ID elements store for quick look-up. */ var PAGE_ID_ELEMENTS = new Array(); /** * The page class elements store for quick look-up. */ var PAGE_CLASS_ELEMENTS = new Array();
The setExtensionStyles() method contains the set of style rules to apply to the page in a series of nested method calls: setBorderRadiusByClass() and setBoxShadowByClass() in this case. The first argument is the HTML class attribute name to match, the second is the style property value to apply. The setExtensionStyles() method should be attached to the document's onload event to ensure it is fully loaded before the styles are assigned.
/** * Apply specified styles to the document (after it has loaded). */ function setExtensionStyles() { setBorderRadiusByClass('MenuBox', '5px'); setBorderRadiusByClass('FAQAction', '5px'); setBorderRadiusByClass('FAQSearchBox','5px'); setBorderRadiusByClass('Information', '5px'); setBorderRadiusByClass('LogAction', '5px'); setBorderRadiusByClass('NavBar', '5px'); setBorderRadiusByClass('RgtBox', '5px'); setBoxShadowByClass('Thumbnail', '0px 1px 3px #DDD'); setBorderRadiusByClass('TOC', '0px 10px 10px 0px'); }
The setExtensionStyleById() method shows the general scheme used by the other style assignment methods, setExtensionStyleByClass() and setExtensionStyleByTagName(). The first argument is an identifier for the node set to be styled: an id attribute name, class attribute name or HTML tag name respectively. The second argument is the standard DOM style property name without proprietary prefix, the third is the style value to be applied.
This set of methods first check the relevant DOM node selection method is supported, in this case the type of the getElementById method. Next they check whether the specified node set has previously been stored. If not, the node set is selected and stored by the given ID. Finally the setExtensionStyle() method is called, passing the selected DOM node, original style name and value. The style by class and tag name functions obtain a set of DOM nodes and loop through to dispatch one at a time.
/** * Generic method to set an extension style by ID name. * @param idName The ID name of the element to select. * @param styleName The standard DOM style property name. * @param value The property value to apply (no semi-colon). */ function setExtensionStyleById(idName, styleName, value) { if (typeof document.getElementById != 'undefined') { if (typeof PAGE_ID_ELEMENTS[idName] == 'undefined') { PAGE_ID_ELEMENTS[idName] = document.getElementById(idName); } setExtensionStyle(PAGE_ID_ELEMENTS[idName], styleName, value); } }
The setExtensionStyle() method is the ultimate target of all the set style methods, it takes a single DOM element reference, a standard DOM style property name and value as arguments. A guard clause checks a valid DOM element has been passed. The next check ensures only extension styles are handled; if a standard DOM style name is recognised by the browser a cascading style sheet rule should be used, not Javascript, so the function returns immediately.
The final part of the setExtensionStyle() method uses the given DOM element reference to get the appropriate extension style name for the browser from the getExtensionStyleName() function. So long as the returned extension style name is not the NOT_SUPPORTED value the style value is assigned to the element and the function returns.
/** * Core method to set an extension style on the given DOM element. * @param element The element to which the style should be applied. * @param styleName The standard DOM style property name. * @param value The style value to apply (no semi-colon). */ function setExtensionStyle(element, styleName, value) { if ((element != null) && (typeof element != 'undefined') && (typeof element.style != 'undefined')) { if (typeof element.style[styleName] != 'undefined') { // CSS3 property name matched // Should be declared in a standard cascading style sheet return; } else { var extensionStyleName = getExtensionStyleName(element, styleName); if (extensionStyleName != NOT_SUPPORTED) { element.style[extensionStyleName] = value; return; } } } // Fall through return; }
The getExtensionStyleName() method is called by the setExtensionStyle() method above to get the relevant style property name for the browser. It first checks if the property name has already been checked and stored in the AGENT_STYLE array. If a stored property name is not found, the function loops through the array of browser specific prefixes, stores and returns any property name that is matched. If the prefix loop exits without a match, the function checks for a Microsoft format property name; the standard DOM property name with lower case initial. A successful match is stored and returned, otherwise the NOT_SUPPORTED value is assigned and returned.
/** * Get the extension style property name for the user agent. * @param element A reference element to check for style properties. * @param styleName The standard style name for the property. * @return The appropriate extension style property name for the user agent, * or the NOT_SUPPORTED constant if not matched. */ function getExtensionStyleName(element, styleName) { if (typeof AGENT_STYLE[styleName] == 'undefined') { for (var i = 0; i < PREFIXES.length; i++) { if (typeof element.style[PREFIXES[i] + styleName] != 'undefined') { AGENT_STYLE[styleName] = PREFIXES[i] + styleName; return AGENT_STYLE[styleName]; } } var msStyle = toLowerCaseInitial(styleName); if (typeof element.style[msStyle] != 'undefined') { AGENT_STYLE[styleName] = msStyle; return AGENT_STYLE[styleName]; } AGENT_STYLE[styleName] = NOT_SUPPORTED; return AGENT_STYLE[styleName]; } else { return AGENT_STYLE[styleName]; } }
The nature of the object, method and property checks in the CSS3 extension styles script means that it is backwards compatible with older browsers and those with basic DOM support, though the advanced styles are not supported in this case. The style by class functions will only work with browsers that support the DOM getElementsByClassName() method, which is not widespread at the time of writing. The extension styles script is only intended to supplement and enhance standard cascading style sheets.
The Code Style CSS3 extension styles script is a work in progress, primarily developed to work with the box-shadow and border-radius properties through a number of convenience methods for each style property and node selection method. Equivalent methods exist for text-overflow and background-size, mainly for development testing. Performance tests with a limited number of styles and node sets indicate that styles are applied to a typical Code Style page in 4 to 6 milliseconds.
setTextOverflowById(idName, value)
setTextOverflowByClass(className, value)
setTextOverflowByTagName(elementName, value)
setBackgroundSizeById(idName, value)
setBackgroundSizeByClass(className, value)
setBackgroundSizeByTagName(elementName, value)
setBoxShadowById(idName, value)
setBoxShadowByClass(className, value)
setBoxShadowByTagName(elementName, value)
setBorderRadiusById(idName, value)
setBorderRadiusByClass(className, value)
setBorderRadiusByTagName(elementName, value)
This approach would work for other extension style properties too, but three convenience methods for each property would make the script quite bulky. In future the core functions should be refactored to allow style property arguments to be passed directly and verify they are legitimate property names. The current setExtensionStyleById(), setExtensionStyleByClass() and setExtensionStyleByTagName() functions behave this way without verification, so can be used with caution.
Build a standards conformant, accessible drop down menu system with DOM1 visibility menus. Javascript CSS visibility controls compatible with Internet Explorer 5, Netscape 6 and Opera 4 onwards, the source has a Creative Commons share-alike license.