Skip to content
This repository was archived by the owner on Dec 17, 2021. It is now read-only.

Commit 22c600a

Browse files
author
Oxford
committedJun 4, 2020
Introducing CHTML Explainer
1 parent 201e05f commit 22c600a

File tree

3 files changed

+295
-6
lines changed

3 files changed

+295
-6
lines changed
 

‎chtml/v060/explainer.md

+289
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,289 @@
1+
# CHTML Explainer
2+
3+
## Status
4+
## TODO
5+
link to official Scoped CSS
6+
HTML parts and walls explainer
7+
list more CSS naming schemes
8+
write about frameworks
9+
10+
Often, an HTML document follows some **information hierarchy** and other pieces of **standalone functional blocks** that are related **hierarchically**. When we look, we realize that what we really end up with, or try to achieve, is a hierarchy of scopes and sub scopes, or better put, **a component architecture**. Yet, the HTML language itself is yet to have a way of defining these smaller-sized scopes. What we have, instead, is **one global document scope** for every element, every content/functional block, every stylesheet, and every script.
11+
12+
What we have:
13+
14+
What we want:
15+
16+
This state of misfit (having one **flat** scope for what is **hierarchically-related**) has been the root of much of our UI engineering problems:
17+
18+
+ **Naming Conflicts**. Since everything in HTML belongs to a global scope, IDs are often conflicting, especially where the document is being dynamically-generated. We often have to implement some auto-ID generator. And where this has to be manually done, the back-and-forth just never stops.
19+
20+
In the IDs below, we are practically having to flatten the hierarchical structure of our information, just to avoid conflicts.
21+
22+
```html
23+
<body>
24+
25+
<article id="continents">
26+
<b>Continents</b>
27+
28+
<section id="continents-europe">
29+
<b>Europe</b>
30+
31+
<div id="continents-europe-about">
32+
<b>About Europe</b>
33+
<ul>
34+
<li>Fact1</li>
35+
<li>Fact2</li>
36+
</ul>
37+
</div>
38+
39+
<div id="continents-europe-countries">
40+
<b>Countries in Europe</b>
41+
<ul>
42+
<li>Country1</li>
43+
<li>Country2</li>
44+
</ul>
45+
</div>
46+
</section>
47+
48+
<section id="continents-africa">
49+
<b>Africa</b>
50+
51+
<div id="continents-africa-about">
52+
<b>About Africa</b>
53+
<ul>
54+
<li>Fact1</li>
55+
<li>Fact2</li>
56+
</ul>
57+
</div>
58+
59+
<div id="continents-africa-countries">
60+
<b>Countries in Africa</b>
61+
<ul>
62+
<li>Country1</li>
63+
<li>Country2</li>
64+
</ul>
65+
</div>
66+
</section>
67+
68+
</article>
69+
70+
</body>
71+
```
72+
73+
+ **Clumsy Naming Conventions**. The history of modular naming schemes for HTML/CSS has not been a story of success. We have experimented with different class-naming conventions like BEM. Maybe it hasn’t been obvious, but all such experiments are pointing to a missing feature in HTML itself.
74+
+ **CSS Specificity Wars**. It always happens that we intend to style one element, we end up with many styled elements. We try a narrower selector, but then, the volatility, as everything breaks on changes in the DOM tree! This doubles with vertical specificity (targeting a specific deep descendant). Since there are no scope boundaries, we end up with verbose, often inaccurate, very inefficient and very volatile selectors.
75+
+ **Frameworks Abstractions**. Not pollyfills
76+
77+
## Doesn't the Shadow DOM Fix This?
78+
79+
No! Although the Shadow DOM provides the desired encapsulation for naming, styling and functionality, it stands far from being the ideal solution to every scoping need. This is because:
80+
+ It is impractical to use custom elements and the Shadow DOM everywhere as generic structural pieces. All we are asking for here is structural modularity without throwing the regular HTML tags away. We also do not always want total subtree encapsulation! So, the overengineering with this approach would be too unmanageable!
81+
+ Even the Shadow DOM - being the same globally-scoped document (albeit smaller) - is itself not immune to the challenge. Try creating a little large Shadow tree, and the problem with naming elements and CSS specificity wars will resurface! Yes, even here!
82+
+ While a component architecture involves both *encapsulation* and some sense of parent/child *relationships*, what the Shadow DOM would only ever do for us is encapsulation. Web Components generally isn’t thinking for a means of relationship between "components".
83+
84+
A component architecture thus remains a fundamental need in the HTML language itself. Every piece of HTML (even the Shadow tree) would stand to benefit from a more modular tree.
85+
86+
## Everything Is Pointing to a Component-Oriented HTML!
87+
88+
I propose CHTML - a new set of platform features that bring a component architecture to the HTML language. CHTML will bring the missing bits and tie the remaining nuts to make the platform everything for modern UI development.
89+
90+
### Overview
91+
92+
CHTML is a suite of four new technologies that provide for a component-based HTML. The good news is that CHTML is already obtainable today through the Web-Native project. Here, I will only describe each component with an example or two, then link to the appropriate place in the project docs to see more.
93+
94+
+ **Scoped HTML** - A new way to structure an HTML document as a hierarchy of scopes and sub scopes. Each scope establishes a new naming context for elements within its subtree - introducing *Roots* and *Scoped IDs*.
95+
96+
**Roots and Scoped IDs:**
97+
98+
```html
99+
<body>
100+
101+
<article root id="continents">
102+
<b>Continents</b>
103+
104+
<section root id="europe">
105+
<b>Europe</b>
106+
107+
<div id="about">
108+
<b>About Europe</b>
109+
<ul>
110+
<li>Fact1</li>
111+
<li>Fact2</li>
112+
</ul>
113+
</div>
114+
115+
<div id="countries">
116+
<b>Countries in Europe</b>
117+
<ul>
118+
<li>Country1</li>
119+
<li>Country2</li>
120+
</ul>
121+
</div>
122+
</section>
123+
124+
<section root id="africa">
125+
<b>Africa</b>
126+
127+
<div id="about">
128+
<b>About Africa</b>
129+
<ul>
130+
<li>Fact1</li>
131+
<li>Fact2</li>
132+
</ul>
133+
</div>
134+
135+
<div id="countries">
136+
<b>Countries in Africa</b>
137+
<ul>
138+
<li>Country1</li>
139+
<li>Country2</li>
140+
</ul>
141+
</div>
142+
</section>
143+
144+
</article>
145+
146+
</body>
147+
```
148+
149+
Note that Scoped HTML in the current implementation of CHTML is making do with the `scoped:id` attribute instead of the desired `id` attribute - just to maintain the current state of validity of HTML documents. As seen above, what we really want is have the `id` attribute scoped to its closest *root* (or the document root where no *root* context is found). This change to how IDs are interpreted will give us a system of IDs that are only contextually unique, eradicating the naming wars - all without necessarily putting pre-CHTML websites at risk as their lack of *roots* would keep their IDs associated with the document root.
150+
151+
Now, deeply Scoped IDs may even be queried from the global scope using the path notation: `#continents / #europe / #about`. This also visually follows the information hierarchy of the document, whereas the flattened `#continents-europe-about` would be leaving no clue.
152+
153+
154+
Scoped IDs are especially useful in maintaining a structural API for applications. Above, our structural API would be:
155+
156+
```html
157+
continents
158+
|- europe
159+
| |- about
160+
| |- countries
161+
|- africa
162+
|- about
163+
|- countries
164+
```
165+
166+
We also have the *ScopedHTML* API that makes it easy to traverse these structural models.
167+
168+
```js
169+
// The regular querySelector() function would give us the #article element
170+
let continents = document.querySelector('#continents');
171+
172+
// The new scopeTree DOM property would give us the structural parts
173+
let europe = continents.scopeTree.europe;
174+
let africa = continents.scopeTree.africa;
175+
176+
// Deeply-nested...
177+
let aboutAfrica = continents.scopeTree.africa.scopeTree.about;
178+
```
179+
180+
Now, much structural guesswork and inefficient DOM queries would have been avoided with a simple, bankable structural API.
181+
182+
**Scope Selectors – (Coming soon to the CHTML at Web-Native):**
183+
184+
+ The regular ID selector `#` will now respect scope boudaries, without necessarily breaking pre-CHTML documents as these have only one scope.
185+
+ The forward slash `/` will be used to denote a scope boundary.
186+
+ Two new query selectors (`scopeSelector()` and `scopeSelectorAll()`) will now be created, or the regular `querySelector()` and `querySelectorAll()` DOM methods will now be upgraded, to support Scope Selectors.
187+
188+
[Read the full Scoped HTML docs](https://docs.web-native.dev/chtml/v060/specs/scoped-html)
189+
190+
+ **Scoped CSS** - Stylesheets that are scoped to their containing element – actually, the return of scoped CSS redesigned to support *Scope Selectors*.
191+
192+
```html
193+
<div root class="article">
194+
<style scoped>
195+
:root {
196+
color: red;
197+
}
198+
.wrapper {}
199+
#title {
200+
font-weight: bold;
201+
}
202+
#content {
203+
font-weight: normal;
204+
}
205+
</style>
206+
<div class="wrapper">
207+
<div scoped:id="title"></div>
208+
<div scoped:id="content"></div>
209+
</div>
210+
</div>
211+
```
212+
213+
[Read the full Scoped CSS docs](https://docs.web-native.dev/chtml/v060/specs/scoped-css)
214+
215+
+ **Scoped JS** - Scripts that run within the scope of their containing element, with automatic observability inbuilt. Scoped JS is as fundamentally different from regular scripts as module scripts are, this time, to serve as everything for presentational logic.
216+
217+
We define a *scoped script* with the special `text/scoped-js` MIME type. (What I really would love is simply using the `scoped` Boolean attribute, as in the case of scoped CSS.)
218+
219+
```html
220+
<div id="alert">
221+
<div class="message">This task is now complete!</div>
222+
<div class="exit" title="Close this message.">X</div>
223+
<script type="text/scoped-js">
224+
this.querySelector('.exit').addEventListener('click', () => {
225+
this.remove();
226+
});
227+
</script>
228+
</div>
229+
```
230+
231+
The awesome thing about scoped scripts is that they are isolated from the global document scope with the `this` reference bound to their containing element.
232+
233+
It is also possible to bind external values to a scoped script, usually a data object from an application.
234+
235+
```js
236+
let alertEl = document.querySelector('#alert');
237+
alertEl.bind({
238+
message: 'This task is now complete!',
239+
});
240+
```
241+
```html
242+
<div id="alert">
243+
<div class="message"></div>
244+
<div class="exit" title="Close this message.">X</div>
245+
<script type="text/scoped-js">
246+
let messageEl = this.querySelector('.message');
247+
messageEl.innerHTML = message;
248+
</script>
249+
</div>
250+
```
251+
252+
Scoped JS also features automatic obervability that keeps the UI in sync with bound values.
253+
254+
[Read the full Scoped JS docs](https://docs.web-native.dev/chtml/v060/specs/scoped-js)
255+
256+
+ **HTML Transport** - An import/export system that lets us define, extend, and distribute HTML components – now, the platform itself as an UI component framework.
257+
258+
HTML Transport uses existing HTML features to make a feature-rich system of defining and reusing HTML snippets.
259+
260+
261+
```html
262+
<head>
263+
<template is="html-bundle">
264+
265+
<div namespace="export/one"></div>
266+
<div namespace="export/two"></div>
267+
268+
</template>
269+
</head>
270+
```
271+
272+
These *exports* easily importable and can be placed anywhere in the main document.
273+
274+
```html
275+
<body>
276+
<html-import namespace="export/one"></html-import>
277+
<html-import namespace="export/two"></html-import>
278+
</body>
279+
```
280+
281+
And in a script, we could programmatically import them.
282+
283+
```js
284+
let import1 = HTMLTransport.import('export/one');
285+
```
286+
287+
Taking things beyond imports and exports, HTML Transport sets a new bar in code organization, extensibility and composability.
288+
289+
[Read the full HTML Transport docs](https://docs.web-native.dev/chtml/v060/specs/html-transport)

‎chtml/v060/specs/README.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ Here is the suite of specifications and tooling that lets you build elegant user
88
While all four technologies fit together seamlessly, they can also be used independently.
99

1010
### Scoped HTML
11-
Scoped HTML follows a semantic markup pattern that lets us create an HTML document as a hierachy of smaller-sized scopes. Each scope represents a *root* or reference point for naming elements within its subtree.
11+
Scoped HTML follows a semantic markup pattern that lets us create an HTML document as a hierachy of smaller-sized scopes. Each scope establishes a new naming context for elements within its subtree.
1212

1313
A scope is designated on an element by simply adding the *Boolean* `root` attribute. This creates a context for implementing scoped IDs.
1414

@@ -130,7 +130,7 @@ If we wanted to style the structural parts of deeply nested scopes, a path-based
130130
#content {
131131
font-weight: normal;
132132
}
133-
#user:hover #user/name {
133+
#user:hover / #name {
134134
font-weight: bold;
135135
}
136136
</style>

‎play-ui/README.md

+4-4
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,12 @@ $(el1).on('doubletap', e => {
1616
});
1717
```
1818

19-
PlayUI's core functions may also be imported as individually to use in a project.
19+
PlayUI's core functions may also be imported individually to use in a project.
2020

2121
```js
22-
import {on} from '@web-native-js/play-ui/src/evt/index.js';
23-
import {play} from '@web-native-js/play-ui/src/ani/index.js';
24-
import {cssAsync} from '@web-native-js/play-ui/src/css/index.js';
22+
import on from '@web-native-js/play-ui/src/evt/on.js';
23+
import play from '@web-native-js/play-ui/src/ani/play.js';
24+
import cssAsync from '@web-native-js/play-ui/src/css/cssAsync.js';
2525

2626

2727
on(el1, 'doubletap', e => {

0 commit comments

Comments
 (0)
This repository has been archived.