From 2ff80d0f7270ee64a0fc29f71366f9ed8f5b1d3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=90=95=E6=9F=8F=E9=9D=92?= Date: Tue, 9 Jun 2026 19:58:34 +0800 Subject: [PATCH] =?UTF-8?q?fix(settings):=20=E8=AE=BE=E7=BD=AE=E5=BC=B9?= =?UTF-8?q?=E7=AA=97=E7=94=A8=20Portal=20=E6=B8=B2=E6=9F=93=E9=81=BF?= =?UTF-8?q?=E5=85=8D=E8=A2=AB=E9=A1=B5=E9=9D=A2=E6=BB=9A=E5=8A=A8=E6=9D=A1?= =?UTF-8?q?=E8=A6=86=E7=9B=96=20(#580)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 在历史/风格页滚动后打开设置弹窗,WebKitGTK(Debian/KDE Wayland)下页面自绘滚动条 (.ol-thinscroll) 会盖在弹窗之上。根因:弹窗用 position:absolute 处于页面 overflow:hidden 祖容器的同一 stacking context 内,而 WebKitGTK 滚动条不创建独立合成层,z-index 对其无效 (issue #580 中 position:fixed、isolation:isolate 均无效已验证)。 - SettingsModal 改用 createPortal 渲染到 document.body,彻底脱离页面 DOM 树与 stacking context(与 SelectLite 的 popover 同款做法)。 - 遮罩层 position 由 absolute 改为 fixed,覆盖整窗;视觉与交互不变。 - 设计 token 定义在 :root,body 下的 portal 正常继承,无样式丢失。 --- openless-all/app/src/components/SettingsModal.tsx | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/openless-all/app/src/components/SettingsModal.tsx b/openless-all/app/src/components/SettingsModal.tsx index 7fe71d9e..7cd7917e 100644 --- a/openless-all/app/src/components/SettingsModal.tsx +++ b/openless-all/app/src/components/SettingsModal.tsx @@ -8,6 +8,7 @@ // 不在此弹窗出现。 import { useLayoutEffect, useRef, useState } from 'react'; +import { createPortal } from 'react-dom'; import { useTranslation } from 'react-i18next'; import { Icon } from './Icon'; import { SavedToast } from './SavedToast'; @@ -69,11 +70,15 @@ export function SettingsModal({ os: _os, onClose, initialSettingsSection }: Sett setPillRect({ top: el.offsetTop, height: el.offsetHeight }); }, [section]); - return ( + // issue #580:用 Portal 渲染到 document.body,脱离页面 overflow:hidden 容器的 + // stacking context。否则 WebKitGTK(Debian/KDE Wayland)下页面自绘滚动条 + // (.ol-thinscroll) 不创建独立合成层,z-index 无法隔离,滚动时会盖在弹窗之上。 + // 配合 position:fixed 覆盖整窗。 + return createPortal(
- + , + document.body, ); }