5
votes

I have a website where each section has its own primary color.

I'd like to put something in Bootstrap 4's Sass code, to override the primary color depending on a body class I set.

I have this, but it's not working so far:

$theme-colors: () !default;
$theme-colors: map-merge((
    // primary: $blue,
    // secondary: $gray-600,
    success: $green,
    info: $cyan,
    warning: $yellow,
    danger: $red,
    light: $gray-100,
    dark: $gray-800
), $theme-colors) !default;

// override according to portal
html {
    &.portal-1 {
        $theme-colors: map-merge((
            primary: #f1b36d
        ), $theme-colors);
    }

How can this be implemented in Bootstrap 4's Sass file?

2
Here is an excellent explanation of how to accomplish this: stackoverflow.com/questions/41791461/…simsom
Keep in mind that Sass is compiled into static CSS prior to runtime, so it can never have context of what's going on in your browser. So, if you're asking if you can override a variable throughout Bootstrap's Sass files based on the presence of a class on your page, you cannot. You would need to modify the Sass to cascade into all affected elements for that class and replace the variable throughout. Alternatively you could look into CSS custom variables, but browser support isn't all there right now.Jon Uleis

2 Answers

2
votes

You can't change the sass variables which are already converted to static CSS dynamically at the client side. However, to build theme system you can apply one of the following options:

1. Generate independent theme

Put a theme argument in your build system which will generate different themes CSS Ex: grunt build-sass --theme=brown

var themes = {
    "default": "https://bootswatch.com/flatly/bootstrap.min.css",
    "cerulean" : "https://bootswatch.com/cerulean/bootstrap.min.css"
}

// Use something like this to add theme: (You can also append instead of overriding whole head html)
var headHTML = document.getElementsByTagName('head')[0].innerHTML;
headHTML    += '<link type="text/css" rel="stylesheet" href="' + themes.cerulean +'">';
document.getElementsByTagName('head')[0].innerHTML = headHTML;

2. Change properties based upon the parent class

You can have a base CSS which defines general CSS. And then you can have separate CSS Properties based upon the parent

In the following example update green-theme class to blue-theme and vice versa

div[class^=component] {
  display: inline-block;
  width:150px;
  height: 150px;
  margin: 1em;
  border: 1px solid black;
  box-shadow: 1px 1px 5px gray;
  border-radius:1em;
}

/* Colors*/
$blue1: #3066BE; 
$blue2: #090C9B;
$green1: #5C946E; 
$green2: #80C2AF;

/* Blue Theme */
.blue-theme {
  .component1 {
    background-color: $blue1;
  }
  
  .component2 {
    background-color: $blue2;
   }
}
/* Green Theme */
.green-theme {
  .component1 {
    background-color: $green1;
  }
  
  .component2 {
    background-color: $green2;
   }
}
<div class="green-theme" id="mainBody">
    <div class="component1">
    </div>
    
     <div class="component2">
    </div>
</div>

*Run Snippet won't work as we are using SCSS *

1
votes

Make a scss file structure like this,

- vendors
  - bootstrap
    - stylesheets /*[Bootstrap 4 official sass files]*/
      - _bootstrap.scss
- scss
  - themes
    - _theme-1.scss
    - _theme-2.scss
  - _variables.scss
  - styles.scss
  - portal-1.scss
  - portal-2.scss

_variables.scss

@import "../vendors/bootstrap/stylesheets/bootstrap/variables";
@import "../vendors/bootstrap/stylesheets/bootstrap/mixins";
/* override bootstrap default variables ... */
/* custom variables with !default ... */

styles.scss

@import "variables";
@import "../vendors/bootstrap/stylesheets/bootstrap";
/* custom styles ... */

themes/_theme-1.scss

@import "../variables";
/* change value bootstrap and custom default variables ... */
$brand-primary:         #428bca
$brand-success:         #5cb85c;
$brand-info:            #5bc0de;
$brand-warning:         #f0ad4e;
$brand-danger:          #d9534f;
$body-bg:               #eff;

themes/_theme-2.scss

@import "../variables";
/* change value bootstrap and custom default variables ... */
$brand-primary:         #C04848;

portal-1.scss

@import "themes/_theme-1";
/* change style with new variable bootstrap default components ... */
.portal-1 {
    @import "../vendors/bootstrap/stylesheets/bootstrap/buttons";
    @import "../vendors/bootstrap/stylesheets/bootstrap/alerts";
   /* custom style overrides ... */
}

portal-2.scss

@import "themes/_theme-2";
/* change style with new variable bootstrap default components ... */
.portal-2 {
    @import "../vendors/bootstrap/stylesheets/bootstrap/buttons";
    @import "../vendors/bootstrap/stylesheets/bootstrap/alerts";
   /* custom styles from style.scss overrides ... */
}

After sass compilation we will get 3 files styles.css, portal-1.css and portal-2.css. Use style.css by default and others include in head tag for theming.

<html>
    <head>
         <link href="styles.css" rel="stylesheet" />
         <link href="portal-1.css" rel="stylesheet" />
    </head>
    <body>
        <button class="btn btn-primary">BUTTON</button>
        <div class="portal-1">
            <button class="btn btn-primary">BUTTON</button>
        </div>
    </body>
</html>