如何根据暗黑模式动态调整Shiny应用中元素的颜色?
如何根据暗黑模式动态调整Shiny应用中元素的颜色?
你遇到的这个问题确实很常见——Shiny默认的浅色表头在暗黑模式下对比度不够,导致可读性差。其实我们可以利用Shiny暗黑模式的CSS机制,通过自定义样式来动态切换颜色,不管是自定义元素(比如你的card_header)还是内置的DataGrid/DataTable组件都能轻松搞定。
核心思路:利用Shiny的暗黑模式CSS类
Shiny开启暗黑模式时,会给页面的<body>标签自动添加一个dark类。我们可以基于这个类编写条件CSS规则,让元素在不同模式下自动切换样式。
1. 自定义元素(如card_header)的动态颜色
你现在直接给card_header硬写了style='background:gainsboro',这是固定值,不会随模式变化。我们可以把颜色换成CSS变量,然后在正常和暗黑模式下分别定义变量的值:
首先在UI中添加自定义CSS,用ui.tags.style()嵌入:
ui.tags.style(""" /* 定义全局CSS变量 */ :root { --header-bg: gainsboro; --header-text: #000; } /* 暗黑模式下覆盖变量值 */ body.dark { --header-bg: #333; --header-text: #fff; } /* 把变量应用到card_header */ .card-header { background-color: var(--header-bg) !important; color: var(--header-text) !important; } """)
然后修改card_header的写法,去掉硬编码的style:
ui.card_header("card_header1")
这样它就会自动读取CSS变量的值,随模式切换背景和文字颜色。
2. 内置DataGrid/DataTable表头的样式调整
DataGrid的表头默认使用.dt-header类,我们同样可以针对这个类写暗黑模式下的样式,覆盖默认的浅色背景:
在刚才的CSS里补充这段代码:
/* 正常模式下DataGrid表头样式 */ .dt-header { background-color: gainsboro !important; } /* 暗黑模式下DataGrid表头样式 */ body.dark .dt-header { background-color: #333 !important; color: #fff !important; }
这样就能让暗黑模式下的表头背景和文字颜色有足够对比度,解决可读性问题。
修改后的完整示例代码
把上面的内容整合到你的代码里,最终版本如下:
from shiny import App, render, ui import polars as pl app_ui = ui.page_fillable( # 嵌入自定义CSS样式 ui.tags.style(""" :root { --header-bg: gainsboro; --header-text: #000; } body.dark { --header-bg: #333; --header-text: #fff; } .card-header { background-color: var(--header-bg) !important; color: var(--header-text) !important; } /* 调整DataGrid表头样式 */ .dt-header { background-color: gainsboro !important; } body.dark .dt-header { background-color: #333 !important; color: #fff !important; } """), ui.layout_sidebar( ui.sidebar(ui.input_dark_mode()), ui.layout_columns( ui.card( ui.card_header("card_header1"), ui.output_data_frame("card1"), full_screen=True ), col_widths=12 ) ) ) def server(input, output, session): @output @render.data_frame def card1(): return render.DataGrid(pl.DataFrame({'a': ['a','b','c','d']}), filters=True) app = App(app_ui, server)
额外小技巧
如果你不想全局修改所有card_header或DataGrid,也可以给特定元素加自定义类,然后针对这个类写样式。比如给card_header加个专属类:
ui.card_header("card_header1", class_="custom-table-header")
然后CSS里改成:
.custom-table-header { background-color: var(--header-bg) !important; color: var(--header-text) !important; }
这样就只作用于这个特定的card_header了。
备注:内容来源于stack exchange,提问作者gernophil
相关产品推荐
相关产品推荐

