bslib
bslib copied to clipboard
Allow adding multiple local font-styles with bs_theme & font_face
Hi, either I can´t figure it out, or it is not possible as of now. I´m not able to pass more than one style from a font-family to bs_theme (e.g normal, bold, italic from 'Open Sans').
Reprex
library(shiny)
library(bslib)
library(htmltools)
# Borrow fonts from bslib ----
addResourcePath("fonts", system.file("fonts", package = "bslib"))
# Define font collection ----
nunito <- font_collection(
font_face("Nunito", weight = 400, style = "normal", src = "url('../fonts/XRXV3I6Li01BKof4MQ.woff')"),
font_face("Nunito", weight = 700, style = "normal", src = "url('../fonts/XRXW3I6Li01BKofAjsOkZQ.woff')")
)
ui <- fluidPage(
theme = bs_theme(base_font = nunito),
tags$p("Normal Text"),
tags$b("Bold Text (seems bold, but is thickened by browser I suppose)"),
)
shinyApp(ui, \(...){})
As I inspect this app via the browser dev-tools, I can see this CSS declaration (../_Nunito-0.4.0/font.css
):
@font-face {
font-family: Nunito;
src: url('../fonts/XRXV3I6Li01BKof4MQ.woff');
font-weight: 400;
font-style: normal;
font-display: swap;
}
My font is included 🎉 but only the first style (weight 400) -> bold/700 is missing. Here´s what I would expect in the file:
@font-face {
font-family: Nunito;
src: url('../fonts/XRXV3I6Li01BKof4MQ.woff');
font-weight: 400;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: Nunito;
src: url('../fonts/XRXW3I6Li01BKofAjsOkZQ.woff');
font-weight: 700;
font-style: normal;
font-display: swap;
}
The browser still produces a thickened text (reprex), but I think this is some browser-magic and not the months of work the font designer put into developing the bold style as it is missing in the font-face declaration.
I think you can workaround this bug by replacing nunito
with font_face("Nunito", weight = c(400, 700))
?
Oh actually, I misunderstood what you're trying to do, I'm not sure if that workaround works if you need the 2 different weights to point to 2 different files.
Any reason why you can't use font_google("Nunito", wght = c(400, 700))
instead?
Thanks for your reply @cpsievert!
In my case I don´t use the (convenient) font_google
function for data privacy reasons + a blocking firewall. For others a use case may be using some special non-google font
After a deep dive into CSS, font_face etc. my current status (for woff/woff2-font files) is the following:
Traditional approach
- Professional fonts are usually served in multiple files (each file representing a carefully crafted variation like semi-bold)
- Each font variation can be imported with an
@font_face
declaration (like in the intoducing reprex) - This approach has currently a wide browser support
Variable Fonts
- A relatively new font format is variable fonts
- Multiple font variations are included into a single file
- Less browser support than the traditional approach, as it is a new format.
Still, many variable fonts still distinguish between normal and italic putting both into separate files 😟. Open Sans (as a variable font) for example is split into this two files:
- OpenSans-VariableFont_wdth,wght.ttf
- OpenSans-Italic-VariableFont_wdth,wght.ttf
Maybe there is a third approach putting all font variations into a single file and declaring them via @font_face
that I´m currently not aware of.
I would be very glad to somehow have the possibility to use custom fonts (contained in multiple files) within shiny 😀
I would be very glad to somehow have the possibility to use custom fonts (contained in multiple files) within shiny
I hope we'll be able fix the core issue with font_face()
here (the CSS is being de-duplicated when it in fact shouldn't be), but given that you need this level of control, there isn't much of any benefit to using font_face()
over writing the CSS by hand, like this:
addResourcePath("fonts" = "../fonts")
ui <- fluidPage(
theme = bs_theme(base_font = "Nunito") %>%
bs_add_rules(
"@font-face {
font-family: Nunito;
src: url('fonts/XRXV3I6Li01BKof4MQ.woff');
font-weight: 400;
font-style: normal;
font-display: swap;
}"
),
tags$p("Normal Text"),
tags$b("Bold Text (seems bold, but is thickened by browser I suppose)"),
)
shinyApp(ui, \(...){})
I see, that seems to be the best solution for now! Thank´s for your suggestion!