Chrome 150 e 155 hanno introdotto diverse modifiche all'API HTML in Canvas. Queste modifiche hanno risposto ai feedback della community e degli standard con l'obiettivo di migliorare l'ergonomia dell'API. Questo post del blog descrive le modifiche e come puoi assicurarti che la tua implementazione sia aggiornata.
Gli aggiornamenti includono la ridenominazione di attributi e metodi, che richiedono la pre-allocazione esplicita della memoria delle texture e l'aggiornamento dei modelli di sincronizzazione DOM. Inoltre, la prova dell'origine HTML in Canvas è stata estesa. Di seguito viene spiegato cosa sta cambiando, perché e come aggiornare la tua base di codice.
Modifiche in Chrome 150
In Chrome 150, abbiamo modificato le firme degli argomenti in WebGL e WebGPU per eliminare la ridondanza e allinearle alle convenzioni grafiche moderne.
WebGL
Abbiamo rimosso gli argomenti ridondanti (level, srcFormat, destType) da texElementImage2D
(per maggiori dettagli, consulta la discussione su WebGL):
// Old implementation (Chrome < 150)
const level = 0;
const internalFormat = gl.RGBA;
const srcFormat = gl.RGBA;
const destType = gl.UNSIGNED_BYTE;
gl.texElementImage2D(
gl.TEXTURE_2D,
level,
internalFormat,
srcFormat,
destType,
element
);
// New implementation (from Chrome 150)
const internalFormat = gl.RGBA8;
gl.texElementImage2D(gl.TEXTURE_2D, internalFormat, element);
WebGPU
Abbiamo standardizzato i parametri copyElementImageToTexture negli oggetti sourceDict e
destDict (vedi GPUWeb PR#6250):
// Old implementation (Chrome < 150)
GPUQueue.copyElementImageToTexture(
element,
width,
height,
{ texture: texture }
);
// New implementation (from Chrome 150)
const sourceDict = { source: element };
const destDict = {
destination: { texture: texture },
width: width,
height: height
};
GPUQueue.copyElementImageToTexture(sourceDict, destDict);
Modifiche in Chrome 155
Chrome 155 introduce ulteriori perfezionamenti basati sui feedback degli sviluppatori. Stiamo aggiornando i nomi dei metodi, richiedendo la pre-allocazione esplicita della memoria delle texture, supportando sottoalberi DOM complessi e disaccoppiando la sincronizzazione DOM.
WebGPU
Il metodo WebGPU è stato rinominato da copyElementImageToTexture a
drawElementImageToTexture. Oltre al cambio di nome, le coordinate dei parametri vengono
estese (sourceX, sourceWidth) e i limiti della destinazione vengono raggruppati in un
oggetto size (GPUExtent3D) standard:
// BEFORE (Chrome 150)
const sourceDict = {
source: myElement,
sx: 0,
sy: 0,
swidth: 100,
sheight: 100
};
const destDict = {
destination: { texture: myTexture },
width: 300,
height: 200
};
queue.copyElementImageToTexture(sourceDict, destDict);
// AFTER (Chrome 155+)
const sourceDict = {
source: myElement,
sourceX: 0,
sourceY: 0,
sourceWidth: 100,
sourceHeight: 100
};
const destDict = {
texture: myTexture,
size: { width: 300, height: 200 }
};
queue.drawElementImageToTexture(sourceDict, destDict);
WebGL
Esistono tre aspetti delle modifiche a WebGL per HTML in Canvas:
- Il nome del metodo cambia da
texElementImage2DatexElementSubImage2D.` - La firma del metodo cambia; in particolare, aggiunge gli argomenti
xoffseteyoffsetper consentire facoltativamente di specificare un offset nella texture di destinazione in cui disegnare l'elemento. - Il metodo non alloca più automaticamente lo spazio di archiviazione buffer per la
texture di destinazione; lo spazio di archiviazione deve essere allocato esplicitamente prima di
utilizzare l'API. Questo comportamento è simile a quello di
texSubImage2D.
// 1. Capture natural layout size of the element
const elementImage = canvas.captureElementImage(element);
// 2. Pre-allocate texture backing once (or when element resizes)
gl.bindTexture(gl.TEXTURE_2D, texture);
gl.texImage2D(
gl.TEXTURE_2D,
0,
gl.RGBA8,
Math.ceil(elementImage.width),
Math.ceil(elementImage.height),
0,
gl.RGBA,
gl.UNSIGNED_BYTE,
null // null reserves VRAM without uploading pixels
);
// 3. Upload DOM into pre-allocated VRAM
gl.texElementSubImage2D(
gl.TEXTURE_2D,
0, // level
0, // xoffset
0, // yoffset
element // pass DOM element
);
Attributi Canvas ed elementi secondari disegnabili
Stiamo aggiornando la modalità di preparazione del canvas per il rendering HTML.
Ridenominazione di layoutsubtree in content="drawable"
Per essere in linea con le convenzioni di denominazione degli attributi HTML, l'attributo booleano layoutsubtree
dell'elemento <canvas> è stato rinominato in content="drawable" (vedi
WICG Issue #169 per
una discussione dettagliata).
L'attributo drawable per i discendenti
In precedenza, venivano visualizzati solo gli elementi secondari diretti di un canvas. Per supportare gerarchie DOM complesse senza appiattire il markup, ora puoi aggiungere esplicitamente l'attributo drawable a qualsiasi elemento discendente che intendi disegnare in modo indipendente:
<!-- BEFORE -->
<canvas layoutsubtree>
<div id="badge">
<h2>Player Stats</h2>
<button id="actionBtn">Equip</button>
</div>
</canvas>
<!-- AFTER (Chrome 155+) -->
<canvas content="drawable">
<!-- Subtree A (Body and heading) -->
<div id="badge" drawable>
<h2>Player Stats</h2>
<!-- Subtree B (Excluded from Subtree A; drawn and animated independently) -->
<button id="actionBtn" drawable>Equip</button>
</div>
</canvas>
Un elemento con drawable acquisisce l'intero sottoalbero tranne i discendenti
nidificati che specificano anche drawable. In questo modo, i contenitori principali e gli elementi secondari come i pulsanti possono essere animati e disegnati in chiamate di disegno separate.
Sincronizzazione dei test di successo
In precedenza, gli sviluppatori dovevano acquisire il valore restituito dai metodi di disegno e
trasferirlo a element.style.transform. Il metodo drawElementImage() ora restituisce
void e la sincronizzazione dipende dal contesto.
Contesti 2D: sincronizzazione automatica
Nel canvas 2D, il browser sincronizza automaticamente i limiti di test di hit del DOM e gli anelli di messa a fuoco dello screen reader con le coordinate disegnate. Puoi rimuovere tutte le pipe di trasformazione manuale:
// BEFORE
const transform = ctx.drawElementImage(element, x, y);
element.style.transform = transform.toString();
// AFTER (Chrome 155+)
ctx.drawElementImage(element, x, y);
// No style update needed: position & hit-testing sync automatically
Per gestire manualmente la geometria in 2D, passa { preserveElementGeometry: true } a
drawElementImage() e applica le trasformazioni utilizzando canvas.updateElementGeometry().
Contesti 3D: espliciti updateElementGeometry()
Per sincronizzare il DOM nei contesti WebGL o WebGPU, crea una trasformazione DOMMatrix e passala a canvas.updateElementGeometry():
canvas.addEventListener('paint', () => {
// 1. Upload element snapshot to GPU texture
device.queue.drawElementImageToTexture({ source: element }, { texture });
// 2. Render 3D scene...
drawScene();
// 3. Construct transform matrix as needed
const canvasTransform = new DOMMatrix().translate(x, y);
// 4. Update DOM hit-testing and accessibility bounding boxes
canvas.updateElementGeometry(element, { canvasTransform });
});
Compatibilità tra versioni
Se la tua applicazione deve supportare gli utenti in più versioni di Chrome durante il periodo di transizione, verifica la presenza dei metodi aggiornati nei prototipi e adatta l'implementazione di conseguenza.
Assicurati di impostare gli attributi corretti dell'elemento <canvas> per ogni versione del browser:
// ============================================================================
// Cross-version canvas markup
// ============================================================================
if (!canvas.hasAttribute('content') && !canvas.hasAttribute('layoutsubtree')) {
if ('content' in HTMLCanvasElement.prototype) {
// Chrome 155+ (New standardized attribute)
canvas.setAttribute('content', 'drawable');
} else {
// Chrome < 155 (Legacy boolean attribute)
canvas.setAttribute('layoutsubtree', '');
}
}
Per il contesto 2D, esamina il valore restituito di drawElementImage() e controlla
gli attributi del prototipo del canvas per supportare entrambe le versioni:
// ============================================================================
// Cross-version 2D drawing & synchronization
// ============================================================================
function draw2DElement(ctx, element, x, y) {
// Execute the 2D draw call
const result = ctx.drawElementImage(element, x, y);
if (result !== undefined && typeof result?.toString === 'function') {
// Chrome < 155: drawElementImage returned a DOMMatrix
// Requires manual transform piping to align DOM hit-test bounds:
element.style.transform = result.toString();
} else {
// Chrome 155+: drawElementImage returns void / undefined
// The browser automatically aligns DOM positioning, clicks, and a11y bounds!
// If you previously had element.style.transform logic here, clear it:
if (element.style.transform) {
element.style.transform = "";
}
}
}
Per WebGPU, utilizza la firma e il nome del metodo compatibili:
// ============================================================================
// WebGPU cross-version support
// ============================================================================
if ('drawElementImageToTexture' in GPUQueue.prototype) {
// Chrome 155+ (Latest implementation)
queue.drawElementImageToTexture(
{ source: element, sourceX: 0, sourceY: 0, sourceWidth: w, sourceHeight: h },
{ texture: myTexture, size: { width: w, height: h } }
);
} else if (typeof queue.copyElementImageToTexture === "function") {
// Chrome 150 - 154: Try the Chrome 150+ dictionary signature first,
// then fall back to the Chrome < 150 signature
try {
queue.copyElementImageToTexture(
{ source: element },
{ destination: { texture: myTexture }, width: w, height: h }
);
} catch (err) {
// Chrome < 150
queue.copyElementImageToTexture(element, { texture: myTexture });
}
}
Assicurati di controllare la compatibilità del browser per WebGL:
// ============================================================================
// WebGL cross-version support
// ============================================================================
if ('texElementSubImage2D' in WebGL2RenderingContext.prototype) {
// Chrome 155+ (Explicit pre-allocation + sub-image)
gl.texElementSubImage2D(gl.TEXTURE_2D, 0, 0, 0, element);
} else if (gl.texElementImage2D && gl.texElementImage2D.length === 3) {
// Chrome 150-154 (3-argument signature)
gl.texElementImage2D(gl.TEXTURE_2D, gl.RGBA8, element);
} else if (gl.texElementImage2D) {
// Chrome < 150 (6-argument signature)
gl.texElementImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, element);
}
Estensione della prova dell'origine
La prova dell'origine HTML in Canvas è stata estesa fino a Chrome 160. Assicurati di rinnovare il token di prova dell'origine per continuare a offrire la funzionalità HTML in Canvas ai tuoi utenti. Per maggiori dettagli, consulta l'articolo sulla prova dell'origine.
Condividi il tuo feedback
Comunicaci come funzionano questi aggiornamenti nelle tue applicazioni segnalando un problema nel repository GitHub di WICG. Iscriviti alla newsletter per sviluppatori per rimanere al corrente di tutte le novità relative a HTML in Canvas.