- From: Anne van Kesteren <annevk@opera.com>
- Date: Thu, 05 Nov 2009 16:30:37 -0800
- To: www-archive@w3.org
Below is a proposal Ian Hickson made to replace CSSValue and co somewhere at the end of 2002. This email makes the proposal public. For reference the original Member-only proposal can be found here: http://lists.w3.org/Archives/Member/w3c-css-wg/2002OctDec/0264.html === I discussed possiblities for a replacement for CSSValues with some of the web authors who have been the most vocal to me about the need for a non-string-based API for complex manipulation of the CSSOM. First, here are some examples showing what the API currently requires to do simple tasks. [1] 1. Increasing the 'top' property of a style declaration by one pixel. Using the CSSValues API: var top = style.getPropertyCSSValue('top'); top.setFloatValue(top.CSS_PX, top.getFloatValue(top.CSS_PX) + 1); Using the string-based API (assumes that the property is already set in pixels): style.top = parseInt(style.top) + 1 + 'px'; Using the API proposed below: style.top.px++; 2. Getting the URL of the background image of an element. Using the CSSValues API: var style = document.defaultView.getComputedStyle(element, ''); var url = style.getPropertyCSSValue('background-image').getStringValue(); Using the string-based API: var style = document.defaultView.getComputedStyle(element, ''); var url = style.backgroundImage; url.replace(/^url\(['"]?/, ''); url.replace(/['"]?\)$/, ''); url.replace(/\\(.)/, '$1'); Using the API proposed below: var url = element.computedStyle.backgroundImage.url; 3. Increasing the red component of color by 1 part in 255 (typically this would really be changing two or three values, or the hue, this is just a simple example). Using the CSSValues API: var red = style.getPropertyCSSValue('color').getRGBColorValue.red; red.setFloatValue(red.CSS_NUMBER, red.getFloatValue(red.CSS_NUMBER) + 1); Using the string-based API: var color = style.color; var red, green, blue; if (color.match(/^rgb\(([0-9]+), ?([0-9]+), ?([0-9]+)\)$/)) { red = RegExp.$1; green = RegExp.$2; blue = RegExp.$3; } else if (color.match(/^rgb\(([0-9.]+)%, ?([0-9.]+)%, ?([0-9.]+)%\)$/)) { red = 255 * RegExp.$1 / 100; green = 255 * RegExp.$2 / 100; blue = 255 * RegExp.$3 / 100; } else { // XXX incomplete throw "#rrggbb, #rgb, and named constants not supported (received '" + color + "')"; } red++; style.color = 'rgb(' + red + ',' + green + ',' + blue + ')'; Using the API proposed below: style.color.red++; I maintain that there is definitely a need for DOM-based manipulation of a CSSOM, because SMIL, while great for simple or even moderately complex animations, is not able to do things such as a Pacman game. The existence of sites such as http://www.javascript-games.org/ is pretty clear evidence that there is a demand for programmatic access to the DOM and style-related issues. The complexity of the examples given above speaks for itself. The existing interface is just not suitable. What follows is a straw-man proposal based on feedback I have received from Mozilla's CSSOM implementors and dynamic content authors. Requirements Summary: Being able to manipulate style data through a scriptable object model without an intermediate string representation. Being able to do so without going through pointless theoretical methods and attributes. Examples using the proposal below: // increase font-size by 1px element.style.fontSize.px++; // set width to x%, where x is a variable rule.width.percent = x; // desaturate the colour of an element for (property in ['color', 'background-color', 'border-top-color' /* ... */]) { document.getOverrideStyle(element, null).getProperty(property).saturation = 0; } // set content to 'url(example) counter(headers) "."' style.content.clear(); style.content.append(CSSItemURL.create('example')); style.content.append(CSSItemCounter.create('headers', 1)); style.content.append(CSSItemString.create('.')); // get the background-image URL (possibly relative) var url = style.backgroundImage.url; // get the background-image URL (resolved to an absolute URL) var url = style.backgroundImage.absoluteUrl; Interfaces for this Straw Man Proposal: interface CSSStyleDeclaration { CSSPropertyValue getProperty(in DOMString propertyName); // (plus everything in DOM2 except getPropertyCSSValue) } // Available using binding-specific casting mechanisms on CSSStyleDeclaration interface CSSStyleDeclarationProperties { attribute CSSBackgroundAttachmentPropertyValue backgroundAttachment; attribute CSSColorPropertyValue backgroundColor; attribute CSSURLPropertyValue backgroundImage; attribute CSSBackgroundPositionPropertyValue backgroundPosition; // ... attribute CSSContentPropertyValue content; // etc... // Each longhand property has an attribute on this interface. // Initially we might want to skip properties which only take // keywords, as string manipulation is not a problem with those. } interface CSSPropertyValue { // Note. On bindings with string coercion (such as // ECMAScript) the string representation of this value must // be the same as its cssText attribute. This allows the // CSSStyleDeclarationProperties and CSS2Properties // interfaces to be used interchangeably without casting in // some environments. attribute DOMString cssText; const unsigned short CSS_UNSET = 0; const unsigned short CSS_INHERIT = 1; // CSS2 const unsigned short CSS_INITIAL = 2; // CSS3 const unsigned short CSS_DEFAULT = 3; // CSS3 const unsigned short CSS_ATTR = 4; // CSS3 const unsigned short CSS_VALUE = 16; attribute unsigned short value; // takes one of the CSS_* constants // This will be null unless value == CSS_ATTR // setting it sets value to CSS_ATTR attribute AttrExpression attr; } // initially we might want to avoid mentioning attr altogether interface AttrExpression { const unsigned short CSS_STRING = 0; attribute DOMString attribute; attribute unsigned short type; attribute CSSPropertyValue default; AttrExpression create(in DOMString attribute, in unsigned short type, in CSSPropertyValue default); } // initially we might want to skip out on the keyword-only properties // since string manipulation for those is no big deal interface CSSBackgroundAttachmentPropertyValue { const unsigned short CSS_SCROLL = CSS_VALUE + 0; const unsigned short CSS_FIXED = CSS_VALUE + 1; } interface CSSColorPropertyValue : CSSPropertyValue { const unsigned short CSS_COLOR = CSS_VALUE + 0; const unsigned short CSS_ACTIVEBORDER = CSS_VALUE + 1; const unsigned short CSS_ACTIVECAPTION = CSS_VALUE + 2; // etc.. // These will be 0 unless value >= CSS_COLOR attribute short red; attribute float redPercent; // 100% = 255 attribute short green; attribute float greenPercent; // 100% = 255 attribute short blue; attribute float bluePercent; // 100% = 255 attribute float alpha; // float in range 0.0..1.0 attribute short hue; // integer in range 0..360 attribute float saturation; // percentage attribute float lightness; // percentage attribute unsigned long hex3; attribute unsigned long hex6; // If the given values match a named colour, then namedColor will // have the appropriate value from the following list. If not, it // will have the value UNNAMED. const unsigned short UNNAMED = 0; const unsigned short BLACK = 1; const unsigned short SILVER = 2; // etc... (all CSS3 named colours) attribute unsigned short namedColor; } // useful, because the string representation would have to be CSS escaped interface CSSURLPropertyValue : CSSPropertyValue { // The following is only defined if value == CSS_VALUE attribute DOMString url; attribute DOMString absoluteUrl; } // this shows how multi-values properties would be done interface CSSBackgroundPositionPropertyValue : CSSPropertyValue { // the value of x and y are the same as this interface's // if this interface's value is less than CSS_VALUE, else // they are greater than or equal to CSS_VALUE. attribute DOMLengthAndPercentagePropertyValue x; attribute DOMLengthAndPercentagePropertyValue y; } interface CSSLengthPropertyValue : CSSPropertyValue { const unsigned short LENGTH_EM = CSS_VALUE + 100; const unsigned short LENGTH_EX = CSS_VALUE + 101; const unsigned short LENGTH_PX = CSS_VALUE + 102; const unsigned short LENGTH_IN = CSS_VALUE + 103; const unsigned short LENGTH_CM = CSS_VALUE + 104; const unsigned short LENGTH_MM = CSS_VALUE + 105; const unsigned short LENGTH_PT = CSS_VALUE + 106; const unsigned short LENGTH_PC = CSS_VALUE + 107; attribute float length; // length in units specified by value // the following set the units on setting, and // perform conversions on getting. If conversion is not // possible (e.g. relative to absolute without a view) // then an exception is thrown. attribute float em; attribute float ex; attribute float px; attribute float cm; attribute float mm; attribute float pt; attribute float pc; } interface CSSLengthAndPercentagePropertyValue : CSSLengthPropertyValue { const unsigned short LENGTH_PERCENT = CSS_VALUE + 200; attribute float percent; } interface CSSPercentagePropertyValue : CSSLengthPropertyValue { const unsigned short LENGTH_PERCENT = CSS_VALUE + 200; attribute float length; attribute float percent; } // The following is for 'content', probably the most complicated // CSS2 property. interface CSSContentPropertyValue : CSSPropertyValue { const unsigned short CSS_NONE = CSS_VALUE + 1; // value == CSS_VALUE iff length > 0 readonly attribute unsigned long length; CSSItem item(in unsigned long index); // if index == length, acts like appendItem() // if index > length, throws an exception void setItem(in unsigned long index, in CSSItem value); // if index == length, acts like appendItem() // if index > length, throws an exception void insertItem(in unsigned long index, in CSSItem value); // if value != CSS_VALUE, appendItem sets it to CSS_VALUE void appendItem(in CSSItem value); // if deletion would result in a zero length, set value to CSS_NONE void removeItem(in CSSItem value); // if deletion would result in a zero length, set value to CSS_NONE void deleteItem(in unsigned long index); // raises an exception if item is not there unsigned long indexOf(in CSSItem value); // sets value to CSS_NONE void clear(); } interface CSSItem { attribute DOMString cssText; } interface CSSItemKeyword : CSSItem { const unsigned short CSS_NONE = 0; const unsigned short CSS_NORMAL = 1; const unsigned short CSS_OPEN_QUOTE = 100; const unsigned short CSS_CLOSE_QUOTE = 101; const unsigned short CSS_NO_OPEN_QUOTE = 102; const unsigned short CSS_NO_CLOSE_QUOTE = 103; attribute unsigned short value; CSSItemKeyword create(in unsigned short value); } interface CSSItemAttrExpression : CSSItem { // this could do with just inheriting from AttrExpression instead attribute attrExpression attr; CSSItemAttrExpression create(in unsigned short value); } interface CSSItemString : CSSItem { attribute DOMString value; CSSItemString create(in DOMString value); } interface CSSItemURL : CSSItem { attribute DOMString url; attribute DOMString absoluteUrl; CSSItemURL create(in DOMString url); } interface CSSItemCounter : CSSItem { attribute DOMString name; attribute long increment; CSSItemCounter create(in DOMString name, in long increment); } interface CSSItemCounters : CSSItem { attribute DOMString name; attribute long increment; CSSItemCounters create(in DOMString name, in long increment); } -- Footnotes -- [1] See http://www.damowmow.com/playground/demos/animation/ === -- Anne van Kesteren http://annevankesteren.nl/
Received on Friday, 6 November 2009 00:31:16 UTC