Closed bob2517 closed 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.
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.
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.
_convConfig.js - might rename this as I'm always forgetting which file runs after the parse setup.
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.
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.
Keyframe animation syntax gets recognised ok.
CSS accidentally put inside an ACSS component gets flagged as erroring.
CSS accidentally put inside an ACSS conditional parses fine, but should be flagged as an error.
Doing a little bit of refactoring so we don't get any noticeable loss of speed.
CSS and other invalid syntax accidentally put inside an ACSS conditional gets flagged as erroring. Refactored internal error handling slightly.
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.
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.
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.
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.
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.
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.
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.
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.
Back on this. Adjusting to my new on-site job schedule, hence this is going slower than I'd like.
Getting @media to work inside the declarations as I know I can knock that out quite quickly. Will commit to branch in stages.
Docs done for @media upgrade.
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.
"@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.
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;
}
}
}
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.
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...
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.
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
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.
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.
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.
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.
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.
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().
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.
Done offline - just needs a few more tests and then I'll do a commit.
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.
Testing almost complete on this. Discovered a memory leak which has been fixed. Should have a commit on the branch at some point tomorrow.
Committed to branch.
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.
Going live with 2.8.0 today hopefully - so closing this for the milestone.
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.