Re: User-defined CSS properties and apply()

I was informally told that this proposal does not make it clear what the
advantage would be for components. Also, there seems to have been confusion
regarding the '::' syntax.

So allow me to give a component example, emphasizing the 'CSS variables that
happen to participate in the cascade' aspect and using a more variable-y '$'
instead of '::'. Suppose you have a component <x-fancy> (not intending to go
into the tag-names vs. 'is' attribute discussion here!) that roughly look
like this:

    <style>
        .top {
            background: apply($fromcolor);
            border-top: 2px solid apply($tocolor);
        }
        .bottom {
            background: apply($fromcolor)
            border-bottom: 2px solid apply($fromcolor);
        }
        button {
            background: apply($fromcolor);
            background: -moz-linear-gradient(top, apply($fromcolor) 0%,
apply($to) 100%);
            background: -webkit-linear-gradient(top, apply($from) 0%,
apply($to) 100%);
            background: -o-linear-gradient(top, apply($fromcolor) 0%,
apply($tocolor) 100%);
            background: -ms-linear-gradient(top, apply($fromcolor) 0%,
apply($tocolor) 100%);
            background: linear-gradient(top, apply($fromcolor) 0%,
apply($tocolor) 100%);
        }
    </style>
    <div class=top>
        TOP
    </div>
    <button>
        <content>
    </button>
    <div class=bottom>
        BOTTOM
    </div>
   ...

You could style this component with a simple rule

    x-fancy {
        $fromcolor: green;
        $tocolor: black;
    }


I.e., hide away the complexity and internal structure (!) from the user.
Compare this with the 'pseudo' attribute approach that AFAICT would need to
set all of that explicitly and expose the internal structure:

        x-fancy::top {
            background: green;
            border-top: 2px solid black;
        }
        x-fancy::bottom {
            background: black;
            border-top: 2px solid green;
        }
        x-fancy::button {
            background: green;
            background: -moz-linear-gradient(top, green 0%, black 100%);
            background: -webkit-linear-gradient(top, green 0%, black 100%);
            background: -o-linear-gradient(top, green 0%, black 100%);
            background: -ms-linear-gradient(top, green 0%, black 100%);
            background: linear-gradient(top, green 0%, black 100%);
        }

Furthermore, suppose the component author later wants to streamline the
component and, e.g., get rid of the .top and .bottom <div>s, and instead set
the top and bottom border on the button directly. I.e., he changes the
component to

    <style>
        button {
            border-top: 2px solid apply($tocolor);
            border-bottom: 2px solid apply($fromcolor);
             background: apply($fromcolor);
            background: -moz-linear-gradient(top, apply($fromcolor) 0%,
apply($to) 100%);
            background: -webkit-linear-gradient(top, apply($from) 0%,
apply($to) 100%);
            background: -o-linear-gradient(top, apply($fromcolor) 0%,
apply($tocolor) 100%);
            background: -ms-linear-gradient(top, apply($fromcolor) 0%,
apply($tocolor) 100%);
            background: linear-gradient(top, apply($fromcolor) 0%,
apply($tocolor) 100%);
        }
    </style>
    <button>
        <content>
    </button>

Even with this change, sites that use the component would not need to update
their style sheets, while that would be necessary with the pseudo-attribute
approach (again, AFAICT).


I hope that helps to make the motivations for this proposal clearer, let me
know if you have any feedback!


- Roland


On Thu, Oct 6, 2011 at 21:28, Roland Steiner <rolandsteiner@chromium.org>wrote:

> 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, 20 October 2011 08:48:17 UTC