Iāve noticed in _variables.scss that the brand colours have been moved to a nested object.
Up to now, Iāve been specifying variable overrides in a _custom.scss in my projects like this:
@import "custom";
@import "node_modules/bootstrap/scss/bootstrap";
Iād then override the variables I wanted in my _custom.scss file like this:
$brand-primary: #fc0;
$font-family-sans-serif: "Open Sans", sans-serif;
How do I override values on a per-variable basis now that theyāre inside an object? For example, I have a project where I want the brandās primary color to be green and not blue.
Sorry if this a n00b question, but Iām under the impression that object members like $theme-colors[primary]
_arenāt_ overridable in Sass without overriding the whole object, in which case these _seriously_ reduces the configurability of Bootstrap in version 4.
If Iām doing something wrong, or I _can_ override specific members of objects in Sass, then please let me know.
While it does appear you cannot override part of the Sass maps, much like our variables, they do have the !default
flag. See this example for how you can change the variable or Sass map. IMO this is a fine approach as it maps to variablesācopy, paste, and change the value.
How do I override values on a per-variable basis now that theyāre inside an object?
We also still have all the regular color variables, so you can customize the Sass map or you can change the base variables. See the variables file:
$blue: #007bff !default;
$indigo: #6610f2 !default;
$purple: #6f42c1 !default;
$pink: #e83e8c !default;
$red: #dc3545 !default;
$orange: #fd7e14 !default;
$yellow: #ffc107 !default;
$green: #28a745 !default;
$teal: #20c997 !default;
$cyan: #17a2b8 !default;
$colors: (
blue: $blue,
indigo: $indigo,
purple: $purple,
pink: $pink,
red: $red,
orange: $orange,
yellow: $yellow,
green: $green,
teal: $teal,
cyan: $cyan,
white: $white,
gray: $gray-600,
gray-dark: $gray-800
) !default;
$theme-colors: (
primary: $blue,
secondary: $gray-600,
success: $green,
info: $cyan,
warning: $yellow,
danger: $red,
light: $gray-100,
dark: $gray-800
) !default;
@mdo I get that the theme colours have been mapped to ānamedā colour variables, but if I want my theme to be primarily green, I donāt want to be changing the value of $blue
to be a green since $theme-colors[primary]
is mapped to $blue
.
Iām not liking the fact I have to copy-and-paste and override X, Y and Z just to change _one_ setting. What happens if the keys in the map change? My themeās going to break. Why do I have all these dependencies just to change _one_ single colour in Bootstrap?
@martinbean you don't need to change the value of $blue
to green, you only have to change the primary
color to $green
in $theme-colors
@dushkostanoeski But I have to copy the _whole_ of $theme-colors
map into my _custom.scss file, and then also also the individual colour variables ($blue
etc) because _theyāre_ referenced in the map.
All that, just to change one colour!
You don't have to import the color variables if you import the _variables.scss
file in your custom.scss
file
@houfio That defeats the point of them having the !default
flag if I just have to import them and override them any way?
I guess so. Are you sure you have to copy them if you don't reference the file? It should work fine, because the bootstrap base file imports it too.
@houfio Did you take a look at my original post? I define custom variable values in a _custom.scss file thatās included before Bootstrap. Itās in fact, what the comments say to do in the _variables.scss file: https://github.com/twbs/bootstrap/blob/v4-dev/scss/_variables.scss#L3-L4
However, with colours now being nested in a map, itās created this awkward scenario where I need to copy whole blocks of variable definitions and hope Bootstrap doesnāt change the name or āshapeā of the map (which is has been known to do in the past); or include its variables files before mine, making the point specifying values to override the defaults pointless.
I know it it included before bootstrap, but because of the !default
, it doesn't reassign the variable and uses the one in your _custom.scss
file. Your _custom.scss
file can't find the color variables, but iirc that shouldn't be a problem, since the map gets accessed in files where the colors _are_ imported (unless I'm missing another problem)
@houfio My problem is, I just want to set the primary brand colour to be something other than blue. Before, I could have a _custom.scss file with this in:
$brand-primary: #006400;
That was it. Everything the āprimaryā colour (buttons etc) would then be a dark green when Bootstrap was compiled.
Now I canāt do that as that variableās been removed and instead the theme colours folded into a map.
If you don't need any of the other colors you can just do
$theme-colors: (
primary: #006400
)
since all the calls to the map are loops.
@houfio I _do_ want the other colours though! I just want to override _one_ of the themeās colours, and not have to copy a whole map to do so!
I suppose this change is good if you want much customization, but not so much if you just want to change one color. ~But copying a map isn't _that_ bad, is it?~
You can also just import the variables file, which _does_ defeat the point of the !default
, but allows you to use the map_merge
method.
@houfio My gripe with copying a whole map (and its dependent variables) is that, Iām then relying on Bootstrap not to change anything, which was the point of having a file of variable overrides in the first place. It just seems I have to go ātoo deepā into Bootstrap now to change one thing.
This change makes overriding not work. Coming from a Rails example. I too want to change my theme to green. The following doesn't work. And it's not feasible for me to go and change the variables.scss
``` application.scss
// Custom bootstrap variables must be set or imported before bootstrap.
$green: #89B630;
$theme-colors: (
primary: $green
);
@import "bootstrap";
```
Currently have to change $blue
to get the correct result.
@kartikluke Ideas in #22891 might help
@cr101 Doesnāt really help, as it seems to be people discussing the same issue as in here.
Bringing over the entire Sass map doesn't seem unreasonable to me... is the biggest concern that this feels heavy handed when compared to the old $brand-{color}
variables?
is the biggest concern that this feels heavy handed when compared to the old $brand-{color} variables?
@mdo Exactly that. When overriding a $brand-{color}
variable, Iām overriding what I want, and only what I want. To copy over a whole Sass map just to change _one_ colour in that map just seems overly cumbersome, especially when I also have to re-define the individual colour variables referenced in that map, i.e. $blue
et al. So changing the primary color goes from this:
$brand-primary: #006600;
To this:
$gray-100: #f8f9fa;
$gray-600: #868e96;
$gray-800: #343a40;
$red: #dc3545;
$yellow: #ffc107;
$green: #006600; // This is the only variable I wanted to change
$cyan: #17a2b8;
$theme-colors: (
primary: $green,
secondary: $gray-600,
success: $green,
info: $cyan,
warning: $yellow,
danger: $red,
light: $gray-100,
dark: $gray-800
);
@martinbean
will this not work?
$theme-colors = map_merge($theme-colors, {success: $green});
@bkdotcom Not unless I import the whole of _variables.scss first š©
@martinbean @mdo The solution outlined here seems to be the best option. https://github.com/twbs/bootstrap/issues/22891#issuecomment-316463806
// In a custom variables file...
$theme-colors: (
primary: red
);
// In Bootstrap's _variables.scss file...
$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);
@kartikluke Nice! That does work: https://codepen.io/anon/pen/XaJeVd. I'll see about a PR shortly.
@hokiecoder figured it out. This should make it much easier to work with the new maps.
Please see #23260 for @hokiecoder's suggestion that @kartikluke pointed out here. Any feedback is most definitely welcomed!
I understand the concern. I honestly like this map feature.
Most helpful comment
@mdo Exactly that. When overriding a
$brand-{color}
variable, Iām overriding what I want, and only what I want. To copy over a whole Sass map just to change _one_ colour in that map just seems overly cumbersome, especially when I also have to re-define the individual colour variables referenced in that map, i.e.$blue
et al. So changing the primary color goes from this:To this: