1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
|
---
title: CSS Painting API
slug: Web/API/CSS_Painting_API
tags:
- API
- CSS
- CSS Paint API
- Houdini
- NeedsTranslation
- Painting
- Reference
- TopicStub
translation_of: Web/API/CSS_Painting_API
---
<div>{{DefaultAPISidebar("CSS Painting API")}}</div>
<p>The CSS Painting API — part of the <a href="/en-US/docs/Web/Houdini">CSS Houdini</a> umbrella of APIs — allows developers to write JavaScript functions that can draw directly into an element's background, border, or content.</p>
<h2 id="Concepts_and_usage">Concepts and usage</h2>
<p>Essentially, the CSS Painting API contains functionality allowing developers to create custom values for {{cssxref('paint', 'paint()')}}, a CSS <code><a href="/en-US/docs/Web/CSS/image"><image></a></code> function. You can then apply these values to properties like {{cssxref("background-image")}} to set complex custom backgrounds on an element.</p>
<p>For example:</p>
<pre class="brush: css notranslate">aside {
background-image: paint(myPaintedImage);
}</pre>
<p>The API defines {{domxref('PaintWorklet')}}, a {{domxref('worklet')}} that can be used to programmatically generate an image that responds to computed style changes. To find out more about how this is used, consult <a href="/en-US/docs/Web/API/CSS_Painting_API/Guide">Using the CSS Painting API</a>.</p>
<h2 id="Interfaces">Interfaces</h2>
<dl>
<dt>{{domxref('PaintWorklet')}}</dt>
<dd>Programmatically generates an image where a CSS property expects a file. Access this interface through <a href="https://developer.mozilla.org/en-US/docs/Web/API/CSS/paintWorklet" title="paintWorklet is a static, read-only property of the CSS interface that provides access to the PaintWorklet, which programmatically generates an image where a CSS property expects a file. "><code>CSS.paintWorklet</code></a>.</dd>
<dt>{{domxref('PaintWorkletGlobalScope')}}</dt>
<dd>The global execution context of the <code>paintWorklet</code>.</dd>
<dt>{{domxref('PaintRenderingContext2D')}}</dt>
<dd>
<p>Implements a subset of the <a href="/en-US/docs/Web/API/CanvasRenderingContext2D">CanvasRenderingContext2D API</a>. It has an output bitmap that is the size of the object it is rendering to.</p>
</dd>
<dt>{{domxref('PaintSize')}}</dt>
<dd>Returns the read-only values of the output bitmap's width and height.</dd>
</dl>
<h2 id="Dictionaries">Dictionaries</h2>
<dl>
<dt>{{domxref('PaintRenderingContext2DSettings')}}</dt>
<dd>A dictionary providing a subset of <a href="/en-US/docs/Web/API/CanvasRenderingContext2D">CanvasRenderingContext2D</a> settings.</dd>
</dl>
<h2 id="Examples" name="Examples">Examples</h2>
<p>To draw directly into an element's background using JavaScript in our CSS, we define a paint worklet using the <code><a href="https://developer.mozilla.org/en-US/docs/Web/API/PaintWorklet/registerPaint">registerPaint()</a></code> function, tell the document to include the worklet using the paintWorklet addModule() method, then include the image we created using the CSS <code><a href="https://developer.mozilla.org/en-US/docs/Web/CSS/paint()" title="The documentation about this has not yet been written; please consider contributing!"><code>paint()</code></a></code> function.</p>
<p>We create our PaintWorklet called 'hollowHighlights' using the <code><a href="https://developer.mozilla.org/en-US/docs/Web/API/PaintWorklet/registerPaint">registerPaint()</a></code> function:</p>
<pre class="brush: js notranslate">registerPaint('hollowHighlights', class {
static get inputProperties() { return ['--boxColor']; }
static get inputArguments() { return ['*','<length>']; }
static get contextOptions() { return {alpha: true}; }
paint(ctx, size, props, args) {
const x = 0;
const y = size.height * 0.3;
const blockWidth = size.width * 0.33;
const blockHeight = size.height * 0.85;
const theColor = props.get( '--boxColor' );
const strokeType = args[0].toString();
const strokeWidth = parseInt(args[1]);
console.log(theColor);
if ( strokeWidth ) {
ctx.lineWidth = strokeWidth;
} else {
ctx.lineWidth = 1.0;
}
if ( strokeType === 'stroke' ) {
ctx.fillStyle = 'transparent';
ctx.strokeStyle = theColor;
} else if ( strokeType === 'filled' ) {
ctx.fillStyle = theColor;
ctx.strokeStyle = theColor;
} else {
ctx.fillStyle = 'none';
ctx.strokeStyle = 'none';
}
ctx.beginPath();
ctx.moveTo( x, y );
ctx.lineTo( blockWidth, y );
ctx.lineTo( blockWidth + blockHeight, blockHeight );
ctx.lineTo( x, blockHeight );
ctx.lineTo( x, y );
ctx.closePath();
ctx.fill();
ctx.stroke();
for (let i = 0; i < 4; i++) {
let start = i * 2;
ctx.beginPath();
ctx.moveTo( blockWidth + (start * 10) + 10, y);
ctx.lineTo( blockWidth + (start * 10) + 20, y);
ctx.lineTo( blockWidth + (start * 10) + 20 + blockHeight, blockHeight);
ctx.lineTo( blockWidth + (start * 10) + 10 + blockHeight, blockHeight);
ctx.lineTo( blockWidth + (start * 10) + 10, y);
ctx.closePath();
ctx.fill();
ctx.stroke();
}
}
});</pre>
<div id="hollowExample">
<p>We then include the paintWorklet:</p>
<pre class="brush: html hidden notranslate"><ul>
<li>item 1</li>
<li>item 2</li>
<li>item 3</li>
<li>item 4</li>
<li>item 5</li>
<li>item 6</li>
<li>item 7</li>
<li>item 8</li>
<li>item 9</li>
<li>item 10</li>
<li>item 11</li>
<li>item 12</li>
<li>item 13</li>
<li>item 14</li>
<li>item 15</li>
<li>item 16</li>
<li>item 17</li>
<li>item 18</li>
<li>item 19</li>
<li>item 20</li>
</ul></pre>
<pre class="brush: js notranslate"> CSS.paintWorklet.addModule('https://mdn.github.io/houdini-examples/cssPaint/intro/worklets/hilite.js');
</pre>
<p>Then we can use the {{cssxref('<image>')}} with the CSS {{cssxref('paint()')}} function:</p>
<pre class="brush: css notranslate">li {
--boxColor: hsla(55, 90%, 60%, 1.0);
background-image: paint(hollowHighlights, stroke, 2px);
}
li:nth-of-type(3n) {
--boxColor: hsla(155, 90%, 60%, 1.0);
background-image: paint(hollowHighlights, filled, 3px);
}
li:nth-of-type(3n+1) {
--boxColor: hsla(255, 90%, 60%, 1.0);
background-image: paint(hollowHighlights, stroke, 1px);
}</pre>
</div>
<p>We've included a custom property in the selector block defining a boxColor. Custom properties are accessible to the PaintWorklet.</p>
<p>{{EmbedLiveSample("hollowExample", 300, 300)}}</p>
<h2 id="Specifications">Specifications</h2>
<table class="standard-table">
<tbody>
<tr>
<th scope="col">Specification</th>
<th scope="col">Status</th>
<th scope="col">Comment</th>
</tr>
<tr>
<td>{{SpecName('CSS Painting API')}}</td>
<td>{{Spec2('CSS Painting API')}}</td>
<td>Initial definition.</td>
</tr>
</tbody>
</table>
<h2 id="Browser_compatibility">Browser compatibility</h2>
<p>See the browser compatibility data for each CSS Painting API Interfaces.</p>
<h2 id="See_Also">See Also</h2>
<ul>
<li><a href="/en-US/docs/Web/Houdini/Learn/CSS_Painting_API">Using the CSS Painting API</a></li>
<li><a href="/en-US/docs/Web/CSS_Typed_OM">CSS Typed Object Model API</a></li>
<li><a href="/en-US/docs/Web/Houdini">CSS Houdini</a></li>
</ul>
|