-
Notifications
You must be signed in to change notification settings - Fork 6
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
First draft #17
First draft #17
Changes from 1 commit
cc407e3
7ab13e4
e1e5a96
01c8eb8
df6c73e
b6a6c30
2697017
2464877
69f9aa5
4dfae65
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,205 @@ | ||
## An attempt to find an interoperable CSSinJS format. | ||
## Interoperable CSSinJS format. | ||
|
||
The biggest issue at scale we currently have with all the CSSinJS implementations is that they are not sharable without the runtime. | ||
The biggest issue at scale we currently have with all CSSinJS implementations is that they are not sharable without the runtime. | ||
|
||
If we could find a format that is fast an easy to parse and supports all needs of current CSSinJS implementations, it could become a de facto standard for exported CSSinJS. | ||
We can define a format that is easy to parse and supports all the needs of the current CSSinJS implementations on top of CSS. | ||
|
||
It could be similar to how CommonJS and ES3 are currently the standard for sharing JavaScript modules on npm. | ||
Package maintainers will be able to publish JavaScript files to NPM with this format inside instead of plain CSS. | ||
|
||
## First draft | ||
|
||
Format is optimized for parsing in JavaScript, not for human readability. | ||
|
||
### Constants | ||
|
||
#### Markers | ||
|
||
Examples are using constant names instead of values for readability. The end format will use the values. | ||
|
||
```js | ||
const RULE_START = 0 | ||
const RULE_TYPE = 1 | ||
const RULE_END = 2 | ||
const SELECTOR = 3 | ||
const SCOPED = 4 | ||
const PROPERTY = 5 | ||
const VALUE = 6 | ||
const REF = 7 | ||
const CONDITION = 8 | ||
``` | ||
|
||
#### Rule types | ||
|
||
Copied from https://wiki.csswg.org/spec/cssom-constants | ||
|
||
``` | ||
1 STYLE_RULE CSSOM | ||
2 CHARSET_RULE CSSOM | ||
3 IMPORT_RULE CSSOM | ||
4 MEDIA_RULE CSSOM | ||
5 FONT_FACE_RULE CSSOM | ||
6 PAGE_RULE CSSOM | ||
7 KEYFRAMES_RULE css3-animations | ||
8 KEYFRAME_RULE css3-animations | ||
9 MARGIN_RULE CSSOM | ||
10 NAMESPACE_RULE CSSOM | ||
11 COUNTER_STYLE_RULE css3-lists | ||
12 SUPPORTS_RULE css3-conditional | ||
13 DOCUMENT_RULE css3-conditional | ||
14 FONT_FEATURE_VALUES_RULE css3-fonts | ||
15 VIEWPORT_RULE css-device-adapt | ||
16 REGION_STYLE_RULE proposed for css3-regions | ||
17 CUSTOM_MEDIA_RULE mediaqueries | ||
``` | ||
|
||
### Global tag selector | ||
|
||
```css | ||
body { | ||
color: red | ||
} | ||
``` | ||
|
||
```js | ||
[ | ||
[RULE_START], | ||
[RULE_TYPE, 1], | ||
[SELECTOR, 'body'], | ||
[PROPERTY, 'color'], | ||
[VALUE, 'red'] | ||
[RULE_END] | ||
] | ||
``` | ||
|
||
### Multiple classes in one selector | ||
|
||
```css | ||
body, .foo { | ||
color: red | ||
} | ||
``` | ||
|
||
```js | ||
[ | ||
[RULE_START], | ||
[RULE_TYPE, 1], | ||
[SELECTOR, 'body'], | ||
[SELECTOR, '.foo'], | ||
[PROPERTY, 'color'], | ||
[VALUE, 'red'] | ||
[RULE_END] | ||
] | ||
``` | ||
|
||
### Multiple values | ||
|
||
```css | ||
.foo { | ||
border: 1px solid red, 1px solid green | ||
} | ||
``` | ||
|
||
```js | ||
[ | ||
[RULE_START], | ||
[RULE_TYPE, 1], | ||
[SELECTOR, '.foo'], | ||
[PROPERTY, 'border'], | ||
[VALUE, '1px solid red'], | ||
[VALUE, '1px solid green'], | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I like the recognition of list-valued properties here, and the representation as distinct values. A+. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What I personally dislike is the use of shortcuts. I think we need to come up with a format completely without shortcuts. |
||
[RULE_END] | ||
] | ||
``` | ||
|
||
### Fallbacks | ||
|
||
```css | ||
.foo { | ||
color: red; | ||
color: linear-gradient(to right, red 0%, green 100%); | ||
} | ||
``` | ||
|
||
```js | ||
[ | ||
[RULE_START], | ||
[RULE_TYPE, 1], | ||
[SELECTOR, '.foo'], | ||
[PROPERTY, 'color'], | ||
[VALUE, 'red'], | ||
[PROPERTY, 'color'], | ||
[VALUE, 'linear-gradient(to right, red 0%, green 100%)'], | ||
[RULE_END] | ||
] | ||
``` | ||
|
||
### Media rules | ||
|
||
```css | ||
@media all { | ||
.foo { | ||
color: red; | ||
} | ||
} | ||
``` | ||
|
||
```js | ||
[ | ||
[RULE_START], | ||
[RULE_TYPE, 4], | ||
[CONDITION, 'all'], | ||
[RULE_START], | ||
[RULE_TYPE, 1], | ||
[SELECTOR, '.foo'], | ||
[PROPERTY, 'color'], | ||
[VALUE, 'red'], | ||
[RULE_END], | ||
[RULE_END] | ||
] | ||
``` | ||
|
||
### Nesting | ||
|
||
```css | ||
.foo { | ||
color: red; | ||
&:hover { | ||
color: green; | ||
} | ||
} | ||
``` | ||
|
||
```js | ||
[ | ||
[RULE_START], | ||
[RULE_TYPE, 1], | ||
[SELECTOR, '.foo'], | ||
[PROPERTY, 'color'], | ||
[VALUE, 'red'], | ||
[RULE_START], | ||
[SELECTOR, REF, ':hover'], | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This structure doesn't seem to let you distinguish between Maybe after the That is, There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. true that, maybe a spacer marker?
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. How would the selector (I'm trying to push you to a consistent, extensible selector representation that minimizes the amount of hand-parsing end-users have to do, which maximizes the likelihood that they'll parse things correctly.) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. &.foo.bar .baz -> [SELECTOR, REF, '.foo', '.bar', SPACE, '.baz'] bad idea?
Totally appreciate that! |
||
[PROPERTY, 'color'], | ||
[VALUE, 'red'], | ||
[RULE_END], | ||
[RULE_END] | ||
] | ||
``` | ||
|
||
### Scoped class name | ||
|
||
```css | ||
.foo-123456 { | ||
color: red | ||
} | ||
``` | ||
|
||
```js | ||
[ | ||
[RULE_START], | ||
[RULE_TYPE, 1], | ||
[SELECTOR, SCOPED, '.foo'], | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Similarly, is there some restriction of one-class-per-selector in effect here? Otherwise, you can't tell what's supposed to be scoped; or are all the classes meant to be? Less sure what the right answer would look like here, tho. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I was thinking that we can only have one class here, there is an example with multiple classes in one selector. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. so if we need multiple classes in one selector it would looke like this:
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That indicates a selector like There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah good point! There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What about this? All scoped: .foo.bar -> [SELECTOR, SCOPED, '.foo', '.bar'] There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Another thought in regard of SCOPED. Actually if we want to let the consumers generate selectors, this thing is just a NAME. We need a concept of a named rule: Not scoped selector: .foo -> [SELECTOR, '.foo'] A rule may have just one name, but may have multiple selectors and a name. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah, that makes sense. So a "name" is gonna be auto-generated with some prefix, to help ensure there are no accidental name clashes, right? That's why "scoped" rules only need a single class - that's basically by definition. In that case, yeah, a separate command that is morally equivalent to a selector, but should only appear at most once per rule, sounds best. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
This is one possibility, though I was thinking to let consumers generate them. Generating prefixes at build time on the publisher side would mean we need to ensure the uniqueness for the entire world. Leaving it up to consumer in a specific project will reduce the probability for clashes to the project context. Also there are multiple ways to generate an id, counter based is the most efficient, hashes - not so much. |
||
[PROPERTY, 'color'], | ||
[VALUE, 'red'] | ||
[RULE_END] | ||
] | ||
``` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Merge this value into the previous token (
[RULE_START 1]
); no need to wait until the second token of the rule to find out what type of rule it is. Then you can dropRULE_TYPE
entirely.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep, thought about that too.