From 8a57953f2ad5606f1f9fed986a701bd6ffc1626b Mon Sep 17 00:00:00 2001 From: Mauro Mura Date: Wed, 10 Dec 2025 16:23:48 +0100 Subject: [PATCH 1/2] Refactor CSS handling to include imports --- apps/theming/lib/Controller/ThemingController.php | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/apps/theming/lib/Controller/ThemingController.php b/apps/theming/lib/Controller/ThemingController.php index 8bb9841ae5596..0aa4707240543 100644 --- a/apps/theming/lib/Controller/ThemingController.php +++ b/apps/theming/lib/Controller/ThemingController.php @@ -408,11 +408,15 @@ public function getThemeStylesheet(string $themeId, bool $plain = false, bool $w // from the rest of the CSS. $customCssWithoutComments = preg_replace('!/\*.*?\*/!s', '', $customCss); $customCssWithoutComments = preg_replace('!//.*!', '', $customCssWithoutComments); - preg_match_all('/(@[^{]+{(?:[^{}]*|(?R))*})/', $customCssWithoutComments, $atRules); - $atRulesCss = implode('', $atRules[0]); - $scopedCss = preg_replace('/(@[^{]+{(?:[^{}]*|(?R))*})/', '', $customCssWithoutComments); + preg_match_all('/(@import[^;]+;)/', $customCssWithoutComments, $imports); + $importsCss = implode('', $imports[0]); + $customCssWithoutImports = preg_replace('/(@import[^;]+;)/', '', $customCssWithoutComments); - $css = "$atRulesCss [data-theme-$themeId] { $variables $scopedCss }"; + preg_match_all('/(@[^{]+{(?:[^{}]*|(?R))*})/', $customCssWithoutImports, $atRules); + $atRulesCss = implode('', $atRules[0]); + $scopedCss = preg_replace('/(@[^{]+{(?:[^{}]*|(?R))*})/', '', $customCssWithoutImports); + + $css = "$importsCss $atRulesCss [data-theme-$themeId] { $variables $scopedCss }"; } try { From c89b523688f1de0d8430a4d3942ac032f0b62b25 Mon Sep 17 00:00:00 2001 From: Mauro Mura Date: Thu, 11 Dec 2025 08:42:18 +0100 Subject: [PATCH 2/2] Enhance CSS handling in ThemingController Added extraction of @import and @-rules from custom CSS. --- apps/theming/lib/Controller/ThemingController.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/apps/theming/lib/Controller/ThemingController.php b/apps/theming/lib/Controller/ThemingController.php index 0aa4707240543..66ad40b3b244e 100644 --- a/apps/theming/lib/Controller/ThemingController.php +++ b/apps/theming/lib/Controller/ThemingController.php @@ -408,10 +408,14 @@ public function getThemeStylesheet(string $themeId, bool $plain = false, bool $w // from the rest of the CSS. $customCssWithoutComments = preg_replace('!/\*.*?\*/!s', '', $customCss); $customCssWithoutComments = preg_replace('!//.*!', '', $customCssWithoutComments); + + // Extract @import rules, because they MUST appear at the very top of the final CSS + // If they remain inside the theme scope or behind normal rules, browsers will ignore them preg_match_all('/(@import[^;]+;)/', $customCssWithoutComments, $imports); $importsCss = implode('', $imports[0]); $customCssWithoutImports = preg_replace('/(@import[^;]+;)/', '', $customCssWithoutComments); + // Extract all remaining @-rules (e.g. @media), because they cannot be nested inside the theme scope preg_match_all('/(@[^{]+{(?:[^{}]*|(?R))*})/', $customCssWithoutImports, $atRules); $atRulesCss = implode('', $atRules[0]); $scopedCss = preg_replace('/(@[^{]+{(?:[^{}]*|(?R))*})/', '', $customCssWithoutImports);