Shadow DOM中CSS :hover与cursor属性失效问题排查与解决
问题
开发浏览器插件时,通过Shadow DOM向任意网站插入组件,静态样式正常生效,但CSS的:hover选择器与cursor属性无法正常工作。鼠标悬停图标按钮时,既不显示深色背景也不切换为指针光标。
相关代码片段
内容脚本(创建Shadow DOM)
var inpagePopupHTML = ""; var insertStylesHTML = ""; // 从资源文件加载组件HTML(正常工作) $.get(browser.runtime.getURL("/ui/mistake-popup.html"), function(data) { inpagePopupHTML = data; }); // 从仅包含<style>的HTML文件加载样式(正常工作) $.get(browser.runtime.getURL("/css/insert-styles.html"), function(data) { insertStylesHTML = data; document.body.innerHTML += data; // 插入到页面是因为样式同时作用于整个页面和组件 }); $("body").append('<div class="grammle--shadow" style="all: initial;"></div>'); // "all: initial" 阻止Shadow DOM继承页面样式 var shadow = document.querySelector(".grammle--shadow").attachShadow({ mode: "open" }); shadow.innerHTML += inpagePopupHTML; shadow.innerHTML += insertStylesHTML; // 同样的CSS文件也放入Shadow DOM,因为包含组件样式
mistake-popup.html
<div class="grammle--popup grammle--popup--minimised"> <div class="grammle--popup-text"> <span class="grammle--popup-text-counter">0</span> <span class="grammle--popup-text-label">Fehler</span> </div> <div class="grammle--popup-icons"> <span class="grammle--popup-icon" part="icon"> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-chevron-up" viewBox="0 0 16 16"> <path fill-rule="evenodd" d="M7.646 4.646a.5.5 0 0 1 .708 0l6 6a.5.5 0 0 1-.708.708L8 5.707l-5.646 5.647a.5.5 0 0 1-.708-.708l6-6z"/> </svg> </span> <span class="grammle--popup-icon" part="icon"> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-x-lg" viewBox="0 0 16 16"> <path d="M2.146 2.854a.5.5 0 1 1 .708-.708L8 7.293l5.146-5.147a.5.5 0 0 1 .708.708L8.707 8l5.147 5.146a.5.5 0 0 1-.708.708L8 8.707l-5.146 5.147a.5.5 0 0 1-.708-.708L7.293 8 2.146 2.854Z"/> </svg> </span> </div> </div>
insert-styles.html
<style> :root { --grammle-dark-main-colour: #137768; --grammle-dark-main-colour-hover: #0f6a5d; } ... .grammle--popup-icon { cursor: pointer; padding: 4px; background-color: var(--grammle-dark-main-colour); border-radius: 3px; } .grammle--popup-icon:hover { background-color: var(--grammle-dark-main-colour-hover); } ... </style>
原因分析
核心问题在于Shadow DOM容器的style="all: initial;"设置:
all: initial会重置元素的所有CSS属性,其中包括将pointer-events重置为none,这会导致容器内的所有元素无法接收鼠标事件,:hover状态自然不会触发,cursor属性也无法生效。- 另外,同时将样式插入主文档和Shadow DOM的操作,虽不直接导致当前问题,但可能引发潜在的样式冲突。
修复方案
1. 恢复Shadow DOM容器的鼠标事件能力
保留all: initial的同时,手动指定pointer-events: auto以恢复鼠标事件接收:
$("body").append('<div class="grammle--shadow" style="all: initial; pointer-events: auto;"></div>');
或者直接移除all: initial——Shadow DOM本身自带样式隔离特性,不需要强制重置容器样式来隔离:
$("body").append('<div class="grammle--shadow"></div>');
2. 优化样式加载逻辑(可选)
拆分全局样式与组件样式,避免重复插入:
- 将作用于主文档的全局样式单独放入
global-styles.html,仅插入到主文档 - 组件样式保留在
insert-styles.html,仅放入Shadow DOM
// 加载全局样式到主文档 $.get(browser.runtime.getURL("/css/global-styles.html"), function(data) { document.body.innerHTML += data; }); // 加载组件样式到Shadow DOM Promise.all([ $.get(browser.runtime.getURL("/ui/mistake-popup.html")), $.get(browser.runtime.getURL("/css/insert-styles.html")) ]).then(function([popupHTML, stylesHTML]) { $("body").append('<div class="grammle--shadow"></div>'); var shadow = document.querySelector(".grammle--shadow").attachShadow({ mode: "open" }); shadow.innerHTML = popupHTML + stylesHTML; });
3. 修正异步加载顺序(必做)
原代码中$.get是异步操作,可能出现Shadow DOM已创建但内容/样式未加载完成的情况,用Promise.all确保资源加载完成后再创建Shadow DOM,避免内容缺失。
内容的提问来源于stack exchange,提问作者Pixelcode
相关产品推荐
相关产品推荐

