如何使 Shiny 应用程序符合 W3C 标准?

How can I make a Shiny app W3C compliant?

我已经编写并优化了一个 Shiny 应用程序,现在我正在努力与我工作的组织的 IT 部门在他们的服务器上发布它。 目前,根据 W3C validator.

,他们声称该应用程序不符合 W3C,这是事实

我试图解决但没有成功的错误是:

此类错误也可以在非常小的闪亮应用程序中看到,例如:

# Reprex adapted from https://shiny.rstudio.com/gallery/tabsets.html
library(shiny)

# Define UI for random distribution app ----
ui <- fluidPage(
  
  # App title ----
  titlePanel("Tabsets"),
  
  # Sidebar layout with input and output definitions ----
  sidebarLayout(
    
    # Sidebar panel for inputs ----
    sidebarPanel(
      
      # Input: Select the random distribution type ----
      radioButtons("dist", "Distribution type:",
                   c("Normal" = "norm",
                     "Uniform" = "unif",
                     "Log-normal" = "lnorm",
                     "Exponential" = "exp")),
      
      # br() element to introduce extra vertical spacing ----
      br(),
      
      # Input: Slider for the number of observations to generate ----
      sliderInput("n",
                  "Number of observations:",
                  value = 500,
                  min = 1,
                  max = 1000)
      
    ),
    
    # Main panel for displaying outputs ----
    mainPanel(
      
      # Output: Tabset w/ plot, summary, and table ----
      tabsetPanel(type = "tabs",
                  tabPanel("Plot", plotOutput("plot")),
                  tabPanel("Summary", verbatimTextOutput("summary")),
                  tabPanel("Table", tableOutput("table"))
      )
      
    )
  )
)

# Define server logic for random distribution app ----
server <- function(input, output) {
  
  # Reactive expression to generate the requested distribution ----
  d <- reactive({
    dist <- switch(input$dist,
                   norm = rnorm,
                   unif = runif,
                   lnorm = rlnorm,
                   exp = rexp,
                   rnorm)
    
    dist(input$n)
  })
  
  # Generate a plot of the data ----
  output$plot <- renderPlot({
    dist <- input$dist
    n <- input$n
    
    hist(d(),
         main = paste("r", dist, "(", n, ")", sep = ""),
         col = "#75AADB", border = "white")
  })
}

# Create Shiny app ----
shinyApp(ui, server)

第二个错误似乎只与 radiobuttons 有关,而第一个错误似乎影响所有 shiny apps到目前为止,我已经在网上找到并使用 W3C 验证器进行了测试。 为了完整起见,我还报告了由 shiny 应用程序在 reprex 中生成的 HTML 代码:

<!DOCTYPE html>
<html>
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
  <script type="application/shiny-singletons"></script>
  <script type="application/html-dependencies">jquery[3.6.0];shiny-css[1.7.1];shiny-javascript[1.7.1];ionrangeslider-javascript[2.3.1];strftime[0.9.2];ionrangeslider-css[2.3.1];bootstrap[3.4.1]</script>
<script src="shared/jquery.min.js"></script>
<link href="shared/shiny.min.css" rel="stylesheet" />
<script src="shared/shiny.min.js"></script>
<script src="shared/ionrangeslider/js/ion.rangeSlider.min.js"></script>
<script src="shared/strftime/strftime-min.js"></script>
<link href="shared/ionrangeslider/css/ion.rangeSlider.css" rel="stylesheet" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link href="shared/bootstrap/css/bootstrap.min.css" rel="stylesheet" />
<link href="shared/bootstrap/accessibility/css/bootstrap-accessibility.min.css" rel="stylesheet" />
<script src="shared/bootstrap/js/bootstrap.min.js"></script>
<script src="shared/bootstrap/accessibility/js/bootstrap-accessibility.min.js"></script>  <title>Tabsets</title>
</head>
<body>
  <div class="container-fluid">
    <h2>Tabsets</h2>
    <div class="row">
      <div class="col-sm-4">
        <form class="well" role="complementary">
          <div id="dist" class="form-group shiny-input-radiogroup shiny-input-container" role="radiogroup" aria-labelledby="dist-label">
            <label class="control-label" id="dist-label" for="dist">Distribution type:</label>
            <div class="shiny-options-group">
              <div class="radio">
                <label>
                  <input type="radio" name="dist" value="norm" checked="checked"/>
                  <span>Normal</span>
                </label>
              </div>
              <div class="radio">
                <label>
                  <input type="radio" name="dist" value="unif"/>
                  <span>Uniform</span>
                </label>
              </div>
              <div class="radio">
                <label>
                  <input type="radio" name="dist" value="lnorm"/>
                  <span>Log-normal</span>
                </label>
              </div>
              <div class="radio">
                <label>
                  <input type="radio" name="dist" value="exp"/>
                  <span>Exponential</span>
                </label>
              </div>
            </div>
          </div>
          <br/>
          <div class="form-group shiny-input-container">
            <label class="control-label" id="n-label" for="n">Number of observations:</label>
            <input class="js-range-slider" id="n" data-skin="shiny" data-min="1" data-max="1000" data-from="500" data-step="1" data-grid="true" data-grid-num="9.99" data-grid-snap="false" data-prettify-separator="," data-prettify-enabled="true" data-keyboard="true" data-data-type="number"/>
          </div>
        </form>
      </div>
      <div class="col-sm-8" role="main">
        <div class="tabbable">
          <ul class="nav nav-tabs" data-tabsetid="9747">
            <li class="active">
              <a href="#tab-9747-1" data-toggle="tab" data-bs-toggle="tab" data-value="Plot">Plot</a>
            </li>
            <li>
              <a href="#tab-9747-2" data-toggle="tab" data-bs-toggle="tab" data-value="Summary">Summary</a>
            </li>
            <li>
              <a href="#tab-9747-3" data-toggle="tab" data-bs-toggle="tab" data-value="Table">Table</a>
            </li>
          </ul>
          <div class="tab-content" data-tabsetid="9747">
            <div class="tab-pane active" data-value="Plot" id="tab-9747-1">
              <div id="plot" class="shiny-plot-output" style="width:100%;height:400px;"></div>
            </div>
            <div class="tab-pane" data-value="Summary" id="tab-9747-2">
              <pre class="shiny-text-output noplaceholder" id="summary"></pre>
            </div>
            <div class="tab-pane" data-value="Table" id="tab-9747-3">
              <div id="table" class="shiny-html-output"></div>
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>
</body>
</html>

你有什么建议吗? 谢谢!


此消息也发布在 RStudio Community:抱歉交叉发布。

以下仅处理您提到的第一个错误(由于@BenBolkers 的评论,这个错误非常清楚),但希望它能为您指出正确的工具。

我会使用 htmltools::tagQuery 进行必要的修改 - 请检查以下内容:

# Reprex adapted from https://shiny.rstudio.com/gallery/tabsets.html
library(shiny)
library(htmltools)

# Define UI for random distribution app ----
ui <- fluidPage(
  
  # App title ----
  titlePanel("Tabsets"),
  
  # Sidebar layout with input and output definitions ----
  sidebarLayout(
    
    # Sidebar panel for inputs ----
    {querySidebarPanel <- tagQuery(sidebarPanel(
      # Input: Select the random distribution type ----
      radioButtons("dist", "Distribution type:",
                   c("Normal" = "norm",
                     "Uniform" = "unif",
                     "Log-normal" = "lnorm",
                     "Exponential" = "exp")),
      
      # br() element to introduce extra vertical spacing ----
      br(),
      
      # Input: Slider for the number of observations to generate ----
      sliderInput("n",
                  "Number of observations:",
                  value = 500,
                  min = 1,
                  max = 1000)
    ))
    querySidebarPanel$find(".well")$removeAttrs("role")$addAttrs("role" = "none")$allTags()},
    
    # Main panel for displaying outputs ----
    mainPanel(
      
      # Output: Tabset w/ plot, summary, and table ----
      tabsetPanel(type = "tabs",
                  tabPanel("Plot", plotOutput("plot")),
                  tabPanel("Summary", verbatimTextOutput("summary")),
                  tabPanel("Table", tableOutput("table"))
      )
      
    )
  )
)

# Define server logic for random distribution app ----
server <- function(input, output) {
  
  # Reactive expression to generate the requested distribution ----
  d <- reactive({
    dist <- switch(input$dist,
                   norm = rnorm,
                   unif = runif,
                   lnorm = rlnorm,
                   exp = rexp,
                   rnorm)
    
    dist(input$n)
  })
  
  # Generate a plot of the data ----
  output$plot <- renderPlot({
    dist <- input$dist
    n <- input$n
    
    hist(d(),
         main = paste("r", dist, "(", n, ")", sep = ""),
         col = "#75AADB", border = "white")
  })
}

# Create Shiny app ----
shinyApp(ui, server)

另请参阅 related chapter 来自 “闪亮的杰出用户界面”