The mixin used to generate the button css colour states is called button-variant() which is located in bootstrap/scss/mixins.
This sass mixin does have the parameter capability for handling custom .btn hover and active colour states...
@mixin button-variant(
$background,
$border,
$hover-background: darken($background, 7.5%),
$hover-border: darken($border, 10%),
$active-background: darken($background, 10%),
$active-border: darken($border, 12.5%)
) {
//...
}
But as you can see the hover and active params are $default: params using sass colour darken() function as values to calculate the passed $theme-colors colour value to automatically generate colours for the states.
This makes it impossible to handle button state colours by just using $theme-colors.
There are a few ways to customise the .btn active and hover state
colours whilst minimising compiled css and avoiding
duplicate/overriding selectors in compiled css output.
First method (easiest)
See scss below which handles bootstrap vendor @imports individually and handling custom vars and map-removals in the correct order, so bootstrap compiles and uses variables correctly.
Follow comments in the scss so you know what is happening...
// import initial bootstrap vendors
@import "~bootstrap/scss/functions";
@import "~bootstrap/scss/variables";
@import "~bootstrap/scss/mixins";
// remove unused default bootstrap colours from bs colour maps to prevent larger compiled css file sizes
// this will also speed up compiling time as you are not generating css for all bootstrap standard colours
// if you wish to keep some standard bootstrap colours then remove the ones you want to keep from the map-remove lists below
$colors: map-remove($colors, "blue","indigo","purple","pink","red","orange","yellow","green","teal","cyan","white","gray","gray-dark");
$grays: map-remove($grays, "100","200","300","400","500","600","700","800","900");
$theme-colors: map-remove($theme-colors, "primary","secondary","success","danger","warning","info","light","dark");
// use sass @debug to check dump logs of your colour maps after modifying them if you wish...
// @debug $colors;
// @debug $grays;
// @debug $theme-colors;
// now add your custom colour variables
$new-color-1: #00a89c;
$new-color-2: #e61b53;
// now add your custom colour maps using above variables
$colors: (
"newcolor1": $new-color-1,
"newcolor2": $new-color-2
);
// you can always tidy this up by including these variables and any other bootstrap theming override variables into a separate sass _vars.scss file
// and then import _vars.scss here (before root.scss and after mixins.scss|map-removals)...
//@import "./vars";
// now import the rest of your needed bootstrap scss vendor files below this
// the below imports will now use any variable overrides you've defined above
// if you want to reduce you css output file size and speed up compiling
// you can remove unused scss vendor imports below, for example i've removed breadcrumb, toasts and carousel
@import "~bootstrap/scss/root";
@import "~bootstrap/scss/reboot";
@import "~bootstrap/scss/type";
@import "~bootstrap/scss/images";
@import "~bootstrap/scss/code";
@import "~bootstrap/scss/grid";
@import "~bootstrap/scss/tables";
@import "~bootstrap/scss/forms";
@import "~bootstrap/scss/buttons";
@import "~bootstrap/scss/transitions";
@import "~bootstrap/scss/dropdown";
@import "~bootstrap/scss/button-group";
@import "~bootstrap/scss/input-group";
@import "~bootstrap/scss/custom-forms";
@import "~bootstrap/scss/nav";
@import "~bootstrap/scss/navbar";
@import "~bootstrap/scss/card";
//@import "~bootstrap/scss/breadcrumb";
@import "~bootstrap/scss/pagination";
@import "~bootstrap/scss/badge";
@import "~bootstrap/scss/jumbotron";
@import "~bootstrap/scss/alert";
@import "~bootstrap/scss/progress";
@import "~bootstrap/scss/media";
@import "~bootstrap/scss/list-group";
@import "~bootstrap/scss/close";
//@import "~bootstrap/scss/toasts";
@import "~bootstrap/scss/modal";
@import "~bootstrap/scss/tooltip";
@import "~bootstrap/scss/popover";
//@import "~bootstrap/scss/carousel";
@import "~bootstrap/scss/spinners";
@import "~bootstrap/scss/utilities";
@import "~bootstrap/scss/print";
Because we emptied the $theme-colors map, bootstrap will not compile @each loops which utilise $theme-colors because it is now empty.
We can now manually use button-variant() mixin inside any .btn-* selector to create custom buttons without add extra css to the compiled output.
This option is easiest because you can pass any colour you wish to the button-variant() params.
.btn-primary {
@include button-variant(
$new-color-1, // background
$new-color-1, // border
$new-color-1, // hover background (customise how you wish)
$new-color-1, // hover border (customise how you wish)
$new-color-1, // active background (customise how you wish)
$new-color-1 // active border (customise how you wish)
);
}
.btn-secondary {
@include button-variant(
$new-color-2, // background
$new-color-2, // border
$new-color-2, // hover background (customise how you wish)
$new-color-2, // hover border (customise how you wish)
$new-color-2, // active background (customise how you wish)
$new-color-2 // active border (customise how you wish)
);
}
Second method (trickier)
Using the above code, re-introduce $theme-colors and modify/override the @include button-variant() in mixins.scss.
Removed the custom button selectors from the above code before continuing.
This method is trickier to precisely control hover and active state colours because @include button-variant() will use the same param scss colour adjustments for each passed colour.
You can try this... re-introduce $theme-colors before root.scss and immediately after $colors map array.
$theme-colors: (
"primary": $new-color-1,
"secondary": $new-color-2
);
Then create an overriding button mixin to handle all button variant calls.
Add this bootstrap v4.5.3 modified button-variant mixin after our @import "~bootstrap/scss/mixins"; and before the map-removals.
You can put this in a sass file called _mixins.scss in your project and import like this @import "./mixins"; to keep things tidy.
You can also keep all your custom mixins for this project in "./mixins" too.
Now we can modify the custom @mixin button-variant() parameters to handle passed $theme-colors.
// i've customised params in the button-variant() mixin below as an example
// see original default mixin params as comments below
// $background
// $border
// $hover-background: darken($background, 7.5%)
// $hover-border: darken($border, 10%)
// $active-background: darken($background, 10%)
// $active-border: darken($border, 12.5%)
@mixin button-variant(
$background,
$border,
$hover-background: lighten($background, 10%),
$hover-border: lighten($border, 10%),
$active-background: lighten($background, 2.5%),
$active-border: lighten($border, 2.5%)
) {
color: color-yiq($background);
@include gradient-bg($background);
border-color: $border;
@include box-shadow($btn-box-shadow);
@include hover() {
color: color-yiq($hover-background);
@include gradient-bg($hover-background);
border-color: $hover-border;
}
&:focus,
&.focus {
color: color-yiq($hover-background);
@include gradient-bg($hover-background);
border-color: $hover-border;
@if $enable-shadows {
@include box-shadow($btn-box-shadow, 0 0 0 $btn-focus-width rgba(mix(color-yiq($background), $border, 15%), .5));
} @else {
// Avoid using mixin so we can pass custom focus shadow properly
box-shadow: 0 0 0 $btn-focus-width rgba(mix(color-yiq($background), $border, 15%), .5);
}
}
// Disabled comes first so active can properly restyle
&.disabled,
&:disabled {
color: color-yiq($background);
background-color: $background;
border-color: $border;
// Remove CSS gradients if they're enabled
@if $enable-gradients {
background-image: none;
}
}
&:not(:disabled):not(.disabled):active,
&:not(:disabled):not(.disabled).active,
.show > &.dropdown-toggle {
color: color-yiq($active-background);
background-color: $active-background;
@if $enable-gradients {
background-image: none; // Remove the gradient for the pressed/active state
}
border-color: $active-border;
&:focus {
@if $enable-shadows and $btn-active-box-shadow != none {
@include box-shadow($btn-active-box-shadow, 0 0 0 $btn-focus-width rgba(mix(color-yiq($background), $border, 15%), .5));
} @else {
// Avoid using mixin so we can pass custom focus shadow properly
box-shadow: 0 0 0 $btn-focus-width rgba(mix(color-yiq($background), $border, 15%), .5);
}
}
}
}