Building separate Stylesheets for different themes with webpack - css

Right now we are using a scss mixin ( https://github.com/zellwk/themify ) to provide different themes for our react components in our app.
It works great, but produces rather long selector chains in the compiled css file.
While we do have to provide the ability to change themes during runtime ( which is no hassle with the current solution, we only have to switch one classname on the body element ) the default usecase is, that the theme does not change.
So we thought about reducing the complexity and filesize of our stylesheets by splitting them up in separate files.
Example:
themes.scss:
$themes: (
red: (
mainColor: #aa3939,
secondaryColor: #D46A6A
),
blue: (
mainColor: #2e4272,
secondaryColor: #4f628e
)
);
button.sccs
#import 'themes.scss';
.button {
#include themify($themes) {
color: themed('secondaryColor');
background-color: themed('mainColor');
}}
}
This becomes:
.theme-red .button {
color: #D46A6A;
background-color: #aa3939;
}
.theme-blue .button {
color: #4f628e;
background-color: #2e4272;
}
Now I want this to become:
theme-red.css:
.button {
color: #D46A6A;
background-color: #aa3939;
}
theme-blue.css:
.button {
color: #4f628e;
background-color: #2e4272;
}
We are not depenent on the themify mixin, we could change that to any kind of solution one could make work with webpack. Any hint in the right direction would be appreciated! :)

#ManuKaracho, I tried to use the similar approach with the help of these two tutorials and faced the same issue as you are facing.
Sass Theming: The Neverending Story
Theming Web Apps with SASS
The CSS is generated in a single file instead of two separate files. I wanted to generate two separate CSS files just like you. I did some R&D about the issue and finally figured out how to do this.
First of all you need to break your themes.scss file into two separate files as shown below.
_theme-red-variables.scss
$themes: (
red: (
mainColor: #aa3939,
secondaryColor: #D46A6A
)
);
_theme-blue-variables.scss
$themes: (
blue: (
mainColor: #2e4272,
secondaryColor: #4f628e
)
);
Next you need to make some changes in your button.scss file. Simply remove the #import statement from the top because we will import theme specific variables into their own separate files as shown below
button.scss
.button {
#include themify($themes) {
color: themed('secondaryColor');
background-color: themed('mainColor');
}
}
Next you need to create two separate theme files. In these files, you need to import theme specific variables file, mixin file and your button.scss file
theme-red.scss
// Import red theme variables file
#import 'theme-red-variables';
// Import mixins file, where you have defined themify and themed mixins
#import 'mixins';
// Import button.scss file in this theme file
#import 'button';
theme-blue.scss
// Import blue theme variables file
#import 'theme-blue-variables';
// Import mixins file, where you have defined themify and themed mixins
#import 'mixins';
// Import button.scss file in this theme file
#import 'button';
Two separate files will be generated using the above technique
theme-red.css
.button {
color: #D46A6A;
background-color: #aa3939;
}
theme-blue.css
.button {
color: #4f628e;
background-color: #2e4272;
}
I hope I have explained the solution well and it will help you to resolve your problem.

Related

Vue 3 (CLI) imports global styles many times than need

So, I have scss file with global styles. This file seems like that:
#import "colors";
#import "border-radius";
#import "box-shadow";
#import "paddings";
#import "margins";
#import "fonts-famalies";
#import "font-sizes";
#import "transition-durations";
#import "global-path";
#import "mixins";
#import "mixins-properties";
#import "../design/animations/fade-animation";
::v-global(*), ::v-global(*::before), ::v-global(*::after) {
box-sizing: border-box;
outline-color: var(--color-outline__global);
transition: background-color 0.2s linear;
}
::v-global(html), ::v-global(body), ::v-global(#application) {
font-family: var(--font-famaly__comfortaa);
background-color: var(--color-background__global);
color: var(--color-font__content);
margin: 0;
font-size: 95%;
height: 100vh;
overflow-wrap: anywhere;
}
v:global(a) {
color: var(--color-font__link);
}
Styles imports using vue.config.js with this configuration:
module.exports = defineConfig({
transpileDependencies: true,
css: {
loaderOptions: {
sass: {
additionalData: `
#import "#/styles/global/global.scss";
`
}
}
}
})
All good, but when I open developer console in chrome I see picture like that.
When I checked header tag in HTML I see a lot of same css imports. If I comment all css styles - header have a lot of styles still. What am I doing wrong? I think that problem in loader
If you're going to be adding a global import (for example for shared SCSS variables and mixins), don't put ANY global styles in that import.
scss-loader's additionalData modifies each scss file it loads with the given string template. As a result, you're putting an import with your global style definitions at the start of every component's style block.
To fix this, move all your v-global(html) styles and the animations to a different file, which you import once in your index.html or App.vue. Ensure that the file you want to automatically import in your components only contains code that does not generate any styles by themselves (so scss variables, mixins, functions, etc. are fine). It's common that you name this file 'variables.scss' or similar, so no style definitions accidentally end up in this file or its dependencies.

Dynamic import style and set scss variable value

I have an admin template in which I would like user to provide option to switch between different theme color such as dark/light theme along with setting variable values, but I'm unable to conditionally import style files.
#if $light-theme {
#import "./_metronic/_assets/sass/themes/layout/aside/light.scss";
$primary: green;
} #else {
#import "./_metronic/_assets/sass/themes/layout/aside/dark.scss";
$primary: blue;
}
Getting error: Import directives may not be used within control directives or mixins.
Also it is a very long wished item to sass ... as the error message returns: that is not possible. (https://github.com/sass/sass/issues/279)
But what you can do is setting a theme variable and import your theme files. Every theme file has an conditional output based on the theme variable:
$theme: 'light-theme';
#import 'path/dark-theme';
#import 'path/light-theme';
// EVEREY THEME FILE WITH STRUCTURE:
#if( $theme == 'this-theme' ){
/*
here goes your theme variables or
if whanted your theme code in the file
*/
}

Reac-Bootstrap how to overwrite form-input background

I've got a next.js application and am using react-bootstrap. I am trying to overwrite my default form background from that blueish gray (#e8f0fe or rgb(232, 240, 254)) that bootstrap is using for inputs to white.
I am currently customizing the bootstrap variables via a custom.bootstrap.scss file
$theme-colors: (
'primary': #e28215,
'secondary': #83b8f3,
'tertiary': #1575e2,
'headings': #2b363f,
'body': #5b6b79,
'inputBorderNormal': #c3ced6,
'inputBorderFocus': #90a3b0,
'darkBG': #2b363f,
'lightBG': #eef0f3,
'input-bg': #fff,
'input-bg-disabled': #fff,
);
#import '~bootstrap/scss/bootstrap.scss';
this file is then imported into my index.scss:
#import './custom.bootstrap.scss'
I am then using the index.scss in my _app.js like this:
import '../style/index.scss';
The theming seems to work as my primary button is orange, but I can't get the form background to change (I can't even overwrite it on element level with !important)
Please find a repo here
Any help appreciated.
Cheers
I have made a code sandbox to demonstrate this
https://codesandbox.io/s/sparkling-feather-ppg8q?file=/style/custom.bootstrap.scss
There were two changes:
1.instead of importing index.scss import the custom bootstrap file into _app.js
import "../style/custom.bootstrap.scss";
Declare the variables directly into the file and apply them.
$darkBG: #2b363f;
$primary:#e28215;
$tertiary: #1575e2;
// ... Rest of your colors..
#import '~bootstrap/scss/bootstrap';
body {
padding: 20px 20px 60px;
margin: 0;
background-color: $primary;
}
form {
background-color:$darkBG;
}
.my-3 {
background-color:$tertiary;
}

Why is the #forward naming prefix not working with variables using Sass?

I am learning Sass over here and would like to get support in understanding why does this prefixing attribute not working when referencing variables when forwarding scss files.
I am using dart-sass with react.js taking the advantage of package-aliasing over node-sass so I can use #use, etc.
I cannot use this on codesandbox in order to replicate the issue, so I will post the code down here:
At src/library I have 2 partial scss files and one index.scss file to #forward my stuff:
_variables.scss
$color: darkgreen;
_mixins.scss
#mixin box-structure {
width: 50vw;
height: 50vw;
background-color: yellow;
margin: 0;
}
index.scss
#forward 'mixins' as mix-*;
#forward 'variables' as var-*;
the index.scss file is imported to a dummy react component, just to play around with the features and understand how things work.
Here is the Child1.js file and subsequently the Child1.scss file:
Child1.js
import React from 'react';
import './Child1.scss'
export default function Child1(props) {
return (
<div className="Child1">
<h2>Child 1 Title</h2>
</div>
)
}
Child1.scss
#use '../library/index.scss' as i;
#function invert($color, $amount: 100%) {
$inverse: change-color($color, $hue: hue($color) + 180);
#return mix($inverse, $color, $amount);
}
$primary-color: #036;
.Child1 {
#include i.mix-box-structure; //this works as intended
background-color: invert($primary-color);
h2 {
color: i.var-$color; //here is where the error occurs
}
}
As demonstrated above, I import index.scss as i and apply it on two places in Child1.scss:
When I use it to apply a mixin it works just fine, but when I try to apply the prefix to use a variable I get the following error:
SassError: expected "(".
╷
14 │ color: i.var-$color;
│ ^
I guess it is not accepting the $ after the dash. I tried placing the variable using string-interpolation with no success. Would it be a react.js issue?
Thanks in advance!!
I think the Problem is the application of the forwarding prefix. you need to add it after the $ like:
color: i.$var-color
It looks weird but if i remember correctly thats how forwarding prefixes work in sass.

How to overwrite mat-slide-toggle/ overwrite Css in components

I have a component which is Sample1.html.component which contains mat slide toogle, I've added a scss but it is not taking effect , is this because of the default of angular material? Thanks.
If it is toggled and checked the color of it should be #56ff00 like on the scss below.
Angular toogle
<mat-slide-toggle #relayToggle [checked]="hasBeenChecked" labelPosition="before" (change)="relayChanged($event)">
Toggle
</mat-slide-toggle>
scss
:host {
#include full-width();
.mat-slide-toggle.mat-checked {
& .mat-slide-toggle-thumb {
background-color: #56ff00 !important;
}
& .mat-slide-toggle-bar {
background-color: #56ff008a !important;
}
}
You have a main.scss or something similar as your root scss file in your root folder.
Inside this main.scss (or whatever it's called in your project) you can include your themes. Just add something like
// Theme customization
#import 'theme/theme';
in this file.
Then in your theme folder create a _theme.scss file and add this code:
.mat-slide-toggle {
border-top-color: pink;
}
to have a pink top border for your .mat-slide-toggle

Resources