Skip to content

Commit 4a99413

Browse files
authored
Merge pull request #307758 from mjbvz/dev/mjbvz/safe-crab
Try using anchor positioning for webview
2 parents 07f2e22 + d196b51 commit 4a99413

File tree

1 file changed

+31
-1
lines changed

1 file changed

+31
-1
lines changed

src/vs/workbench/contrib/webviewPanel/browser/webviewEditor.ts

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
import * as DOM from '../../../../base/browser/dom.js';
77
import { CancellationToken } from '../../../../base/common/cancellation.js';
88
import { Emitter, Event } from '../../../../base/common/event.js';
9-
import { DisposableStore, IDisposable, MutableDisposable } from '../../../../base/common/lifecycle.js';
9+
import { DisposableStore, IDisposable, MutableDisposable, toDisposable } from '../../../../base/common/lifecycle.js';
1010
import { isWeb } from '../../../../base/common/platform.js';
1111
import { generateUuid } from '../../../../base/common/uuid.js';
1212
import * as nls from '../../../../nls.js';
@@ -71,6 +71,8 @@ export class WebviewEditor extends EditorPane {
7171
this.synchronizeWebviewContainerDimensions(this.webview);
7272
}
7373
}));
74+
75+
7476
}
7577

7678
private get webview(): IOverlayWebview | undefined {
@@ -188,6 +190,26 @@ export class WebviewEditor extends EditorPane {
188190

189191
this.synchronizeWebviewContainerDimensions(input.webview);
190192
this._webviewVisibleDisposables.add(this.trackFocus(input.webview));
193+
194+
// Use CSS Anchor Positioning to automatically track position changes.
195+
// The editor element's parent acts as the CSS anchor, and the webview
196+
// container is tethered to it.
197+
// Falls back to explicit pixel positioning via layoutWebviewOverElement
198+
// when anchor positioning is not supported.
199+
if (this._element?.parentElement && CSS.supports('(top: anchor(top))')) {
200+
const anchorName = `--${this._element.id}`;
201+
this._element.parentElement.style.setProperty('anchor-name', anchorName);
202+
const container = input.webview.container;
203+
container.style.setProperty('position-anchor', anchorName);
204+
container.style.setProperty('top', 'anchor(top)');
205+
container.style.setProperty('left', 'anchor(left)');
206+
this._webviewVisibleDisposables.add(toDisposable(() => {
207+
this._element?.parentElement?.style.removeProperty('anchor-name');
208+
container.style.removeProperty('position-anchor');
209+
container.style.removeProperty('top');
210+
container.style.removeProperty('left');
211+
}));
212+
}
191213
}
192214

193215
private synchronizeWebviewContainerDimensions(webview: IOverlayWebview, dimension?: DOM.Dimension) {
@@ -203,6 +225,14 @@ export class WebviewEditor extends EditorPane {
203225
clippingContainer = this._workbenchLayoutService.getContainer(this.window, Parts.EDITOR_PART);
204226
}
205227
webview.layoutWebviewOverElement(this._element.parentElement!, dimension, clippingContainer);
228+
229+
// Re-apply CSS anchor positioning after layoutWebviewOverElement sets
230+
// explicit pixel values for top/left. This lets the browser handle
231+
// position tracking between explicit layout calls.
232+
if (CSS.supports('(top: anchor(top))') && this._element.parentElement?.style.getPropertyValue('anchor-name')) {
233+
webview.container.style.setProperty('top', 'anchor(top)');
234+
webview.container.style.setProperty('left', 'anchor(left)');
235+
}
206236
}
207237

208238
private trackFocus(webview: IOverlayWebview): IDisposable {

0 commit comments

Comments
 (0)