You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何根据暗黑模式动态调整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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.14 18:19:49