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
42 stars 7 forks source link

Allow regular CSS inside ACSS #164

Closed bob2517 closed 3 years ago

bob2517 commented 3 years ago

This may be useful to someone. There would be a slight delay where the CSS would kick in, but if the developer wanted to test CSS with ACSS without having to write in separate files it would be useful to that degree.

Then when the person was happy, the CSS could be extracted out into a separate file for putting on a production site. Could even have a plugin for it so it would happen on a build flow, if so that would get a separate issue. Actually, that would be a great build tool. For now, just allow regular CSS in with ACSS.

The good thing about ACSS is that all the events are distinguishable by the fact that all the declarations start with an event selector, which is the primary reason it's compatible with CSS syntax if ever implemented by the browser, as these events can be isolated easily and moved somewhere else prior to CSS hitting the rendering engine.

Implementation notes: We keep track of all potential colon endings, like :hover, :not, etc. up to CSS Level 4 in the core. So that will need to be employed to differentiate the event selectors from the regular CSS. As part of this, see what else is coming up in CSS as it's been a couple years since the CSS level 4 stuff was looked at.

bob2517 commented 3 years ago

This upgrade will happen at the core level of adding config and will involve setting up a new CSS document for each of the config files or inline tags. Each newly created CSS-in-ACSS document will need to be removed when the same config file or inline ACSS is removed, hence the separation. Plus doing it this way will allow viewing of the inline CSS separately by the extension when that eventually gets worked on. Architecturally it should be straight-forward, as the handling of inline tags - adding and removing from the active config - seems to be working and stable. So it should just be a case of writing the functions and tying them in.

bob2517 commented 3 years ago

Cross-browser-wise, manually creating an inline CSS tag and appending it after the inline ACSS tag is probably the way to go for inline. Give it an ID and tie it to the inline ACSS tag for removal when needed. For initially loaded config, inserting the new CSS tag before the end of the body is probably best, and that won't need tying into any removal stage. That way the cascading should work I think. Regular CSS files should come first followed by any loaded up by ACSS dynamically, and the inline CSS tag should just appear wherever the inline ACSS tag is. Firefox doesn't support the creation of dynamic stylesheet documents yet, so this seems to be the best strategy right now.

bob2517 commented 3 years ago

Care should be taken to unescape anything for the final tag that might get escaped by the time the parser is through with it's stuff for regular parsing.

bob2517 commented 3 years ago

_convConfig.js - might rename this as I'm always forgetting which file runs after the parse setup.

bob2517 commented 3 years ago

Huh! Just found an inherent error whilst sorting this out - "focus" is both a CSS pseudo-selector and an event. That's an interesting one. Not sure what to do about that. I need both though, so I'll have to sleep on that one and work out a best approach to work around it. The isolation of CSS from ACSS is pretty much done now, so apart from this particular scenario it looks like I'm differentiating ok. The next step would be in creating the appropriate CSS tags.

bob2517 commented 3 years ago

Hmmm... do we even need a CSS declaration for focus? Can it be treated as an ACSS event? I think it might just work anyway. CSS commands will apply to the target, which will be the event selector. There'll be a lag as it isn't native CSS, but it would probably work.

Yeah, actually I'm going to leave it.

No breaking change imminent. I'll just make a note in the docs mentioning that focus will act as an event in ACSS and not a CSS declaration.

If ACSS is ever put in the browser, the recommendation from me would be to allow ACSS action commands in the focus declaration and treat it like an event rather than a declaration.

There's no reason regular CSS declarations like :hover" and ":focus" couldn't have ACSS action commands anyway, as those are just events anyway, where the target selector is the same as the event selector. Static commands wouldn't generally have action commands though.

The same issue would have come up if there was an onhover JavaScript event. But luckily there isn't actually an onhover event.

bob2517 commented 3 years ago

Keyframe animation syntax gets recognised ok.

bob2517 commented 3 years ago

CSS accidentally put inside an ACSS component gets flagged as erroring.

bob2517 commented 3 years ago

CSS accidentally put inside an ACSS conditional parses fine, but should be flagged as an error.

bob2517 commented 3 years ago

Doing a little bit of refactoring so we don't get any noticeable loss of speed.

bob2517 commented 3 years ago

CSS and other invalid syntax accidentally put inside an ACSS conditional gets flagged as erroring. Refactored internal error handling slightly.

bob2517 commented 3 years ago

As suspected, CSS at-rules don't work inside ACSS events, only ACSS at-rules do. It's just never been set up. That will need a separate issue started, as that's going to need a more in-depth handling.

Next though, CSS in media queries and CSS at-rules needs sorting out for this particular issue. We just need to recognise all "root" based CSS.

bob2517 commented 3 years ago

A good integration test would be to convert the docs site to not use a CSS file for styling. Ie. merge the CSS file with the main site ACSS. display: none; the body tag (with fallback - need to check that out) and display once ACSS has loaded. It's not necessary the optimum thing to do for a website, but should be a good proof of concept. If that works, slap up a loading indicator of some kind. Faster on initial loading, but slightly slower to render. Would be fine though. I'm already getting 100% performance on Lighthouse, so the experience is not going to be terrible.

If no body fallback, could just set up a parameter that does it on compilation for testing purposes, which would show the un-CSSed docs followed by the loaded CSS once ACSS has initialised.

bob2517 commented 3 years ago

Should probably set up a visual testing examples page for the different CSS at-rules. They would be too irritating to test in karma and jasmine.

bob2517 commented 3 years ago

I can see this issue taking a little while to set up. It would be a good to do though. It would allow server-side set ups to include initial page loading CSS in regular files, and then inline-CSS to be loaded in with ACSS files, which may be more useful for creating component type ACSS, as CSS files can be merged in with the accompanying ACSS code. I dunno. Time will tell. It would demonstrate that CSS and ACSS can live together in the same file though, which would be good for sure.

bob2517 commented 3 years ago

An idea with the CSS at-rules, with the exception of media query which is working fine around event selectors currently, maybe the best way to handle these without trying to duplicate browser behaviour is to place these dynamically into a style tag as they come up. Looking into it some more before doing anything though as it's a messy solution. Just mentioning it to show that it needs more thought.

bob2517 commented 3 years ago

The more I look into these, it seems more appropriate to only allow certain at-rules within ACSS events. And they have to be run using some sort of JavaScript API. They just won't work sensibly if simply placed into style tags on the page - that's messy and a bit weird. Here is a list of findings.

These are not applicable for dynamic ACSS but ok for regular CSS extracted from an ACSS file or tag:

@charset - first element in stylesheet - not applicable. @color-profile - not a valid according at-rule to MDN. @counter-style - more applicable in regular CSS as it's a setup step. @document - deprecated. @font-face - more applicable in regular CSS as it's a setup step. @font-feature-values - doesn't look like it's going to be pursued in chromium browsers. @import - appears right near the top of a stylesheet - not applicable - there's already load-style which works with @media. @keyframes - more applicable in regular CSS as it's a setup step. @namespace - appears right near the top of a stylesheet - not applicable @page - maybe... probably not worth it though. Use just before printing? May as well just put it in regular CSS. @viewport - deprecated.

The only benefit I can think of right now for the "more applicable in regular CSS" rules is that it might be worth having these respond to an ACSS conditional. But without a use case it seems more trouble than it's worth. Need a proper use case to go any further with these.

All the above, however, will be extracted from ACSS files and inline ACSS tags. That's easy enough, as anything not directly coded from ACSS like @if or @media will get placed into a style tag and that's that. So that's future support catered for on a regular CSS level.

That just leaves the following applicable CSS at-rules to support on a dynamic level:

@media - supported outside event declarations already but needs inner declaration support to be more useful. @property - could be done, as there is a JS API for it. But it is experimental, so it might be a waste of time doing it right now. This one is possible though. It's not going to get implemented though unless it gets proper approval, or someone personally asks for it because they can find a use for it when using it with Houdini or something. @supports - would work like @media, but I need to see if I can run the conditions on a JS level like @media.

bob2517 commented 3 years ago

Next step is to find out if @support can work via JS somehow, get a use case for @support, and then get it using the same "outer" event declaration handling as @media and genericise that method properly, if so. That should the first move as it's easy. After that, @media should be gotten to work around and inside target selectors. That should be easy now that @if is supported - just treat inner @media statements like an ACSS conditional and check the media query as a conditional. Simples... may even do that first just to wrap up the @media handling. Then put the @media statement into the control flow docs.

bob2517 commented 3 years ago

I might ask around and see if anyone uses @property. Meanwhile, if anyone is reading this and thinks they have a use for it, comment into this issue and I'll slap it on the to-do list for this release.

bob2517 commented 3 years ago

Back on this. Adjusting to my new on-site job schedule, hence this is going slower than I'd like.

bob2517 commented 3 years ago

Getting @media to work inside the declarations as I know I can knock that out quite quickly. Will commit to branch in stages.

bob2517 commented 3 years ago

Docs done for @media upgrade.

bob2517 commented 3 years ago

Adding an "@else media" statement. @media will work with @else too.

These will only work inside event declarations where the flow is sequential. There is no sequential flow outside of event declarations, so it doesn't make a lot of sense to use these conditionals there, and the core wouldn't be able to easily handle it at the moment.

bob2517 commented 3 years ago

"@media" and "@else media" statements now working offline surrounding target selectors or action commands. Just needs a bit more testing and then I'll do a commit. The @else media one is quite cool. It means you can do this:

body:scroll {
    @media (min-width: 1025px) {
        ...
    } @else media (min-width: 768px) {
        ...
    } @else {
        ...
    }
}

Having less event selectors means that it's more performant to do media queries in this way, if several need to be checked. And it's just a regular media query, so it's better than if-media-max-width which is a bit limited.

bob2517 commented 3 years ago

Or this equivalent (dynamically applying styles) of https://developer.mozilla.org/en-US/docs/Web/CSS/@media/resolution:

button:click {
    p {
        @media (resolution: 150dpi) {
            color: red;
        } @else media (min-resolution: 72dpi) {
            text-decoration: underline;
        } @else media (max-resolution: 300dpi) {
            background: yellow;
        }
    }
}
bob2517 commented 3 years ago

Back on this. Time cut to 1/8th of what it was due to new job - need to create more time. Adding @support next, with support (ooooooh!) for wrapping action commands and target selectors. Dunno if it can be done with JS yet. WIll check it out.

bob2517 commented 3 years ago

Just found this which indicates it can be done: https://stackoverflow.com/questions/30123289/css-supports-vs-checking-support-via-js

Interestingly there's a question in there about whether CSS supports @if or not...

bob2517 commented 3 years ago

Hmmm... need to find out if there's a better way of implementing it without rewriting the full @supports syntax in JS. I don't particularly want to go that route if I can help it.

bob2517 commented 3 years ago

Good news, the CSS.supports() function works with the full @supports condition, like the JS equivalent of @media. That's great, it means it will just slot into the core without any additional stuff.

https://developer.mozilla.org/en-US/docs/Web/API/CSS/supports

bob2517 commented 3 years ago

Ok - will implement thjs tomorrow when I can. I may even just leave it like that for this release - I dunno - time is so limited at the moment. I'll see what the scope of the rest of the release is like and decide tomorrow.

bob2517 commented 3 years ago

I'll do an "@else supports" statement for this too, to align with the new "@else media" statement. That would allow fallback. These commands probably aren't really going to be relevant for a decade or so, but hey - I like thinking ahead.

bob2517 commented 3 years ago

Docs are done for @support and I've got it working in event selectors. Just need to sort out the outer event selector wrapping in the same manner of @media and that should be that.

Then it will be the extraction of regular CSS which will be a bit more challenging.

bob2517 commented 3 years ago

Offline, @support is now fully functional like @media. Docs are done. Just the CSS extraction part of this issue left to do now, which I'll start next weekend unless I can muster sufficient brainpower during the working week.

bob2517 commented 3 years ago

I think I've successfully spotted all the combinations of validly extractable CSS from a config file, including mixtures of CSS and ACSS from within an external @media or @support query, and I'm ignoring them in the core, ready for extraction.

Next step is to generate the stylesheet that will contain these CSS statements commands. They will be distinct per config file loaded and referenceable by some sort of ID or code, for dynamic removal purposes and for use in the extension (if I ever get back on that).

I'm working on a CSP thing this afternoon, so this will be put on hold for the moment. Looking good on this so far though.

bob2517 commented 3 years ago

Back on this. Note to self: All routes to adding config, from startup to inline detection and insertion, go through _addConfig(), so setup prior to _makeVirtualConfig() for CSS extraction should go in _addConfig().

bob2517 commented 3 years ago

Update: Moving along on this. Currently converting the pseudo-code for this in the core to the real code. I've got as far as generating the CSS to be embedded, and just need to create the tags and some code for removing tags. Aiming for completion on this today, depending on test results.

bob2517 commented 3 years ago

Done offline - just needs a few more tests and then I'll do a commit.

bob2517 commented 3 years ago

Note: This also allows mixed CSS and ACSS within outer @media and @support rules. It will extract the CSS away from the ACSS and both will work with their correct engines in entirely separate rules.

CSS specificity-wise, extracted CSS from "loaded" config goes into one style tag at the end of the body. Any embedded ACSS tags subsequently extracted will each appear in their own CSS tags after this "loaded" tag. So CSS extracted from embedded ACSS will take precedence over regular "loaded" CSS extracted from ACSS config.

bob2517 commented 3 years ago

Testing almost complete on this. Discovered a memory leak which has been fixed. Should have a commit on the branch at some point tomorrow.

bob2517 commented 3 years ago

Committed to branch.

bob2517 commented 3 years ago

Going to try and wrap up the docs for this today. May or may not release 2.8.0 once that is done. Tempted to do the performance enhancement issue. Still getting 100% with Lighthouse for load time, but the enhancement would improve running performance.

bob2517 commented 3 years ago

Going live with 2.8.0 today hopefully - so closing this for the milestone.