design-shiny-ui
À propos
Cette compétence aide les développeurs à créer des interfaces utilisateur d'applications Shiny réactives et accessibles en utilisant bslib pour le thème, layout_columns pour les grilles, et du CSS/SCSS personnalisé. Elle est idéale pour créer de nouvelles applications à partir de zéro, moderniser des mises en page fluidPage existantes ou appliquer des thèmes de marque. Les capacités clés incluent la mise en œuvre d'un design réactif adapté à toutes les tailles d'écran et l'amélioration de la conformité en matière d'accessibilité.
Installation rapide
Claude Code
Recommandénpx skills add pjt222/agent-almanac -a claude-code/plugin add https://github.com/pjt222/agent-almanacgit clone https://github.com/pjt222/agent-almanac.git ~/.claude/skills/design-shiny-uiCopiez et collez cette commande dans Claude Code pour installer cette compétence
Documentation
name: design-shiny-ui description: > 使用 bslib 进行主题设计、layout_columns 实现响应式网格、值框、卡片及 自定义 CSS/SCSS 设计 Shiny 应用 UI。涵盖页面布局、可访问性和品牌一致性。 适用于从零构建新 Shiny 应用 UI、将现有应用从 fluidPage 升级到 bslib、 应用品牌主题、使 Shiny 应用在不同屏幕尺寸上响应式显示,或改善 Shiny 应用的可访问性。 license: MIT allowed-tools: Read Write Edit Bash Grep Glob metadata: author: Philipp Thoss version: "1.0" domain: shiny complexity: intermediate language: R tags: shiny, bslib, ui, theming, layout, css, accessibility, responsive locale: zh-CN source_locale: en source_commit: 6f65f316 translator: claude-opus-4-6 translation_date: 2026-03-16
设计 Shiny UI
使用 bslib 主题、现代布局原语和自定义 CSS 设计响应式、无障碍的 Shiny 应用界面。
适用场景
- 从零构建新 Shiny 应用 UI
- 将现有 Shiny 应用从 fluidPage 升级到 bslib
- 为 Shiny 应用应用品牌主题(颜色、字体)
- 使 Shiny 应用在不同屏幕尺寸上响应式显示
- 改善 Shiny 应用的可访问性
输入
- 必需:应用用途和目标受众
- 必需:布局类型(侧边栏、导航栏、可填充、仪表盘)
- 可选:品牌颜色和字体
- 可选:是否使用自定义 CSS/SCSS(默认:仅 bslib)
- 可选:可访问性要求(WCAG 级别)
步骤
第 1 步:选择页面布局
bslib 提供多种页面构造函数:
# Sidebar layout — most common for data apps
ui <- page_sidebar(
title = "My App",
sidebar = sidebar("Controls here"),
"Main content here"
)
# Navbar layout — for multi-page apps
ui <- page_navbar(
title = "My App",
nav_panel("Tab 1", "Content 1"),
nav_panel("Tab 2", "Content 2"),
nav_spacer(),
nav_item(actionButton("help", "Help"))
)
# Fillable layout — content fills available space
ui <- page_fillable(
card(
full_screen = TRUE,
plotOutput("plot")
)
)
# Dashboard layout — grid of value boxes and cards
ui <- page_sidebar(
title = "Dashboard",
sidebar = sidebar(open = "closed", "Filters"),
layout_columns(
fill = FALSE,
value_box("Revenue", "$1.2M", theme = "primary"),
value_box("Users", "4,521", theme = "success"),
value_box("Uptime", "99.9%", theme = "info")
),
layout_columns(
card(plotOutput("chart1")),
card(plotOutput("chart2"))
)
)
预期结果: 页面布局与应用的导航和内容需求匹配。
失败处理: 如果布局看起来不对,检查是否使用了 page_sidebar() / page_navbar()(bslib)而非 fluidPage() / navbarPage()(基础 shiny)。bslib 版本有更好的默认值和主题支持。
第 2 步:配置 bslib 主题
my_theme <- bslib::bs_theme(
version = 5, # Bootstrap 5
bootswatch = "flatly", # Optional preset theme
bg = "#ffffff", # Background color
fg = "#2c3e50", # Foreground (text) color
primary = "#2c3e50", # Primary brand color
secondary = "#95a5a6", # Secondary color
success = "#18bc9c",
info = "#3498db",
warning = "#f39c12",
danger = "#e74c3c",
base_font = bslib::font_google("Source Sans Pro"),
heading_font = bslib::font_google("Source Sans Pro", wght = 600),
code_font = bslib::font_google("Fira Code"),
"navbar-bg" = "#2c3e50"
)
ui <- page_sidebar(
theme = my_theme,
title = "Themed App",
# ...
)
开发时使用交互式主题编辑器:
bslib::bs_theme_preview(my_theme)
预期结果: 应用以一致的品牌颜色、字体和 Bootstrap 5 组件渲染。
失败处理: 如果字体未加载,检查网络访问(Google Fonts 需要联网)或切换到系统字体:font_collection("system-ui", "-apple-system", "Segoe UI")。如果主题变量未应用,检查是否将 theme 传递给了页面函数。
第 3 步:用卡片和列构建布局
ui <- page_sidebar(
theme = my_theme,
title = "Analysis Dashboard",
sidebar = sidebar(
width = 300,
title = "Filters",
selectInput("dataset", "Dataset", choices = c("iris", "mtcars")),
sliderInput("sample", "Sample %", 10, 100, 100, step = 10),
hr(),
actionButton("refresh", "Refresh", class = "btn-primary w-100")
),
# KPI row — non-filling
layout_columns(
fill = FALSE,
col_widths = c(4, 4, 4),
value_box(
title = "Observations",
value = textOutput("n_obs"),
showcase = bsicons::bs_icon("table"),
theme = "primary"
),
value_box(
title = "Variables",
value = textOutput("n_vars"),
showcase = bsicons::bs_icon("columns-gap"),
theme = "info"
),
value_box(
title = "Missing",
value = textOutput("n_missing"),
showcase = bsicons::bs_icon("exclamation-triangle"),
theme = "warning"
)
),
# Main content row
layout_columns(
col_widths = c(8, 4),
card(
card_header("Distribution"),
full_screen = TRUE,
plotOutput("main_plot")
),
card(
card_header("Summary"),
tableOutput("summary_table")
)
)
)
关键布局原语:
layout_columns()— 带col_widths的响应式网格card()— 可选头部/尾部的内容容器value_box()— 带图标和主题的 KPI 显示layout_sidebar()— 卡片内嵌套侧边栏navset_card_tab()— 带标签页的卡片
预期结果: 响应式网格布局适应屏幕尺寸。
失败处理: 如果列在宽屏上意外堆叠,检查 col_widths 之和是否等于 12(Bootstrap 网格)。如果卡片重叠,确保非填充行设置了 fill = FALSE。
第 4 步:添加动态 UI 元素
server <- function(input, output, session) {
output$dynamic_filters <- renderUI({
data <- current_data()
tagList(
selectInput("col", "Column", choices = names(data)),
if (is.numeric(data[[input$col]])) {
sliderInput("range", "Range",
min = min(data[[input$col]], na.rm = TRUE),
max = max(data[[input$col]], na.rm = TRUE),
value = range(data[[input$col]], na.rm = TRUE)
)
} else {
selectInput("values", "Values",
choices = unique(data[[input$col]]),
multiple = TRUE
)
}
)
})
# Conditional panels (no server round-trip)
# In UI:
# conditionalPanel(
# condition = "input.show_advanced == true",
# numericInput("alpha", "Alpha", 0.05)
# )
}
预期结果: UI 元素根据用户选择和数据动态更新。
失败处理: 如果动态 UI 闪烁,尽可能使用 conditionalPanel()(基于 CSS)而非 renderUI()。如果动态输入在重渲染后丢失值,添加 session$sendInputMessage() 恢复状态。
第 5 步:添加自定义 CSS/SCSS(可选)
对于超出 bslib 主题变量的样式:
# Inline CSS
ui <- page_sidebar(
theme = my_theme,
tags$head(tags$style(HTML("
.sidebar { border-right: 2px solid var(--bs-primary); }
.card-header { font-weight: 600; }
.value-box .value { font-size: 2.5rem; }
"))),
# ...
)
# External CSS file (place in www/ directory)
ui <- page_sidebar(
theme = my_theme,
tags$head(tags$link(rel = "stylesheet", href = "custom.css")),
# ...
)
使用 bslib 集成 SCSS:
my_theme <- bslib::bs_theme(version = 5) |>
bslib::bs_add_rules(sass::sass_file("www/custom.scss"))
预期结果: 自定义样式已应用且不破坏 bslib 主题。
失败处理: 如果自定义 CSS 与 bslib 冲突,使用 Bootstrap CSS 变量(var(--bs-primary))代替硬编码颜色。这样主题更改时自定义样式也会随之更新。
第 6 步:确保可访问性
# Add ARIA labels to inputs
selectInput("category", "Category",
choices = c("A", "B", "C")
) |> tagAppendAttributes(`aria-describedby` = "category-help")
# Add alt text to plots
output$plot <- renderPlot({
plot(data(), main = "Distribution of Values")
}, alt = "Histogram showing the distribution of selected values")
# Ensure sufficient color contrast in theme
my_theme <- bslib::bs_theme(
version = 5,
bg = "#ffffff", # White background
fg = "#212529" # Dark text — 15.4:1 contrast ratio
)
# Use semantic HTML
tags$main(
role = "main",
tags$h1("Dashboard"),
tags$section(
`aria-label` = "Key Performance Indicators",
layout_columns(
# value boxes...
)
)
)
预期结果: 应用满足 WCAG 2.1 AA 标准的颜色对比度、键盘导航和屏幕阅读器兼容性。
失败处理: 使用浏览器开发者工具的可访问性审计(Lighthouse)进行测试。使用 WebAIM 的对比度检查器验证颜色对比度。确保所有交互元素可通过键盘聚焦。
验证清单
- 页面布局在桌面和移动宽度上正确渲染
- bslib 主题一致应用于所有组件
- 值框以正确的主题和图标显示
- 卡片在响应式网格中正确调整大小
- 自定义 CSS 使用 Bootstrap 变量而非硬编码值
- 所有图表有屏幕阅读器的替代文本
- 颜色对比度满足 WCAG AA(文本 4.5:1)
- 交互元素可通过键盘访问
常见问题
- 混用旧版和新版 Shiny UI:不要将
fluidPage()与 bslib 组件混用。专用page_sidebar()、page_navbar()或page_fillable()。 - CSS 中硬编码颜色:使用
var(--bs-primary)而非#2c3e50。主题更改时硬编码颜色会失效。 - 非填充行缺少
fill = FALSE:值框行和摘要行通常不应拉伸填充可用空间。设置fill = FALSE。 - 离线环境中的 Google Fonts:如果应用部署到隔离网络,使用系统字体或自托管字体文件而非
font_google()。 - 忽略移动端:使用浏览器响应式模式测试。
layout_columns在窄屏上自动堆叠,但自定义 CSS 可能不会。
相关技能
scaffold-shiny-app— 包含主题配置的初始应用设置build-shiny-module— 创建模块化 UI 组件optimize-shiny-performance— 注重性能的渲染review-web-design— 布局、排版和配色的视觉设计评审review-ux-ui— 可用性和可访问性评审
Dépôt GitHub
Compétences associées
executing-plans
DesignUtilisez la compétence executing-plans lorsque vous disposez d'un plan de mise en œuvre complet à exécuter par lots contrôlés avec des points de contrôle de revue. Elle charge et examine le plan de manière critique, puis exécute les tâches par petits lots (3 tâches par défaut) tout en rapportant la progression entre chaque lot pour une revue par l'architecte. Cela garantit une mise en œuvre systématique avec des points de contrôle de qualité intégrés.
requesting-code-review
DesignCette compétence délègue un sous-agent réviseur de code pour analyser les modifications apportées au code par rapport aux exigences avant de poursuivre. Elle doit être utilisée après avoir terminé des tâches, implémenté des fonctionnalités majeures, ou avant une fusion vers la branche principale. La revue aide à détecter précocement les problèmes en comparant l'implémentation actuelle avec le plan initial.
connect-mcp-server
DesignCette compétence fournit un guide complet permettant aux développeurs de connecter des serveurs MCP à Claude Code via les transports HTTP, stdio ou SSE. Elle couvre l'installation, la configuration, l'authentification et la sécurité pour intégrer des services externes tels que GitHub, Notion et des API personnalisées. Utilisez-la lors de la configuration d'intégrations MCP, de la configuration d'outils externes ou du travail avec le Protocole de Contexte de Modèle de Claude.
web-cli-teleport
DesignCette compétence aide les développeurs à choisir entre les interfaces Web et CLI de Claude Code en fonction de l'analyse des tâches, puis permet une téléportation transparente des sessions entre ces environnements. Elle optimise le flux de travail en gérant l'état et le contexte de la session lors du passage entre le web, la CLI ou le mobile. Utilisez-la pour des projets complexes nécessitant différents outils à diverses étapes.
