如何用Userscript修改Service Now Agent Workspace的Shadow DOM CSS?
解决ServiceNow Agent Workspace Shadow DOM样式覆盖问题
问题背景
我多年来一直使用JS用户脚本来修改ServiceNow页面的各类样式,旧脚本示例如下。但ServiceNow最新版本采用的Agent Workspace通过Shadow DOM交付CSS,旧脚本完全失效,试过Stack Overflow上的多种方法都无法适配到我的场景,求能覆盖这类Shadow DOM样式的方案。
旧失效脚本示例
// ==UserScript== // @name Service Now 001 // @version 1.0 // @description Service Now // @namespace https://example.com/ // @author This // @match https://*.service-now.com/*incident.do* // @match https://*.service-now.com/*incident_task.do* // @icon https://www.google.com/s2/favicons?sz=64&domain=service-now.com // ==/UserScript== (function() { 'use strict'; function addGlobalStyle(css) { var head = document.getElementsByTagName('head')[0]; if (!head) { return; } var style = document.createElement('style'); style.type = 'text/css'; style.innerHTML = css.replaceAll(';', ' !important;'); head.appendChild(style); } addGlobalStyle('.vt, .sn-list-grid-cell, .row { border-left:1px dotted #888; border-top:1px solid #999; vertical-align: top; }'); addGlobalStyle('.timelineMainContainer { display:none; }'); })();
解决方案
要修改Shadow DOM内的样式,核心是定位到对应的Shadow Root节点并注入样式。由于Agent Workspace的Shadow DOM是动态加载的,需要用MutationObserver监听页面变化,确保样式能及时注入到新增的Shadow DOM中。
适配Shadow DOM的用户脚本
// ==UserScript== // @name Service Now Agent Workspace Style Fix // @version 2.0 // @description 适配Agent Workspace Shadow DOM的样式修改 // @namespace https://example.com/ // @author This // @match https://*.service-now.com/*incident.do* // @match https://*.service-now.com/*incident_task.do* // @match https://*.service-now.com/now/agent-workspace* // @icon https://www.google.com/s2/favicons?sz=64&domain=service-now.com // @grant none // ==/UserScript== (function() { 'use strict'; // 自定义样式(保留原需求) const customStyles = ` .vt, .sn-list-grid-cell, .row { border-left:1px dotted #888 !important; border-top:1px solid #999 !important; vertical-align: top !important; } .timelineMainContainer { display:none !important; } `; // 向指定Shadow Root注入样式 function injectStyleToShadowRoot(shadowRoot) { if (!shadowRoot) return; const style = document.createElement('style'); style.textContent = customStyles; shadowRoot.appendChild(style); } // 遍历所有可能的Shadow Host元素并注入样式 function findAndInjectToAllShadowRoots() { // 这里的选择器可根据实际页面结构调整,用F12查看Shadow Host标签 const shadowHosts = document.querySelectorAll('sn-agent-workspace, sn-record-page, sn-list-grid'); shadowHosts.forEach(host => { if (host.shadowRoot) { injectStyleToShadowRoot(host.shadowRoot); } }); } // 监听DOM变化,处理动态加载的Shadow DOM const observer = new MutationObserver(() => { findAndInjectToAllShadowRoots(); }); // 启动监听,覆盖整个DOM树的新增节点 observer.observe(document.body, { childList: true, subtree: true }); // 页面加载完成后首次执行 window.addEventListener('load', findAndInjectToAllShadowRoots); })();
关键注意点
- Shadow Host选择器调整:打开浏览器开发者工具(F12),找到包含目标样式的Shadow DOM对应的宿主元素标签(比如
sn-agent-workspace),替换到querySelectorAll的参数中,确保能定位到正确的Shadow Root。 - 动态监听:
MutationObserver会自动捕获页面中新增的DOM节点,确保后续加载的Shadow DOM也能被注入样式。 - 样式优先级:保留
!important声明,确保自定义样式能够覆盖Agent Workspace的原有样式。
内容的提问来源于stack exchange,提问作者4532066
相关产品推荐
相关产品推荐

