Skip to content

Commit eaab7e4

Browse files
committed
15501: [Samples]: Write a recipe for using CSS variables in shadow DOM subtrees.
https://www.w3.org/Bugs/Public/show_bug.cgi?id=15501
1 parent d646112 commit eaab7e4

File tree

1 file changed

+66
-20
lines changed

1 file changed

+66
-20
lines changed

samples/widget-theming.html

+66-20
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
<li><a href="../spec/shadow/index.html">Shadow DOM Spec</a></li>
2121
<li><a href="../spec/templates/index.html">HTML Templates</a></li>
2222
</ul>
23-
<h1>Contacts Widget</h1>
23+
<h1>Widget Theming</h1>
2424
</header>
2525

2626
<p>After Raj's <a href="contacts-widget.html">discovery of Shadow DOM</a> triggered company-wide conversion to properly incapsulated widgets, Howard&mdash;not to be outdone&mdash;gleans another great opportunity in this change. He realizes that with the help of <a href="http://www.whatwg.org/specs/web-apps/current-work/multipage/semantics.html#attr-style-scoped">scoped stylesheets</a> and <a href="../spec/shadow/index.html">shadow DOM</a>, he can separate the general framing of the widgets from the theming code. For years now, it's been bugging him that whenever the widget's author wanted to tweak the general layout of their widgets, they would have edit the <code>/src/ui/layout/widgets.css</code> stylesheet and muck with their gubbins of code there, creating a waterfall of lines that looks like this:<p>
@@ -75,6 +75,9 @@ <h1>Contacts Widget</h1>
7575
this.element.className = 'contacts widget';
7676
var shadow = new ShadowRoot(this.element);
7777
shadow.applyAuthorStyles = true;
78+
<ins>var style = document.createElement('style');</ins>
79+
<ins>style.scoped = true;</ins>
80+
<ins>style.textContent = this.scopedStyleText;</ins>
7881
var users = shadow.appendChild(document.createElement('ul'));
7982
this.loadUsers(MAX_USERS, function(user) {
8083
var li = document.createElement('li');
@@ -85,11 +88,17 @@ <h1>Contacts Widget</h1>
8588

8689
// &hellip;
8790

88-
// Asynchronously loads users from server and invokes [callback] for each user loaded
89-
Contacts.prototype.loadUsers = function(userCount, callback)
90-
{
91-
// &hellip;
92-
}
91+
<ins>// Styles moved from /src/ui/layout/widgets.css, minus ".contacts.widget" selector.</ins>
92+
<ins>// Quasi-literals are awesome! (<a href="http://wiki.ecmascript.org/doku.php?id=harmony:quasis">http://wiki.ecmascript.org/doku.php?id=harmony:quasis</a>)</ins>
93+
<ins>Contacts.prototype.scopedStyleText = `ul {</ins>
94+
<ins>margin: 0;</ins>
95+
<ins>list-style: none;</ins>
96+
<ins>&hellip;</ins>
97+
<ins>}</ins>
98+
<ins>ul li { &hellip; }</ins>
99+
<ins>ul li img.photo { &hellip; }</ins>
100+
<ins>ul li span.n { &hellip; }</ins>
101+
<ins>&hellip;`;</ins>
93102

94103
// &hellip;
95104

@@ -98,33 +107,70 @@ <h1>Contacts Widget</h1>
98107
})();
99108
</code></pre>
100109

101-
</body>
102-
</html>
103-
104-
105-
106-
107-
108-
109-
110-
111-
112-
113-
114-
110+
<p>Whoa!&mdash;Howard sees another way to improve robustness of the layout system. The <a href="../spec/shadow/index.html#api-shadow-root-apply-author-styles"><code>applyAuthorStyles</code></a> flag (which is <code>false</code> by default) controls whether document stylesheets apply in the shadow DOM subtrees. Thus removing a line of code ensures that the widget's styles are never messed with:</p>
115111

112+
<pre class="prettyprint"><code>
113+
this.element.className = 'contacts widget';
114+
var shadow = new ShadowRoot(this.element);
115+
<del>shadow.applyAuthorStyles = true;</del>
116+
var users = shadow.appendChild(document.createElement('ul'));
117+
</code></pre>
116118

119+
<p>The celebration is cut short as Howard notices that the stylesheets from <code>/src/ui/themes/</code> directory were <em>also</em> part of the document stylesheet. As it stands, there is no way to apply theming styles to the widgets&hellip;</p>
117120

121+
<p>Or maybe there is. <a href="http://dev.w3.org/csswg/css-variables/">CSS Variables</a> to the rescue! Upon reading the spec, Howard does a little dance. Not only they allow widget theming, the <em>method</em> is such that you can specify <strong>precise</strong> and <strong>named</strong> points where theming is allowed. Digging into the Contacts widget, Howard documents the following theming points:</p>
122+
<ul>
123+
<li><strong>font</strong> -- font and size of text</li>
124+
<li><strong>color</strong> -- color, used for text and border of the user pic</li>
125+
<li><strong>background</strong> -- style of the widget background</li>
126+
</ul>
127+
<p>Howard mixes the variables into the <code>scopedStyleText</code> string:</p>
118128

129+
<pre class="prettyprint"><code>
130+
// Styles moved from /src/ui/layout/widgets.css, minus ".contacts.widget" selector.
131+
// Quasi-literals are awesome! (<a href="http://wiki.ecmascript.org/doku.php?id=harmony:quasis">http://wiki.ecmascript.org/doku.php?id=harmony:quasis</a>)
132+
Contacts.prototype.scopedStyleText = `ul {
133+
margin: 0;
134+
list-style: none;
135+
<ins>font: data(font);</ins>
136+
<ins>color: data(color);</ins>
137+
<ins>background: data(background);</ins>
138+
&hellip;
139+
}
140+
ul li { &hellip; }
141+
ul li img.photo {
142+
border: 1px solid<ins> data(color)</ins>;
143+
&hellip;';
119144

145+
</code></pre>
120146

147+
<p>Now to tweak the actual themes, starting with <code>/src/ui/themes/purple-and-black.css</code>:</p>
121148

149+
<pre class="prettyprint"><code>
122150

151+
&hellip;
123152

153+
/* Contacts Widget Theme */
124154

155+
<del>.contacts.widget ul {</del>
156+
<del>color: black;</del>
157+
<del>background: purple;</del>
158+
<del>}</del>
125159

160+
<del>.contacts.widget ul li img.photo {</del>
161+
<del>border-color: black;</del>
162+
<del>}</del>
126163

164+
<ins>.contacts.widget {</ins>
165+
<ins>data-color: black;</ins>
166+
<ins>data-background: purple;</ins>
167+
<ins>}</ins>
127168

169+
&hellip;
128170

171+
</code></pre>
129172

173+
<p>Whoohoo! No more reaching into widgets to style them! No more breakages when widget authors change their widgets and forget to update the theme! After all themes are converted, the <em>Socia1eet</em> looks and works same as before. But on the inside, the brittle layout and theming system has been replaced with a flexible, elegant, and robust solution.</p>
130174

175+
</body>
176+
</html>

0 commit comments

Comments
 (0)