From ade18cb473203a3a8cd2156021e0431286c4c885 Mon Sep 17 00:00:00 2001 From: Samarth Jaiswal Date: Thu, 12 Nov 2026 17:07:12 +0530 Subject: [PATCH] Treat a null $body-bg or $body-color as unset in Bootstrap variables A theme that declares `$body-bg: null !default;` (as Dart Sass recommends before setting a variable conditionally) made `variable-exists()` true, so Quarto used the null value and theme compilation failed. Check for null too, as the `$pre-color` fallback already does. Fixes #15304 --- news/changelog-1.12.md | 1 + .../html/_quarto-variables-copy-code.scss | 2 +- .../html/bootstrap/_bootstrap-functions.scss | 4 ++-- .../html/bootstrap/_bootstrap-variables.scss | 14 +++++++------- .../docs/smoke-all/2026/11/12/custom-15304.scss | 11 +++++++++++ tests/docs/smoke-all/2026/11/12/issue-15304.qmd | 16 ++++++++++++++++ 6 files changed, 38 insertions(+), 10 deletions(-) create mode 100644 tests/docs/smoke-all/2026/11/12/custom-15304.scss create mode 100644 tests/docs/smoke-all/2026/11/12/issue-15304.qmd diff --git a/news/changelog-1.12.md b/news/changelog-1.12.md index bfc6660377a..a98a5096d76 100644 --- a/news/changelog-1.12.md +++ b/news/changelog-1.12.md @@ -34,6 +34,7 @@ All changes included in 1.12: - ([#9606](https://github.com/quarto-dev/quarto-cli/issues/9606)): Fix `format-links` entries written as `{format, text}` adding a second, default link for the same format instead of renaming its link. - ([#15269](https://github.com/quarto-dev/quarto-cli/pull/15269)): Fix `link-external-newwindow` overriding a `target` set explicitly on a link. (author: @mcanouil) - ([#15297](https://github.com/quarto-dev/quarto-cli/issues/15297)): Fix the table of contents highlight not following the scroll position when a heading id contains a `%` or a `:`. (author: @chenyangsu) +- ([#15304](https://github.com/quarto-dev/quarto-cli/issues/15304)): Fix theme compilation failing when a theme declares `$body-bg` or `$body-color` as `null`. (author: @SAMARTHJAISWAL) - ([#15320](https://github.com/quarto-dev/quarto-cli/pull/15320)): Update `theme: pandoc` to Pandoc 3.13's styles: - Links inherit the text color unless `linkcolor` is set, and horizontal rules and table borders follow the text color. - Printed output drops backgrounds and uses the 11pt print size of the other Quarto HTML themes. diff --git a/src/resources/formats/html/_quarto-variables-copy-code.scss b/src/resources/formats/html/_quarto-variables-copy-code.scss index 5a35bebf29f..9459824a186 100644 --- a/src/resources/formats/html/_quarto-variables-copy-code.scss +++ b/src/resources/formats/html/_quarto-variables-copy-code.scss @@ -2,7 +2,7 @@ $btn-code-copy-color: if( variable-exists(text-muted), $text-muted, - if(variable-exists(body-color), $body-color, $gray-900) + if(variable-exists(body-color) and $body-color != null, $body-color, $gray-900) ) !default; $btn-code-copy-color-active: if( diff --git a/src/resources/formats/html/bootstrap/_bootstrap-functions.scss b/src/resources/formats/html/bootstrap/_bootstrap-functions.scss index 51158bf061e..8f4b5f77f6a 100644 --- a/src/resources/formats/html/bootstrap/_bootstrap-functions.scss +++ b/src/resources/formats/html/bootstrap/_bootstrap-functions.scss @@ -162,7 +162,7 @@ navbar-bg: if( $default == #378dfc, - if(variable-exists(body-bg), $body-bg, $black), + if(variable-exists(body-bg) and $body-bg != null, $body-bg, $black), $default ), navbar-fg: rgba($black, 0.5), @@ -285,7 +285,7 @@ // being set $theme-bgs: ( litera: $white, - cyborg: if(variable-exists(body-bg), $body-bg, #000), + cyborg: if(variable-exists(body-bg) and $body-bg != null, $body-bg, #000), ); $bg: quarto-map.get($theme-bgs, $theme); diff --git a/src/resources/formats/html/bootstrap/_bootstrap-variables.scss b/src/resources/formats/html/bootstrap/_bootstrap-variables.scss index 6d8e0e8b76d..9fc87663a8e 100644 --- a/src/resources/formats/html/bootstrap/_bootstrap-variables.scss +++ b/src/resources/formats/html/bootstrap/_bootstrap-variables.scss @@ -86,8 +86,8 @@ $navbar-bg: theme-override-value( $btn-bg: if(variable-exists(secondary), $secondary, #6c757d) !default; $btn-fg: theme-contrast($btn-bg, $btn-bg) !default; -$body-contrast-bg: if(variable-exists(body-bg), $body-bg, $white); -$body-contrast-color: if(variable-exists(body-color), $body-color, $gray-900); +$body-contrast-bg: if(variable-exists(body-bg) and $body-bg != null, $body-bg, $white); +$body-contrast-color: if(variable-exists(body-color) and $body-color != null, $body-color, $gray-900); $navbar-fg: if( $navbar-bg == transparent, theme-override-value( @@ -178,7 +178,7 @@ $title-block-contast-color: $body-contrast-bg !default; $title-block-padding-top: 2.5em !default; // Footer coloring -$footer-bg: if(variable-exists(body-bg), $body-bg, #fff) !default; +$footer-bg: if(variable-exists(body-bg) and $body-bg != null, $body-bg, #fff) !default; $footer-fg: theme-contrast($footer-bg, $footer-bg, "AA") !default; $footer-font-size: 0.825em !default; $footer-left-font-size: $footer-font-size !default; @@ -261,12 +261,12 @@ $breadcrumb-divider: quote(">") !default; // table variable overrides $table-group-separator-color: mix( - if(variable-exists(body-color), $body-color, $gray-900), + if(variable-exists(body-color) and $body-color != null, $body-color, $gray-900), $body-contrast-bg, 50% ) !default; $table-group-separator-color-lighter: mix( - if(variable-exists(body-color), $body-color, $gray-900), + if(variable-exists(body-color) and $body-color != null, $body-color, $gray-900), $body-contrast-bg, 20% ) !default; @@ -301,8 +301,8 @@ $link-decoration: null !default; /// if a theme does not provide body-color or body-bg /// defaults to boostrap own default value for theses variables (in _variables.scss) $border-color: mix( - if(variable-exists(body-color), $body-color, $gray-900), - if(variable-exists(body-bg), $body-bg, $white), + if(variable-exists(body-color) and $body-color != null, $body-color, $gray-900), + if(variable-exists(body-bg) and $body-bg != null, $body-bg, $white), 15% ) !default; /// Make sure table border are the same as the border color (in case change in bootstrap default) diff --git a/tests/docs/smoke-all/2026/11/12/custom-15304.scss b/tests/docs/smoke-all/2026/11/12/custom-15304.scss new file mode 100644 index 00000000000..6eef162a543 --- /dev/null +++ b/tests/docs/smoke-all/2026/11/12/custom-15304.scss @@ -0,0 +1,11 @@ +/*-- scss:defaults --*/ +// Dart Sass recommends declaring a variable as `null` at the stylesheet root +// before setting it conditionally. Quarto must treat `null` as "not set". +$body-bg: null !default; +$body-color: null !default; + +/*-- scss:rules --*/ +#test-15304 { + background-color: $body-bg; + color: $body-color; +} diff --git a/tests/docs/smoke-all/2026/11/12/issue-15304.qmd b/tests/docs/smoke-all/2026/11/12/issue-15304.qmd new file mode 100644 index 00000000000..b541fd43dd3 --- /dev/null +++ b/tests/docs/smoke-all/2026/11/12/issue-15304.qmd @@ -0,0 +1,16 @@ +--- +title: "Theme declaring a null body-bg and body-color" +format: + html: + theme: + - default + - custom-15304.scss +_quarto: + tests: + html: + ensureCssRegexMatches: + - ['#test-15304\s*\{\s*background-color:\s*#fff;\s*color:\s*#212529;?\s*\}'] +--- + +A theme that declares `$body-bg: null !default;` or `$body-color: null !default;` +must render with Bootstrap's default body colours.