User-defined CSS properties and apply()

Hi all,

In a previous thread regarding components and user-defined pseudo-elements (
http://lists.w3.org/Archives/Public/www-style/2011Aug/0280.html) I made a
suggestion to add user-defined CSS properties instead. However, I believe
this idea might have wider applicability, so I'd like to present it here in
a more general context. But please note that all this still very much is
brainstorming, so please be gentle... ;)

Overview:

The proposal consists of 2 parts:

1.) Allow users to define arbitrary CSS properties (using some syntax) that
inherit and cascade as normal.
2.) Add a function apply() that returns the current value of a CSS property.


Details:

In style rules, a user can add arbitrary properties, prefixed by '::' (a
parallel to pseudo-elements, but the exact syntax doesn't matter). Such
properties cascade and inherit as normal. In and of themselves, user-defined
properties have no effect, but a script can query them using
getComputedStyle(). The value of a user-defined property is similarly
arbitrary, but we might add an (optional?) type identifier.

apply(<property>) returns the current inherited value of the specified
property for the current node. apply() on an undefined property is invalid
(or returns the empty string?). For example:

<div class=A>
  <div class=B>
    <div class=C>

.A {
  ::foo: color red;
  ::bar: color blue;
  ::quz: length 2px;
}

.B {
  color: apply(::foo);  [1]
}

.C {
  ::foo: color green;   [2]
  background-color: apply(::foo);  [3]
  border-color: apply(color);  [4]
  padding: 0 2px;  [5a]
  padding: 0 apply(::quz);  [5b]
  padding: 0 apply(::quz) 0 apply(::qoz);  [5c]
}

[1] set color to the current value of ::foo, i.e., red. It is NOT set to a
dynamic 'apply(::foo)' value.
[2] as noted in [1], apply() is NOT dynamic, so even though ::foo changes
here, 'color' is still red, as inherited.
[3] apply() returns the inherited value, NOT any overridden value of the
current rule, so background-color would be red.
[4] apply should be usable with any property, not just user-defined
properties.
[5a] a default padding
[5b] a more specific padding to be used iff ::quz is defined and applicable
(which it is), overriding [5a]
[5c] ::quz is defined and legal here, but ::qoz isn't, so the whole line
isn't applied, leaving the padding defined in [5b]


Other usage examples:

.menu {
  ::lo-color: color #000044;
  ::hi-color: color #0000CC;
}
.warning {
  ::lo-color: color #440000;
  ::hi-color: color #CC0000;
}
div.colored {
  color: apply(::hi-color);
  background-color: apply(::lo-color)
}
pre {
  border: 1px solid apply(::lo-color)
}

body {
  ::level: integer 0;
}
.nested {
  ::level: calc(apply(::level) + 1);
}
.nested::before {
  content: apply(::level) ' ';
}

A component use case (which spawned this whole proposal):

video {
  border: 1px solid black;
  ::play-background-color: slategrey;
  ::stop-background-color: darkred;
  ::panel-color: black;
  ::click-sound: true;
}

As implied above, apply() can be useful in and of itself:

.negative {  /* switch background and text color, whatever they currently
are */
  color: apply(background-color);
  background-color: apply(color);
}


Fundamentally, this proposal is similar to CSS variables, but - I would
argue - more powerful:

.) The user-defined properties inherit and participate in the cascade. I.e.,
they can change based on combination of layout, media queries, etc.
.) apply() can express inter-dependencies, like shown in the examples above.
.) It'd be terribly useful for components... ;)


What do you think?

- Roland

Received on Thursday, 6 October 2011 12:29:06 UTC