Specify hover colours directly in customized Bootstrap 4 - css

I'm using a custom build of Bootstrap 4.5.3 with some fairly simple changes.
Here's my custom SCSS:
$newcolor1: #00a89c;
$newcolor2: #e61b53;
$colors: (
"newcolor1": $newcolor1,
"newcolor2": $newcolor2
);
$primary: $newcolor1;
$theme-colors: (
"primary": $primary,
"newcolor2": $newcolor2
);
#import "bootstrap";
I'm adding two new colours, setting "primary" to be newcolor1, and adding a theme for newcolor2 so that I can do e.g. btn-newcolor2.
Bootstrap automatically calculates variants of these colours for use with hover, focus, etc, which look fine to me, but my client wants to specify the hover colours directly and that has taken me beyond my very limited Sass knowledge.
Looking through the source files, it seems as though Bootstrap darkens the base colour by a fixed percentage to create the hover version. Is there a way that I could force it to use a specific colour for .btn-primary:hover and .btn-newcolor2:hover? The ideal would be if I could get it to use the specified colour where I have provided one, and use the default behaviour (darkening by a fixed percentage) where I haven't.

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);
}
}
}
}

Related

is there a way to use bootstrap 5 custom color directly in the class attribute?

like we do:
<span class="text-primary">some text</span>
I want to know if there is a way to do:
<span class="text-red-300">some text</span>
red-300 is a bootstrap 5 custom color and there are others in the following link.
https://getbootstrap.com/docs/5.0/customize/color/
There is no way to use $red-300 directly in CSS. It's only possible using SASS because $red-300 is a SASS variable.
However, the base colors are also available as CSS variables. For example, --bs-red is the same as $red and $red-500. So, it could be used as a CSS variable like this...
.text-red-500 {
color: var(--bs-red);
}
CSS Demo
If you wanted to use SASS for $red-300, it would be done like this:
#import "functions";
#import "variables";
.text-red-300 {
color: $red-300;
}
SASS demo
Indeed there are no Bootstrap native classes or mixins to realise that out of the box. On the other hand ... Bootsstrap is build to be extended: Using SASS you can extend Bootstrap and create the helper classes on the fly.
NOTE: The SASS code example below is done to YOUR QUESTION (= all colors = 900 additional helper classes). Maybe you may like to reduce that huge amount of additional code by building the color classes only to your indeed needed colors. Please feel free to adapt that code to your needs.
//### make sure you have imported bootstrap function & variables first
#import 'functions';
#import 'variables';
//### SASS function to extend Bootstrap
//### --> quick and dirty demo example!!!
#mixin make-color-classes( $class_prefix, $color_name, $color ){
// note: positive values = tint | negative values = shade
$swatch_variations: (80%, 60%, 40%, 20%, 0, -20%, -40%, -60%, -80%);
$i: 1;
#each $variation in $swatch_variations {
// process bootstrap color
#if ($variation > 0){
$swatch_color: tint($color);
}#else if ($variation < 0) {
$variation: $variation * -1;
$swatch_color: shade($color);
}#else{
$swatch_color: $color;
}
// write class
$color_number: $i * 100;
.#{$class_prefix}-#{$color_name}-#{$color_number} {
color: tint-color($color, $variation );
}
$i: $i + 1;
}
}
//### NOW:
//### create helper classes for a single color
#include make-color-classes('text', 'blue', $blue);
//### NOW EXTENDED:
//### create helper classes for all named default bootstrap colors
$colors_to_use: $colors;
#each $color_name, $color in $colors_to_use {
#include make-color-classes('text', $color_name, $color);
}

MDC-Web CSS theme colors not defined

When running locally my front end i inspect button element and the color --mdc-theme-primary is not defined even when it is.
Inspecting the element:
Index.html:
<button class="mdc-tab mdc-tab--active" aria-selected="true" tabindex="0">
<span class="mdc-tab__content">
<span class="mdc-tab__text-label">Home</span>
</span>
</button>
Firefox Inspect element result, --mdc-theme-primary not defined using fallback value:
.mdc-tab--active .mdc-tab__text-label {
color: #e3f2fd;//this line is disabled in console is dashed
color: var(--mdc-theme-primary, #e3f2fd);
}
Using the Theming Guide! I've set up my files as follows:
_themecolor.scss
$mdc-theme-primary: #e3f2fd;
$mdc-theme-on-primary: #442C2E;
$mdc-theme-secondary: #0d48a1;
$mdc-theme-on-secondary: rgb(235, 15, 33);
$mdc-theme-surface: #000000;
$mdc-theme-on-surface: #442C2E;
$mdc-theme-background: #000000;
$mdc-theme-on-background: #442C2E;
_variables.scss (for completion, not needed for this)
.topAppBar-margin-fix {
top: 0;
left: 0;
}
app.scss
#import "./_themecolor";
#import "./_variables";
#import "#material/top-app-bar/mdc-top-app-bar";
#import "#material/typography/mdc-typography";
#import "#material/button/mdc-button";
#import "#material/tab-bar/mdc-tab-bar";
#import "#material/tab-bar/mixins";
#import "#material/tab-scroller/mdc-tab-scroller";
#import "#material/tab-indicator/mdc-tab-indicator";
#import "#material/tab-indicator/mixins";
#import "#material/tab/mdc-tab";
#import "#material/tab/mixins";
.mdc-tab__text-label{
//#include mdc-tab-active-text-label-color(on-primary);
//--mdc-theme-primary: red;
//--mdc-theme-primary: $mdc-theme-on-secondary;
}
body {
color: blue;
}
app.js
import {MDCTabBar} from '#material/tab-bar';
const tabBar = new MDCTabBar(document.querySelector('.mdc-tab-bar'));
import {MDCTabScroller} from '#material/tab-scroller';
const tabScroller = new MDCTabScroller(document.querySelector('.mdc-tab-scroller'));
import {MDCTab} from '#material/tab';
const tab = new MDCTab(document.querySelector('.mdc-tab'));
Serving this site inside the scroll bar the color of the Home label in the button is the fallback color and not the primary color or whatever i set with the mixin.
I tried:
case a)
.mdc-tab__text-label{
#include mdc-tab-active-text-label-color(on-primary);
}
case b)
.mdc-tab__text-label{
--mdc-theme-primary: red;
}
case c)
.mdc-tab__text-label{
--mdc-theme-primary: $mdc-theme-on-secondary;
}
case a) tried using also a simple color as "red" and still the color used is the fallback one.
case b) works as intended being red.
case c) the label color is black instead of red as the $mdc-theme-on-secondary defined in themecolor.scss
Also tried a) b) and c) using
.mdc-tab--active .mdc-tab__text-label{
//repeating each case, only working the one with "red" value.
}
Errors i think i do:
1- I am using the wrong mixin for setting label color.
2- I am using the defined color variable in themecolor.scc wrong cause i don't know css.
3- There is a problem with my includes.
4- Are my SASS variables not being compiled?
Question why the --mdc-theme-primary is not defined? And why i cant point to the colors defined in themecolor.scss?
Any help is appreciated.
I fixed this by doing something isn't explained in the guide. When you want to use theming you have to import the theme component into your project, as follows:
app.scss
#import "./_themecolor";
#import "./_variables";
//----add these lines after custom imports-----
#import "#material/theme/mdc-theme";
#import "#material/theme/mixins";
//---------------------------------------------
#import "#material/top-app-bar/mdc-top-app-bar";
Nothing else is needed all the colors will be defined.
Thank ypou. I hpe this help newcomers.

Create angular material theme with CSS variables

I'm working on a project that requires to be themeable at runtime. So I created a theme system that combines SCSS variable with CSS Variables.
This is how it looks.
:root {
--primary-color: 196;
}
// Primary
$primary-100: hsl(var(--primary-color), 90%, 98%);
$primary-400: hsl(var(--primary-color), 90%, 65%);
$primary-main: hsl(var(--primary-color), 90%, 50%);
$primary-700: hsl(var(--primary-color), 90%, 30%);
$primary-900: hsl(var(--primary-color), 90%, 10%);
While this works amazingly with my custom components, I'm having a hard time making it work with the Material design theme system.
My thinking was that I will create the theme as explained in the Angular material docs, and instead of using static colors, I will use my SCSS variables. this is how my theme.scss file looks like.
#import '~#angular/material/theming';
#import 'var.scss';
#include mat-core();
$shop-primary: (
50: $primary-100,
100: $primary-100,
200: $primary-200,
300: $primary-300,
400: $primary-400,
// ..... all other colors
contrast: (
50: $black-87-opacity,
100: $black-87-opacity,
200: $black-87-opacity,
// ..... all other colors
)
);
$shop-app-primary: mat-palette($shop-primary);
$shop-app-accent: mat-palette($shop-primary);
$shop-app-warn: mat-palette($shop-primary);
$shop-app-theme: mat-light-theme($shop-app-primary, $shop-app-accent, $shop-app-warn);
#include angular-material-theme($shop-app-theme);
And I'm getting an error:
Argument `$color` of `rgba($color, $alpha)` must be a color
Presumingly because the Angular Material mixin is expecting a color and not a hsl() value.
So my question is how would I be able to create a custom material theme with runtime CSS variables?
I created a little library to make this a little easier.
You can use it like so:
Install:
npm i angular-material-css-vars -S
Then remove any existing #import '~#angular/material/theming'; from your main stylesheet file.
Add this to your main stylesheet instead:
#import '~angular-material-css-vars/main';
#include initMaterialCssVars();
Change the main theme color like so:
import {MaterialCssVarsService} from 'angular-material-css-vars';
export class SomeComponentOrService {
constructor(public materialCssVarsService: MaterialCssVarsService) {
const hex = '#3f51b5';
this.materialCssVarsService.changePrimaryColor(hex);
}
}
If you upgrade to #angular/material 7.3.4 CSS Variables will mostly work. Only riples and other stuff that uses opacity will need a little fix. I use rgba() for my project, but it should also work for hsla()
Include this:
#function mat-color($palette, $hue: default, $opacity: null) {
#if type-of($hue) == number and $hue >= 0 and $hue <= 1 {
#return mat-color($palette, default, $hue);
}
$color: map-get($palette, $hue);
#if (type-of($color) != color) {
#if ($opacity == null){
#return $color;
}
// Here is the change from the original function:
// If the $color resolved to something different from a color, we assume it is a CSS variable
// in the form of rgba(var(--rgba-css-var),a) and replace the 'a' value.
#return #{str-slice($color, 0, str-index($color, ',')) + $opacity + ')'};
}
#return rgba($color, if($opacity == null, opacity($color), $opacity));
}
directly after:
#import '~#angular/material/theming';
and define your colors like this:
--primary-color-50-parts: 0,158,224;
// ... all other colors
$color-primary: (
50: rgba(var(--primary-color-50-parts), 1),
// ... all other colors
);
if you define your colors in the map like this:
50: hsla(var(--primary-color), 90%, 98%, 1);
then you need to change str-index($color, ',') in the sass function to something that finds the last ',' in the string. Unfortunatelly my sass knowledge covers only the bare minimum and I don't know how to do that :/
I created a little library - material-theme-creator
You can theming your angular-application or use this approach to create themes
NPM: https://www.npmjs.com/package/material-theme-creator
DOCS: https://artik-man.github.io/material-theme-creator/
npm i material-theme-creator
#import "~material-theme-creator/ngx-mtc";
#import '~#angular/material/theming';
#include mat-core();
#include ngx-mtc-init();
$primary-map: ngx-mtc-create-theme-map('primary');
$accent-map: ngx-mtc-create-theme-map('accent');
$warn-map: ngx-mtc-create-theme-map('warn');
:root {
--is-dark-theme: 1; // Is dark theme? 1 or 0;
#include ngx-mtc-theme-base(); // Creates base colors
// Creates theme colors
#include ngx-mtc-create-variables-from-color('primary', #009688, 38%);
#include ngx-mtc-create-variables-from-color('accent', #2196f3, 57%);
#include ngx-mtc-create-variables-from-color('warn', #f44336, 62%);
}
// Creates Angular Material Theme
#include angular-material-theme(
ngx-mtc-custom-theme(
mat-palette($primary-map),
mat-palette($accent-map),
mat-palette($warn-map)
)
);
The second theme code:
.second-theme {
--is-dark-theme: 0;
#include ngx-mtc-update-theme('primary', #142148, 45%);
#include ngx-mtc-update-theme('accent', #658e14, 50%);
#include ngx-mtc-update-theme('warn', #750101, 50%);
}
You can use it with Angular Material or SCSS or pure CSS
Sooo... css variables are runtime, not compile time. SASS doesn't know what to do with them. You should be able to refactor your css vars using the ${} interpolation of SCSS and have everything still work the same. http://sass-lang.com/documentation/file.SASS_REFERENCE.html#interpolation_
$primary-color: 196;
:root {
--primary-color: #{$primary-color};
}
$primary-100: hsl($primary-color, 90%, 98%);

Dynamically override Bootstrap CSS variables in React?

So what I have is a React project with Bootstrap.css loaded. I'd like to somehow override the variables, so for instance I have a bunch of buttons like
<button className="btn btn-primary">Hello</button>
Which basically 'inherit' the color from:
:root {
--primary: somecolor;
}
Is there a way to somehow override this? I've tried passing it in as inline style to components, like <Component style={{"--primary" : "red"}} /> which will override the :root { --primary }, but the button colors will remain the same. What's the easiest way to do this, considering I'm supporting dynamic colors, so I can't create a few CSS files, and it would be good if I didn't have to rewrite every single button I have to be a styled-component that minds props!
There's not really an easy way to do this. You could generate the CSS for the "custom" primary colors in SASS, and then add a "root" primary color class to the component like this...
SASS to generate "primary" color Bootstrap CSS
/* import the necessary Bootstrap files */
#import "bootstrap";
#mixin build-primary-classes($color) {
/* background classes */
#include bg-variant(".bg-primary", $color);
/* btn classes */
.btn-primary {
#include button-variant($color, $color);
}
.btn-outline-primary {
#include button-outline-variant($color);
}
/* text- classes */
#include text-emphasis-variant(".text-primary", $color);
/* badge classes */
.badge-primary {
#include badge-variant($color);
}
/* borders */
.border-primary {
border-color: $color !important;
}
}
$customprimarycolors: (
"purple": purple,
"red": red,
"orange": orange
);
#each $colorName, $color in $customprimarycolors {
.#{$colorName} {
#include build-primary-classes($color);
}
}
JS
class Hello extends React.Component {
constructor(props) {
super(props);
}
render() {
return(
<div className={this.props.className}>Hello <button className="btn btn-primary">Button</button></div>
);
}
}
ReactDOM.render(<Hello className="red" />, document.getElementById('root'));
Codeply demo: https://codeply.com/go/R4X5x8taiH
Not sure if this will work, but an idea...
Could you edit your bootstrap.css file like this
:root { --primary: unset; }
That way you wouldn't have to overwrite any bootstrap styles?
HONESTLY ... I am not sure if it is a good idea to try to overwrite in CSS a few part of the classes bootstrap builds on a color var like $primary but let's the rest of the classes build on the same var as it is.
That's the way trouble raises up ...
An IMHO better way would be to do it the way Bootstrap provides it:
Changing in SASS the basic var $primary to the new wanted color in Bootstrap the color will change and the classes are there. Or adding a new color $additional-color and adding the color to map $theme-color and all the additional classes are build up on the fly ... Just have a look to the docs ... it is much more easier than it seems to be on the first look:
https://getbootstrap.com/docs/5.0/customize/color/
So yes: in SASS theming is possible just setting/adding the color vars.
But if in a project it is not possible to use SASS or the direct setup is not wanted for some reasons ... there are many free easy to use theming tools in the web which do the job for you. Than you are able to import a clean and consistend Bootstrap CSS with your wanted colors. Because that it is as easy Bootstrap is as successful (what not means I/you need to like it). As Bootstrap 5 still is Beta here an example for BS4 ...
http://pikock.github.io/bootstrap-magic/app/index.html#!/editor
NOTE: only changing/overwriting the CSS color vars in CSS file is not enough as the colors in the classes are hard coded to the original hex colors. You indeed would have to overwrite the original classes which leads to doubled code structures.

What is best fit to use for theming variables or mixins in sass

I am creating a UI library in which I want to provide the mechanism to theme all the UI components like button, cards, slider and all. I am confused between variables and mixins.
One way is to provide the no. of variables that user can update and based on that variables component classes will be derived. The same concept is used in the materialzecss library. And user will use like
//variables that are used to create component css classes
$primary : "blue";
$btn-primary :"green";
//then include the ui library
#import "_ui-variables";
#import "ui-library";
_ui-variables.scss
$primary : "red" !default;
$btn-primary: $primary !default;
// and other variables
and the _btn.scss will be like
.btn {
// other rule sets
color:$btn-primary;
}
Other way could be to use mixins. There will be a theme file for every component that will contain the theme mixin for that component and at the library level, there will be theme mixin that will include all the mixin of the individual component. As the angular-material has done
_btn.scss
#import "_btn-theme.scss";
.btn {
// some rules
}
_btn-theme.scss
#mixin btn-theme($theme) {
// if user has added the btn-primary then use btn-primary otherwise primary
#if map-has-key($theme,btn-primary) {
$btn-primary : map-get($theme,primary);
} #else {
$btn-primary : map-get($theme,primary);
}
.btn {
color:$btn-primary;
}
}
and the ui-library.scss
#import "_btn.scss";
#import "_card.scss";
#mixin ui-theme($theme) {
#include btn-theme($theme);
#include card-theme($theme); // include all component theme
}
and the consumer will call this as
consumer-theme.scss
#import "ui-library";
$theme :(primary:"blue",accent:"yellow");
#include ui-theme($theme);
What are the pros and cons of these approaches? Is there any other way to do this?
If you can use CSS custom properties (CSS variables) that would be really easy. You would just need to add a class to the body change your all your variables at once. So you just need a default theme and then just some classes changing your theme.
I have a small example in one of my project, if you click on "invert theme" it will change the page theme to invert: https://vinceumo.github.io/atomic-bulldog-style-guide-demo/styleguide/section-organisms.html#kssref-organisms-accessibility-settings
The issue with CSS custom properties is that not every brother support it yet :/
https://caniuse.com/#feat=css-variables
Otherwise, I would highly recommend using sass maps. It is easier to maintain when you have few themes, and you can quickly generate your components using #each loop
For example, if you want to generate background color classes:
$color-themes: (
primary:
(
base: #4c5c8c,
dark: darken(#4c5c8c, 15%),
light: lighten(#4c5c8c, 15%),
transparent: transparentize(#4c5c8c, 0.5),
contrast: #ffffff
),
secondary:
(
base: #212529,
dark: darken(#212529, 15%),
light: lighten(#212529, 15%),
transparent: transparentize(#212529, 0.5),
contrast: #ffffff
)
}
#each $name, $theme in $color-themes {
.has-bg-#{$name} {
background-color: map-get($name, base);
color: map-get($name, contrast);
}
}
So here we will get two new classes .has-bg-primary, .has-bg-secondary
If you add new entries to your map it will automatically generate new classes :)
I have created a Scss boilerplate using CSS custom properties (This one can be disabled) with Sass variables. It is optimized for themes creation. Most components are linked to variables (using map). Check it out https://github.com/vinceumo/atomic-bulldog
Variables are going to be your initial best bet.
Creating a theme story isn't something you should rush through, but rather take the time to integrate solid, well thought variables for a base set of colors. After that, you can extend them with things like lighten(), darken(), and other tools built into SASS.
Then, use that base set of variables to establish component specific variables to scale the theme story as needed.

Resources