Active-CSS / active-css

The epic event-driven browser language for UI with functionality in one-liner CSS. Over 100 incredible CSS commands for DOM manipulation, ajax, reactive variables, single-page application routing, and lots more. Could CSS be the JavaScript framework of the future?
https://activecss.org
Other
41 stars 7 forks source link

Proposal to treat HTML attributes, properties and styles more like variables in ACSS. #335

Closed bob2517 closed 4 months ago

bob2517 commented 10 months ago

What sets apart CSS from JavaScript is that it is a OOP language to directly reference HTML elements. It styles properties and classes of objects. It mostly doesn't do anything else other than set styling properties on HTML elements.

ACSS, being the dynamic branch of CSS, could be used to do the same thing with regards setting and getting of those properties.

The syntax below should work if variables are limited to dollar variables, ie. with the syntax of "$varname". Otherwise it could be translated in the core as a variable inside an array. But if dollars are used for variable prefixes, this syntax should work.

#myElement:click {
    [data-list]: "some data";
    @if ([data-list] == "some data") {
        render: "The data-list attribute has some data in it.";
    }
}

I like the attribute syntax, as it's the CSS way to reference an attribute. I'm not convinced on the property syntax used below, but it would be something like that.

#myElement:click {
    [*value]: "2";
    @if ([*value] == "2") {
        render: "The value property is two.";
    }
}

Following on the logic for that, being able to get the getComputedStyle value of any element dynamically may bring further benefits, which gets the actual value of the styling property, set or not set in the developer's CSS. I'm tending to manually use getComputedStyle more and more in my ACSS code these days, mostly for getting real widths and heights. The tilde is a temporary symbol - not sure about this one yet.

#myElement:click {
    ~display: "none";
    @if (~display == "none") {
        render-after-end: "<p>The element above this just disappeared.</p>";
    }
}

That would make #myElement have a display of none, and then a check is done to see if it does have a display of none, and if so, it draws a p tag after it with some text.

The next step is to review existing ACSS code and see if this would have made things simpler if the proposed syntax had been available.

This should be a backward compatible upgrade. There will be more scenarios needed along this line, but that's a start of an idea at least. It needs a similar syntax for use in the render command to be more useful I think, and it should utilize existing CSS syntax if feasible.

bob2517 commented 10 months ago

A more readable alternative could be:

#myElement:click {
    attr(data-list): "some data";
    @if (attr(data-list) == "some data") {
        render: "something";
    }
}
#myElement:click {
    prop(value): "some data";
    @if (prop(value) == "some data") {
        render: "something";
    }
}
#myElement:click {
    style(display): "none";
    @if (style(display) == "none") {
        render-after-end: "something";
    }
}

That feels more acceptable, as it follows the syntax of CSS functions. Easier to read too.

Would need to revisit the syntax for referencing inside CSS commands and inside string variables or string renders. Will ponder this. Feels maybe like the right way to go though. ACSS can seem a bit cryptic unless you know the syntax - this new approach would be easier to read.

Personally I like the brevity of symbols instead of functions, like using "[attribute name]" instead of "attr(attribute name)", but for the sake of readability for all it's worth looking at this. Some developers really struggle with CSS.

bob2517 commented 10 months ago

Perhaps something like this for rendering and using in CSS commands:

#myElement:click {
    render: "The data-list attribute contains: {attr(data-list)}";
    render: "The value property contains: {prop(value)}";
    render: "The display style contains: {style(display)}";
}

or this, which follows CSS function syntax more closely, like with the CSS content command:

#myElement:click {
    render: "The data-list attribute contains: " attr(data-list);
    render: "The value property contains: " prop(value);
    render: "The display style contains: " style(display) " and here is more text";
}

And if so, regular variables could be used the same way:

#myElement:click {
    render: "The total is : " $total ", which is quite a lot";
}

I dunno - it just seems a bit vague to leave functions hanging in between strings with no operator - could be just me.

It's either that or we add in some plus signs so we turn it into JS combined with the CSS function syntax, like this:

#myElement:click {
    render: "The total is : " + $total + ", which is quite a lot.".toUpperCase() + " The attribute contains: " + attr(data-list);
}

Or finally, the existing way in ACSS, which does actually work (you can use JS in a render command with the {= ... =} wrapper), is this:

#myElement:click {
    render: "The total is : {$total}, {= "which is quite a lot.".toUpperCase() =} The attribute contains: {@data-list}";
}

I think that's easier to read than with the plus signs. So with that existing method and only the proposed new CSS function syntax to get attributes, properties and styles, it would look like this:

#myElement:click {
    render: "The total is : {$total}, {= "which is quite a lot.".toUpperCase() =} The attribute contains: {attr(data-list)}";
}

Or if something needed to be done with the attribute, it could be put into the existing ACSS JS expression syntax:

#myElement:click {
    render: "The value property is: {= prop(value).toUpperCase() =}";
}

I'm leaning towards the last two examples above. JS manipulation on attribute values in a function format would be easier to do than it does currently, which requires two commands or not:

#myElement:click {
    $value: "{@value}".toUpperCase();
    render: "The value property is: {$value}";
}
#myElement:click {
    render: "The value property is: {= "{@value}".toUpperCase() =}";
}

It's fine if you know the rules, but unless you know the rules of using {@value}, it can get a bit messy. It's sort of a variable, but it isn't. It needs double quotes when used in a render string but doesn't when used as part of a target selector. The new proposed function syntax makes it a bit more clear as to what is going on, as we don't have to worry about the double quotes, and the abbreviated @ is not as easy to understand as attr().

I think the argument is really what would a new developer learning the language find easier to work with.

bob2517 commented 10 months ago

If I implement this last render command addition, I won't remove the old method, as there's arguments for both. But the CSS function style would additionally need to be there to make this whole issue make sense.

bob2517 commented 4 months ago

Scrapping these ideas for now. {@data-ref} and {@@value} aren't difficult to grasp as concepts. There is scope for a getComputedStyle variable, so re-opening previous issue.