diff --git a/.changeset/silent-elephants-film.md b/.changeset/silent-elephants-film.md
new file mode 100644
index 0000000000..1182b687f5
--- /dev/null
+++ b/.changeset/silent-elephants-film.md
@@ -0,0 +1,5 @@
+---
+'svelte': patch
+---
+
+fix: simplify and robustify appending styles
diff --git a/packages/svelte/src/compiler/phases/3-transform/client/transform-client.js b/packages/svelte/src/compiler/phases/3-transform/client/transform-client.js
index 45e48e565e..04815dbc28 100644
--- a/packages/svelte/src/compiler/phases/3-transform/client/transform-client.js
+++ b/packages/svelte/src/compiler/phases/3-transform/client/transform-client.js
@@ -386,9 +386,7 @@ export function client_component(analysis, options) {
state.hoisted.push(b.const('$$css', b.object([b.init('hash', hash), b.init('code', code)])));
component_block.body.unshift(
- b.stmt(
- b.call('$.append_styles', b.id('$$anchor'), b.id('$$css'), options.customElement && b.true)
- )
+ b.stmt(b.call('$.append_styles', b.id('$$anchor'), b.id('$$css')))
);
}
diff --git a/packages/svelte/src/internal/client/dom/css.js b/packages/svelte/src/internal/client/dom/css.js
index 2c7efe8994..52be36aa1f 100644
--- a/packages/svelte/src/internal/client/dom/css.js
+++ b/packages/svelte/src/internal/client/dom/css.js
@@ -2,25 +2,11 @@ import { DEV } from 'esm-env';
import { queue_micro_task } from './task.js';
import { register_style } from '../dev/css.js';
-var roots = new WeakMap();
-
/**
* @param {Node} anchor
* @param {{ hash: string, code: string }} css
- * @param {boolean} [is_custom_element]
*/
-export function append_styles(anchor, css, is_custom_element) {
- // in dev, always check the DOM, so that styles can be replaced with HMR
- if (!DEV && !is_custom_element) {
- var doc = /** @type {Document} */ (anchor.ownerDocument);
-
- if (!roots.has(doc)) roots.set(doc, new Set());
- const seen = roots.get(doc);
-
- if (seen.has(css)) return;
- seen.add(css);
- }
-
+export function append_styles(anchor, css) {
// Use `queue_micro_task` to ensure `anchor` is in the DOM, otherwise getRootNode() will yield wrong results
queue_micro_task(() => {
var root = anchor.getRootNode();
@@ -29,6 +15,8 @@ export function append_styles(anchor, css, is_custom_element) {
? /** @type {ShadowRoot} */ (root)
: /** @type {Document} */ (root).head ?? /** @type {Document} */ (root.ownerDocument).head;
+ // Always querying the DOM is roughly the same perf as additionally checking for presence in a map first assuming
+ // that you'll get cache hits half of the time, so we just always query the dom for simplicity and code savings.
if (!target.querySelector('#' + css.hash)) {
const style = document.createElement('style');
style.id = css.hash;
diff --git a/packages/svelte/tests/runtime-browser/samples/mount-in-iframe/Child.svelte b/packages/svelte/tests/runtime-browser/samples/mount-in-iframe/Child.svelte
index dac93751b8..9f2fc953cf 100644
--- a/packages/svelte/tests/runtime-browser/samples/mount-in-iframe/Child.svelte
+++ b/packages/svelte/tests/runtime-browser/samples/mount-in-iframe/Child.svelte
@@ -1,10 +1,13 @@