htmlcssr-markdownknitrkableextra

cell border fill with color in html Rmarkdown file in R


I have a data frame called df and I am using html format in Rmarkdown to create a data frame but the due to different size of cells the color in background does not fill exactly with the cell and I have white spaces.

The code that I use is :


df = structure(list(projects = c("Restaurant, Pizzeria and Pasta House Works for  New York",
                                "London Project - New Restaurant  Project", 
                                "Athens - Beautiful Lands for Aigaleo City Project",
                                "Berlin City - Exhibition  near the airport with restaurants",
                                "Pizzeria Buenos Aires New italian restaurant - pasta, tartufo and vino",
                                "area mean value", "total mean value"), 
                    happiness.and.joyfullness = c(3.5,4, 3, 3.2, 4, 5, 3), 
                    joy.for.children = c(3, 5, 3, 4, 5,4, 4), 
                    area = c(3, 5, 3, 3, 3, 4, 4), 
                    damages.from.environment = c(2,4, 2, 3, 3, 5, 5), 
                    approach  = c(3, 1, 5,3, 5, 5, 4), 
                    expensive = c(3, 5, 3, 4, 5, 5, 5), 
                    safety.comes.first = c(5,5, 5, 5, 5, 5, 4),
                    hungry = c(3, 5, 2, 4, 5,5, 5)), 
               row.names = c(NA, -7L), 
               class = c("tbl_df", "tbl","data.frame"))






set_background  = function(x, color = "white") {
  kableExtra::cell_spec(x,
                        bold = TRUE,
                        align = "center",
                        color = "black", 
                        background = color,
                        extra_css ="align-items: center;
      justify-content: center;margin: -5px; padding: 15px; display: flex;",
                       background_as_tile = FALSE
      )}

set_background2  = function(x, color = "black") {
  kableExtra::cell_spec(x,
                        bold = TRUE,
                        color="black", 
                        background = color,
                        extra_css ="align-items: center;
      justify-content: center;margin: -5px; padding: 10px; display: flex;",
                        background_as_tile = FALSE)
}



df %>%

  dplyr::mutate( across(projects, \(x) case_when(projects == "area mean value" ~set_background2(x, "yellow") ,
                                              projects == "total mean value" ~set_background2(x, "yellow"),
                                              TRUE ~ projects)))%>%
  dplyr::mutate( 
    across(happiness.and.joyfullness:hungry, \(x)
           case_when(
             x <= 3.5  ~ set_background(x, "lightblue"),
             x > 3.5  & x <= 4.5  ~ set_background(x, "pink"),
             x > 4.5  & x <= 5    ~ set_background(x, "purple"),
             TRUE ~ set_background(x))))%>%
  kableExtra::kbl(align = "c",position = "center",caption = "Project Scoring Table", escape=FALSE)%>%
  kableExtra::kable_paper()%>%
  kableExtra::row_spec(0,color = "white", background = "grey")%>%
  kableExtra::column_spec(1:9, 
                          bold = TRUE,
                          border_left  = TRUE,
                          border_right = TRUE)%>%
  kableExtra::row_spec(0:7, align = "center",extra_css = "vertical-align:middle;")

resulting to : enter image description here

how can I fix this in R for html Rmarkdown document? I am just playing around with paddling and margin and I make things bigger and bigger .The problem is that white spacing appears when I render it to html via rmarkdown


Solution

  • Why it doesn't work

    Inspecting the HTML output generated by kableExtra shows that the cell contents are being wrapped in span elements.

    <td style="text-align:center;font-weight: bold;border-left:1px solid;border-right:1px solid;text-align: center;vertical-align:middle;">
        <span style="font-weight: bold; color: black !important;padding-right: 4px; padding-left: 4px; background-color: pink !important; align-items: center; justify-content: center; margin: -5px; padding: 15px; display: flex; text-align: center;">
            4
        </span>
    </td>
    

    Due to idiosyncrasies of how HTML table rows and cells are displayed, the span is not able to determine the height of its parent cell element, so simply setting the height to 100% will have no effect. You could set the height to a fixed value, like 150px, but that would mean any cells with very long content would have overflowing content.

    What to do

    Making an inner span fill its containing table cell is oddly difficult as previous questions have indicated. In this case, probably the easiest way would be to set position: relative on each td element, and position: absolute on each span element. Then we can set the top, right, bottom, and left properties of the spans to 0, making them overlay the entire cell.

    From the HTML given above, we can see that the styles you pass in extra_css to kableExtra::cell_spec (in the set_background function) are being applied to the span. And it seems that styles passed to kableExtra::row_spec are being applied to every td. So we should be able to change the position for tds and spans by using row_spec and cell_spec respectively.

    How to do it

    So to give each td element relative positioning, update extra_css in the call to row_spec on the last line.

    kableExtra::row_spec(
        0:7,
        align = "center",
        extra_css = "
            vertical-align: middle;
            position: relative;
        "
    )
    

    And to give the spans absolute positioning, update extra_css in the call to cell_spec in your set_background function. You can also remove the negative margin.

    set_background  = function(x, color = "white") {
        kableExtra::cell_spec(
            x,
            bold = TRUE,
            align = "center",
            color = "black", 
            background = color,
            extra_css = "
                align-items: center;
                justify-content: center;
                padding: 15px;
                display: flex;
                position: absolute;
                left: 0;
                right: 0;
                top: 0;
                bottom: 0;
            ",
            background_as_tile = FALSE
        )
    }
    

    This gives the following output:

    Table output