Daniel Glazman: A better CSS OM for parsed values |
A large part of the current CSS Object Model sucks. More specifically, the CSSValue, CSSPrimitiveValue, CSSValueList, RGBColor, Rect and Counter interfaces are so poorly designed they're not implemented. I just tried to implement them for a project of mine and I must say the model is so weak and incoherent it cannot be implemented as is.
I have then tried to refine what's in the 2000-nov-13 spec of DOM Level 2 Style to reach something workable. I am NOT saying this has to be done or implemented. Call it a mental exercise I did just for fun, w/o caring about performance.
Let's first look at what's wrong:
interface CSSValue { // UnitTypes const unsigned short CSS_INHERIT = 0; const unsigned short CSS_PRIMITIVE_VALUE = 1; const unsigned short CSS_VALUE_LIST = 2; const unsigned short CSS_CUSTOM = 3; attribute DOMString cssText; // raises(DOMException) on setting readonly attribute unsigned short cssValueType; };
"inherit" is here considered as a special identifier despite of the fact a CSSPrimitiveValue can be a CSS_IDENT. There is no UnitType for "initial". A CSS_CUSTOM is, according to the spec, a "custom value"; but a custom value still has to be valid per CSS syntax so it should be representable with CSS_VALUE_LISTs and CSS_VALUEs.
interface CSSValueList : CSSValue { readonly attribute unsigned long length; CSSValue item(in unsigned long index); };
All in all, this one is simple and should be quite ok. But one thing is missing: a property can accept a comma-separated list of whitespace-separated values. The current CSSValueList cannot express if the serialization of a CSSValueList should be whitespace- or comma-separated.
interface CSSPrimitiveValue : CSSValue { // UnitTypes const unsigned short CSS_UNKNOWN = 0; const unsigned short CSS_NUMBER = 1; const unsigned short CSS_PERCENTAGE = 2; const unsigned short CSS_EMS = 3; const unsigned short CSS_EXS = 4; const unsigned short CSS_PX = 5; const unsigned short CSS_CM = 6; const unsigned short CSS_MM = 7; const unsigned short CSS_IN = 8; const unsigned short CSS_PT = 9; const unsigned short CSS_PC = 10; const unsigned short CSS_DEG = 11; const unsigned short CSS_RAD = 12; const unsigned short CSS_GRAD = 13; const unsigned short CSS_MS = 14; const unsigned short CSS_S = 15; const unsigned short CSS_HZ = 16; const unsigned short CSS_KHZ = 17; const unsigned short CSS_DIMENSION = 18; const unsigned short CSS_STRING = 19; const unsigned short CSS_URI = 20; const unsigned short CSS_IDENT = 21; const unsigned short CSS_ATTR = 22; const unsigned short CSS_COUNTER = 23; const unsigned short CSS_RECT = 24; const unsigned short CSS_RGBCOLOR = 25; readonly attribute unsigned short primitiveType; void setFloatValue(in unsigned short unitType, in float floatValue) raises(DOMException); float getFloatValue(in unsigned short unitType) raises(DOMException); void setStringValue(in unsigned short stringType, in DOMString stringValue) raises(DOMException); DOMString getStringValue() raises(DOMException); Counter getCounterValue() raises(DOMException); Rect getRectValue() raises(DOMException); RGBColor getRGBColorValue() raises(DOMException); };
This is so completely crazy I don't know where to start...
interface Rect { readonly attribute CSSPrimitiveValue top; readonly attribute CSSPrimitiveValue right; readonly attribute CSSPrimitiveValue bottom; readonly attribute CSSPrimitiveValue left; };
This looks and smells like a CSSValueList far too much.
interface RGBColor { readonly attribute CSSPrimitiveValue red; readonly attribute CSSPrimitiveValue green; readonly attribute CSSPrimitiveValue blue; };
This cannot represent rgba(), hsl() and hsla() colors. We also have to use three CSSPrimitiveValue for the three color components because they can be a percentage or an integer...
interface Counter { readonly attribute DOMString identifier; readonly attribute DOMString listStyle; readonly attribute DOMString separator; };
Again, something is missing here: nothing says if it's supposed to be a counter() or a counters() value. And no, the separator could not do the trick since it can be the empty string.
To have a better OM for Values, i.e. an extensible OM that allows an application to deal with parsed values of all kinds, we need to change of perspective. First, the list of reserved idents, the list of units and the list of functions are not extensible. Secondly, we have cast issues between PrimitiveValues and ValueLists and we need a single interface. We can deal with all the issues with a single CSSValue interface:
interface CSSValue { // ValueTypes const unsigned short CSS_SYMBOL = 0; const unsigned short CSS_NUMBER = 1; const unsigned short CSS_UNIT = 2; const unsigned short CSS_STRING = 3; const unsigned short CSS_URI = 4; const unsigned short CSS_IDENT = 5;
const unsigned short CSS_VALUE_LIST = 6; readonly attribute unsigned short type; attribute boolean commaSeparated;
readonly attribute unsigned long length;
CSSValue item(in unsigned long index);
raises(DOMException);
void setFloatValue(in float floatValue) raises(DOMException); float getFloatValue() raises(DOMException);
void setStringValue(in DOMString stringValue) raises(DOMException); DOMString getStringValue() raises(DOMException); };
An integer indicating the type of the Value
CSS_SYMBOL
/
character in the font shorthand
property. The value can be obtained by the getStringValue()
and set by the setStringValue()
method.CSS_NUMBER
getFloatValue()
method and set through by setFloatValue()
method.CSS_UNIT
getFloatValue()
method and
set through by setFloatValue()
method. The unit part of
the value can be obtained by using the getUnit()
method
and set through by setUnit()
methodCSS_STRING
getStringValue()
and set by the setStringValue()
method.CSS_URI
url()
function
can be obtained by the getStringValue()
and set by the setStringValue()
method.CSS_IDENT
getStringValue()
and set by the setStringValue()
method.CSS_VALUE_LIST
getStringValue()
method does not reply the empty string. The list of values is
whitespace-separated if the commaSeparated
attribute is
false and comma-separated otherwise.type
of type unsigned short
, readonlycommaSeparated
of type boolean
type
attribute is CSS_VALUE_LIST
. The list is
whitespace-separated if the attribute is false and comma-separated
otherwise.length
of type unsigned long
, readonlyCSSValue
in the list. The range of valid
values of the indices is 0
to length-1
inclusive.CSS_VALUE_LIST
.getFloatValue
CSS_NUMBER
or the number part
of the value of a CSS_UNIT
. If this CSS value is not a CSS_NUMBER
or a CSS_UNIT
, a DOMException
is raised. float
The float value of this CSS_NUMBER
or CSS_UNIT
CSS_NUMBER
nor a CSS_UNIT
.getStringValue
CSS_SYMBOL
, retrieves the single character used as
a symbol.CSS_STRING
, retrieves the string. Enclosing quotes
or double-quotes are NOT included.CSS_UNIT
, retrieves the unit of the value.CSS_URI
, retrieves the argument of the url(...)
notation. Enclosing quotes or double-quotes are NOT includedt.CSS_IDENT
, retrieves the identifier.CSS_VALUE_LIST
and if that list of values is
passed as the parameters of a function, retrieves the function name.
Retrieves the empty string otherwise.CSS_NUMBER
and CSS_UNIT
, a DOMException
is raised. DOMString
The float value of this CSS_NUMBER
or CSS_UNIT
CSS_NUMBER
or a CSS_UNIT
.item
CSS_VALUE_LIST,
Used to retrieve a CSSValue
by ordinal index. The order in this collection represents the order of
thevalues in the CSS style property. If index is greater than or equal
to the number of values in the list, this returnsnull
. DOMException
is raised. index
of type unsigned long
: index into
the collection. CSSValue
The CSSValue at the index position in the CSSValueList
,
or null
if that is not a valid index.CSS_VALUE_LIST
.setFloatValue
CSS_NUMBER
or the number part of the
value of a CSS_UNIT
. If this CSS value is not a CSS_NUMBER
or a CSS_UNIT
, a DOMException
is raised. floatValue
of type float
;CSS_NUMBER
nor a CSS_UNIT
or if the attached property doesn't
support the float value or the unit type.setStringValue
CSS_SYMBOL
, sets the single character used as a
symbol.CSS_STRING
, sets the string.CSS_UNIT
, sets the unit of the value.CSS_URI
, sets the argument of the url(...)
notation.CSS_IDENT
, sets the identifier.CSS_VALUE_LIST
and if the parameter is not the
empty string, make the list of values become a function and sets the
function name. Make the list become a plain list of values if the
parameter is the empty string.CSS_NUMBER
and CSS_UNIT
, a DOMException
is raised. stringValue
of type DOMString
CSS_NUMBER
or a CSS_UNIT
, if the type of the value is CSS_SYMBOL
and the string can be parsed as an other type of value, if the type
of the value is CSS_UNIT
and the string is not a valid
CSS unit, if the type of the value is CSS_URI
and the
string is not a valid URI, if the type of the value is CSS_IDENT
and the string is not a valid CSS identifier, if the type of the
value is CSS_VALUE_LIST
and the string is not a valid
CSS identifier or the empty string.The above should be enough to describe any CSS value, specified or computed. The model will become a bit complex for complex values but it ensures any web application can have access to parsed values, deal with their types and modify them. Let's take an example:
background-image: linear-gradient(to bottom, yellow 0%, blue 100%), url(foo.png);
This will result in the following OM (click on the image to enlarge it):
Again, I'm not saying the above is the thing to do or implement. It can certainly be improved, for instance for colors. A totally different perspective is also perfectly possible. I am only saying that making a better CSS OM allowing a full representation of parsed values in stylesheets and computed values is feasible. I hope the CSS OM will offer such power in the future.
UPDATE: the new CSSValue interface above lacks one thing, the ubiquitous cssText for parsing and serialization. Sorry for that.
http://www.glazman.org/weblog/dotclear/index.php?post/2014/03/19/A-better-CSS-OM-for-parsed-values
Комментировать | « Пред. запись — К дневнику — След. запись » | Страницы: [1] [Новые] |