In Chrome 150 und 155 wurden mehrere Änderungen an der HTML-in-Canvas-API eingeführt. Mit diesen Änderungen wurde auf Feedback aus der Community und von Standardisierungsorganisationen reagiert, um die Ergonomie der API zu verbessern. In diesem Blogbeitrag werden die Änderungen beschrieben und Sie erfahren, wie Sie dafür sorgen können, dass Ihre Implementierung auf dem neuesten Stand ist.
Die Updates umfassen das Umbenennen von Attributen und Methoden, die explizite Vorabzuweisung von Texturspeicher und die Aktualisierung von DOM-Synchronisierungsmodellen. Außerdem wurde der Ursprungstest für HTML in Canvas verlängert. Im Folgenden wird erläutert, was sich ändert, warum und wie Sie Ihre Codebasis aktualisieren können.
Änderungen in Chrome 150
In Chrome 150 haben wir die Argumentsignaturen in WebGL und WebGPU geändert, um Redundanz zu vermeiden und sie an moderne Grafikkonventionen anzupassen.
WebGL
Wir haben redundante Argumente (level, srcFormat, destType) aus texElementImage2D entfernt (weitere Informationen finden Sie in der WebGL-Diskussion):
// 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
Wir haben copyElementImageToTexture-Parameter in sourceDict- und destDict-Objekte standardisiert (siehe 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);
Änderungen in Chrome 155
In Chrome 155 werden weitere Verbesserungen auf Grundlage von Entwicklerfeedback eingeführt. Wir aktualisieren Methodennamen, erfordern die explizite Vorabzuweisung von Texturspeicher, unterstützen komplexe DOM-Unterbäume und entkoppeln die DOM-Synchronisierung.
WebGPU
Die WebGPU-Methode wurde von copyElementImageToTexture in drawElementImageToTexture umbenannt. Zusammen mit der Umbenennung werden die Parameterkoordinaten erweitert (sourceX, sourceWidth) und die Zielgrenzen in einem Standardobjekt size (GPUExtent3D) gruppiert:
// 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
Änderungen bei WebGL für HTML-in-Canvas lassen sich in drei Aspekte unterteilen:
- Der Methodenname ändert sich von
texElementImage2DzutexElementSubImage2D.` - Die Methodensignatur ändert sich. Vor allem werden die Argumente
xoffsetundyoffsethinzugefügt, um optional einen Offset in der Zieltextur anzugeben, an dem das Element gezeichnet werden soll. - Mit der Methode wird nicht mehr automatisch Pufferspeicher für die Zieltextur zugewiesen. Der Speicher muss explizit zugewiesen werden, bevor die API verwendet wird. Dies ähnelt dem Verhalten von
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
);
Canvas-Attribute und untergeordnete Drawable-Elemente
Wir aktualisieren die Art und Weise, wie Sie Ihr Canvas für das Rendern von HTML vorbereiten.
layoutsubtree wird in content="drawable" umbenannt
Um den HTML-Attribut-Namenskonventionen zu entsprechen, wurde das boolesche Attribut layoutsubtree für das Element <canvas> in content="drawable" umbenannt (siehe WICG Issue #169 für eine detaillierte Diskussion).
Das Attribut drawable für untergeordnete Elemente
Bisher wurden nur direkt untergeordnete Elemente eines Canvas gerendert. Um komplexe DOM-Hierarchien zu unterstützen, ohne Markup zu reduzieren, können Sie jetzt explizit das Attribut drawable zu jedem untergeordneten Element hinzufügen, das Sie unabhängig zeichnen möchten:
<!-- 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>
Ein Element mit drawable erfasst den gesamten untergeordneten Baum mit Ausnahme von verschachtelten untergeordneten Elementen, die ebenfalls drawable angeben. So können übergeordnete Container und untergeordnete Elemente wie Schaltflächen animiert und in separaten Zeichenaufrufen gezeichnet werden.
Synchronisierung von Hit-Tests
Bisher mussten Entwickler den Rückgabewert von Zeichenmethoden erfassen und an element.style.transform übergeben. Die Methode drawElementImage() gibt jetzt „void“ zurück und die Synchronisierung hängt vom Kontext ab.
2D-Kontexte: Automatische Synchronisierung
Im 2D-Canvas synchronisiert der Browser automatisch die DOM-Treffertestgrenzen und die Fokusringe des Screenreaders mit den gezeichneten Koordinaten. Sie können alle manuellen Transformations-Piping entfernen:
// 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
Wenn Sie die Geometrie manuell in 2D verwalten möchten, übergeben Sie { preserveElementGeometry: true } an drawElementImage() und wenden Sie Transformationen mit canvas.updateElementGeometry() an.
3D-Kontexte: Explizit updateElementGeometry()
Wenn Sie das DOM in WebGL- oder WebGPU-Kontexten synchronisieren möchten, erstellen Sie eine DOMMatrix-Transformation und übergeben Sie sie an 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 });
});
Versionsübergreifende Kompatibilität
Wenn Ihre Anwendung während des Übergangszeitraums Nutzer in mehreren Chrome-Versionen unterstützen muss, prüfen Sie, ob die aktualisierten Methoden in den Prototypen vorhanden sind, und passen Sie Ihre Implementierung entsprechend an.
Achten Sie darauf, dass Sie für jede Browserversion die richtigen <canvas>-Elementattribute festlegen:
// ============================================================================
// 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', '');
}
}
Sehen Sie sich für den 2D-Kontext den Rückgabewert von drawElementImage() an und prüfen Sie die Canvas-Prototypattribute, um beide Versionen zu unterstützen:
// ============================================================================
// 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 = "";
}
}
}
Verwenden Sie für WebGPU die kompatible Methodensignatur und den kompatiblen Namen:
// ============================================================================
// 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 });
}
}
Prüfen Sie die Browserkompatibilität für 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);
}
Verlängerung des Ursprungstests
Der Ursprungstest für HTML-in-Canvas wurde bis Chrome 160 verlängert. Verlängern Sie Ihr Ursprungstest-Token, damit Sie die HTML-in-Canvas-Funktion weiterhin für Ihre Nutzer anbieten können. Weitere Informationen finden Sie im Artikel zu Origin Trials.
Feedback geben
Melden Sie ein Problem im WICG-GitHub-Repository, um uns mitzuteilen, wie sich diese Änderungen auf Ihre Anwendungen auswirken. Abonnieren Sie den Newsletter für Entwickler, um über alle Neuigkeiten zu HTML in Canvas auf dem Laufenden zu bleiben.