twbs / bootstrap

The most popular HTML, CSS, and JavaScript framework for developing responsive, mobile first projects on the web.
https://getbootstrap.com
MIT License
170.14k stars 78.78k forks source link

Nested imports / variables broken in 5.1 #34738

Closed stephenhebert closed 3 years ago

stephenhebert commented 3 years ago

In v5.0.2, it is possible to import a customized bootstrap sass file within a selector:

.new-design-system {
   @import 'bootstrap-custom'
}

With this, and BS5's new namespace, it is possible to have an older version of bootstrap side-by-side with a compartmentalized custom BS5, javascript and all. While not arguably not ideal (or not officially supported), this is extremely useful when iterating over an application with a legacy design system and gradually incorporating a new BS5-based design system.

In v5.1.0, this functionality is broken as the sass will not compile without importing functions, variables, and root at the root level, which also breaks the customizations.

ffoodd commented 3 years ago

Could you please elaborate? What would work or wouldn't, in such case? What's the difference?

stephenhebert commented 3 years ago

@ffoodd I'm not exactly sure if your asking specifically about the rationale of the use case or the issue, so I'll take a shot at both.

Rationale for Use Case

This allows something like:

<!-- legacy (eg, BS v2, v4, etc) style system heading, font, font-size, color -->
<h5 class="text-primary">Heading</h5>
<div class="new-design-system">
  <!-- new BS5 design system heading, font, font-size, color -->
  <h5 class="text-primary">Heading</h5>
</div>

It's a simple example, but in v5.0.2 this also works will all BS components, including jQuery/popper, etc without issue.

Configuration

Something like this...

new_design_system.scss

.new-design-system {
    @import "bootstrap5";
}

custom_bootstrap.scss

// Custom bootstrap 5 implementation

// 1. Include functions first (so you can manipulate colors, SVGs, calc, etc)
@import "bootstrap5/functions";

// 2. Include any default variable overrides here
$font-family-serif:
  "Roboto Slab",
  "Lucida Bright",
  Lucidabright,
  "Lucida Serif", Lucida,
  "Bitstream Vera Serif",
  "Liberation Serif",
  serif !default;

$spacer: 1rem !default;
$spacers: (
  0: 0,               // 0
  1: $spacer * .25,   // 4px
  2: $spacer * .5,    // 8px
  3: $spacer * .75,   // 12px
  4: $spacer,         // 16px
  5: $spacer * 1.25,  // 20px
  6: $spacer * 1.5,   // 24px
  7: $spacer * 2,     // 32px
  8: $spacer * 2.5,   // 40px
) !default;

$grid-gutter-width: 24px;
$gutters: (
  0: 0,
  1: $spacer * .25,
  2: $spacer * .5,
  3: $spacer,
  4: $spacer * 1.5,
  5: $spacer * 3,
);

$h1-font-size: 40px !default;
$h2-font-size: 32px !default;
$h3-font-size: 24px !default;
$h4-font-size: 20px !default;
$h5-font-size: 16px !default;
$h6-font-size: 12px !default;
$small-font-size: 14px;
$tiny-font-size: 12px;

// 3. Include remainder of required Bootstrap stylesheets
@import "bootstrap5/variables";
@import "bootstrap5/mixins";
@import "bootstrap5/utilities";

// 4. Include any optional Bootstrap components as you like
@import "bootstrap5/reboot";
@import "bootstrap5/type";
@import "bootstrap5/images";
@import "bootstrap5/containers";
@import "bootstrap5/grid";
@import "bootstrap5/tables";
@import "bootstrap5/forms";
@import "bootstrap5/buttons";
@import "bootstrap5/transitions";
@import "bootstrap5/dropdown";
@import "bootstrap5/button-group";
@import "bootstrap5/nav";
@import "bootstrap5/navbar";
@import "bootstrap5/card";
@import "bootstrap5/accordion";
@import "bootstrap5/breadcrumb";
@import "bootstrap5/pagination";
@import "bootstrap5/badge";
@import "bootstrap5/alert";
@import "bootstrap5/progress";
@import "bootstrap5/list-group";
@import "bootstrap5/close";
@import "bootstrap5/toasts";
@import "bootstrap5/modal";
@import "bootstrap5/tooltip";
@import "bootstrap5/popover";
@import "bootstrap5/carousel";
@import "bootstrap5/spinners";
@import "bootstrap5/offcanvas";
@import "bootstrap5/placeholders";

// Helpers
@import "bootstrap5/helpers";

$utilities: map-merge(
  $utilities,
  (
    "line-height": map-merge(
      map-get($utilities, "line-height"),
      (
        values: map-merge(
          map-get(map-get($utilities, "line-height"), "values"),
          (
            h1: 40px,
            h2: 32px,
            h3: 24px,
            h4: 20px,
            h5: 16px,
            h6: 12px,
            small: 14px,
            tiny: 12px,              
          ),
        ),
      ),
    ),
  )
);

// Utilities
@import "bootstrap5/utilities/api";

@import ... more custom importants

Issue in v5.1.0

Attempting the same thing in v5.1.0 with the same configuration results in sass compilation errors (eg, missing function to-rgb, missing variables).

If the functions, variables, and root files are included at the root level, the sass compiles, but the customizations are lost, even if they are also included at the root level.

conradfr commented 3 years ago

Personally I was using a selector to add a dark theme option, which don't work anymore with 5.1.

It was not the most optimized way to do it obviously, but at least it worked for me, now I'm stuck on 5.0 until I figure something out.

stephenhebert commented 3 years ago

I just attempted to reproduce the issue in a sandbox environment, but I wasn't able to.

https://codesandbox.io/s/nested-bootstrap-5-25dud

It must be related to my configuration -- possibly the python sass compiler.

The error I'm seeing in my environment is:

CompileError at ...
Error: Function not found: to-rgb
...
>> $_map: map-merge($_map, ($key: call(get-function($func), $_args...)));
GuilhermeSantos001 commented 3 years ago

I was able to reset my settings with the new v5.1 version, thanks to zim's answer in the following thread.

First I set my standards:

// ------------------------------------------------------------------------------
// Author: GuilhermeSantos001
// Update: 28/08/2021
//

$primary: #004a6e;
$secondary: #f6d816;
$light-gray: #f1f1f1;
$dark-gray: #414141;

$body-bg: #f5f5f5;
$body-color: #004a6e;

$input-bg: #fafafa;

$component-active-color: $dark-gray;
$component-active-bg: #e0e0e0;

$link-hover-color: #ebcd0f;
$nav-tabs-link-active-color: #ebcd0f;
$nav-pills-link-active-color: #ebcd0f;
$nav-link-font-size: 14px;
$nav-link-font-weight: bold;

$offcanvas-bg-color: $light-gray;

$accordion-button-active-bg: $primary;
$accordion-button-active-color: $secondary;

@import "../../../node_modules/bootstrap/scss/bootstrap.scss";
@import "../../../node_modules/bootstrap-icons/font/bootstrap-icons.css";
@import "../../../node_modules/plyr/src/sass/plyr.scss";

// Bootstrap custom variables
$colors-custom: (
    "light-gray": $light-gray,
    "dark-gray": $dark-gray,
);

$theme-colors: map-merge($theme-colors, $colors-custom);

@import "../plugins/please-wait/margin.scss";
@import "../plugins/spinkit/all.scss";

// Themes
@import "dark.scss";

// Here I will import or write any other style that depends on the variables defined earlier, for example:

.bg-light-gray {
    background-color: map-get($theme-colors, "light-gray");
}
.bg-dark-gray {
    background-color: map-get($theme-colors, "dark-gray");
}

.text-light-gray {
    color: map-get($theme-colors, "light-gray");
}
.text-dark-gray {
    color: map-get($theme-colors, "dark-gray");
}

I define everything that I will use, and then import my themes:

// ------------------------------------------------------------------------------
// Author: GuilhermeSantos001
// Update: 28/08/2021
//

@import "../../../node_modules/bootstrap/scss/functions";
@import "../../../node_modules/bootstrap/scss/variables";
@import "../../../node_modules/bootstrap/scss/mixins";

.dark {
    $primary: #242424;
    $secondary: #f6d816;
    $light-gray: #f1f1f1;
    $dark-gray: #414141;

    $body-bg: #383838;
    $body-color: #f6d816;

    $input-bg: #fafafa;

    $component-active-color: $dark-gray;
    $component-active-bg: #e0e0e0;

    $link-hover-color: #ebcd0f;
    $nav-tabs-link-active-color: #ebcd0f;
    $nav-pills-link-active-color: #ebcd0f;
    $nav-link-font-size: 14px;
    $nav-link-font-weight: bold;

    $offcanvas-bg-color: $light-gray;

    $accordion-button-active-bg: $primary;
    $accordion-button-active-color: $secondary;

    $theme-colors: (
        "primary": $primary,
        "secondary": $secondary,
        "success": $success,
        "danger": $danger,
        "info": $indigo,
        "dark": $dark,
        "light": $light,
    );

    /* redefine theme color variables */
    @each $color, $value in $theme-colors {
        --#{$variable-prefix}#{$color}: #{$value};
    }

    /* redefine theme color rgb vars (used for bg- colors) */
    $theme-colors-rgb: map-loop($theme-colors, to-rgb, "$value");
    @each $color, $value in $theme-colors-rgb {
        --#{$variable-prefix}#{$color}-rgb: #{$value};
    }

    --#{$variable-prefix}body-color: #{$body-color};
    --#{$variable-prefix}body-bg: #{$body-bg};

    @import "../../../node_modules/bootstrap/scss/bootstrap.scss";
}

Works perfectly when I add the "dark" class to the body. Now I can update my bootstrap to the latest version! 🚀

GUI commented 3 years ago

I think this is maybe related to this this libsass bug: https://github.com/sass/libsass/issues/2830

I also ran into this when using libsass 3.6.5. However, I found a couple potential workarounds:

  1. Use dart-sass instead. The original approach of importing bootstrap inside a nested selector seems to work with dart-sass (I tested with dart-sass-embedded 1.0.0-beta.11).
  2. I was also able to get it to work with libsass by importing the bootstrap functions into the top-level namespace. This still accomplishes what I was trying to achieve (namespacing the Bootstrap CSS classes), but this seems to sidestep the issue of libsass not finding functions defined in a nested scope:

    @import "bootstrap/scss/_functions";
    .my-wrapper {
      @import "bootstrap/scss/bootstrap";
    }
mdo commented 3 years ago

I think we can close this is out as a Sass bug. Let me know if y'all think we need to include a mention in the docs somewhere for this.

EdCharbeneau commented 2 years ago

I read on the main page that people are having a hard time with Sass and Visual Studio. I wrote about how this can be set up very easily without third party tools or libraries. https://edcharbeneau.com/2021-04-24-setting-up-sass-with-blazor/

clifgriffin commented 2 years ago

I can confirm that the solution for libsass provided by @GUI works perfectly.