I set up my project as Less in Angular to use the benefits of variables and such in my CSS. But the problem is that I have to define those variables in each component which doesn't make it as efficient. Is there a way to set the variables globaly?
So I want to get rid of this:
In my component less:
#pink-color: #FC9DB5; // I want to get this from a single
// file which I import on each component
header {
background-color: #pink-color;
height: 100px;
}
This is what #import is for; it lets you import files of variables.
Related
I have 2 micro frontends using the same css library, and it is causing issues. Styles from one micro frontend bleed into the other. So I need for all of the css that gets out of the library to be scoped.
But I need to have a different scope for each library import.
Basically I have style files like
some-component.module.scss
.some-class {
color: red;
}
And I want people who use the library to be able to import components from the library, and have it scoped to something they choose. For example in microFrontend 1:
import SomeComponent from "my-library"
const SomePage = () => {
<SomeComponent/>
}
In this scenario I want styles for SomeComponent to look like:
.microfrontend-1 {
.some-class {
color: red;
}
}
Basically I need to wrap all styles that are imported from the library on a different scope depending on which microfrontend I'm in.
Some possible solutions:
Add a variable to .env file with the right wrapper name, and somehow read it from the library, and scope css at runtime (which loader could help me here?)
Use ES6 module query parameters to provide the wrapper name at import time (I would need to do this for every component, so it is not ideal)
Currently I'm building a template that will be used by multiple people on different projects. So making this work instantly without changing things per project install is crutial.
For this instance I want to change the $spacer variable that is used for all the margings and paddings classes that Bootstrap offers. But I cant seem to figure out how to change the $spacer variable outside of the /node_modules. I have an own _variables.scss that creates variables for the theme but an !important or anything else wont work eventhough the custom _variables.scss is loaded later that the bootstrap from the node modules.
Is there a way to send a scss file to the node_modules file so it changes the variables from within? or is there a different way to overwrite a variable from the node modules?
I always work like this and no problem:
// File: my-bootstrap-and-styles.scss
// your overrides
$primary : #FEBC35;
// include bootstrap.scss
#import "../node_modules/bootstrap/scss/bootstrap";
// Then add your additional custom code here
.my-primary-div {
background: $primary;
border: 1px solid black;
}
// also don't forget to take advantage
// of bootstrap's variables and mixins
#include media-breakpoint-down(md) {
.my-class {
overflow-y: auto;
}
}
In my project, I use CSS Modules with Less, which means I get the best of both worlds.
My src folder looks something like this:
components/
[all components]
theme/
themes/
lightTheme.less
darkTheme.less
palette.less
palette.less:
#import './themes/lightTheme.less';
Then, in every component that wants to use colors from the theme, I do:
component.module.less:
#import '../../theme/palette.less';
.element {
background-color: #primary;
}
This structure lets me edit palette.less to import the theme I want to use. The thing is that I want to let the users choose their preferred theme on their own. Themes should be switchable on runtime, which means I somehow need to have both themes compiled.
I imagine the perfect solution to be something like this:
app.less
body {
#theme: #light-theme;
&.dark-theme {
#theme: #dark-theme;
}
}
And then somehow import this #theme variable in every component and read properties from it (i.e. #theme[primary]).
Unfortunately, Less variables scoping don't work like this.
I am open-minded to any solution that uses Less modules.
Thank you!
I know that you've probably looking for a solution that uses Less / CSS modules, but it's very likely that your situation can be solved solely with the use of css variables (as Morpheus commented on your question).
How it would work?
You'd have to ensure all your styling does not use hardcoded values, i.e. instead of:
.awesome-div {
background-color: #fefefe;
}
You would have:
:root {
--awesome-color: #fefefe;
}
.awesome-div {
background-color: var(--awesome-color);
}
Changing between light and dark
There are two ways of changing themes in this approach:
Use vanilla Js code within React to update the :root CSS element, check this codepen for more information;
Just load a component containing all new :root variables in its component.css file;
In React (in vanilla CSS too) you can easily have multiple components/elements declaring their own :root at their .css files.
Furthermore, any new :root will overwrite conflicting values from previous :root. For example if at file app.css we have :root { --color: red; } and, when loading another component, component A for instance, where in component_a.css we have the same variable overwritten, e.g. :root { --color: blue; } the one rendered in our browsers will be the one from component A.
Following this logic, you can have a dummy component that does and renders exactly nothing, but instead in this component.js file you import the .css of a theme, e.g.:
import './light.css'; // suppose this is the light-theme dummy component
When switching themes in your app you'd just have to remove the dummy component from scene and call the other one.
I'm not too experienced with codepen to the point of providing you an example containing imports/modules over there, but I hope the above explanation can give you an idea of what I mean. Still, here's a brief pseudo-code of what I'm intending to demonstrate:
loadTheme() {
if (this.state.theme === 'dark') return <LightTheme />;
if (this.state.theme === 'user-3232') return <UserTheme />;
return <DarkTheme />;
}
render() {
return (
<App>
{this.loadTheme()}
<OtherContent>
</App>
);
}
Check out Styled components, it can do that.
https://www.npmjs.com/package/styled-components
https://styled-components.com/docs/advanced#theming
I did it myself as a Easter Egg in an app of mine, so I know for sure it works. Unfortunately it is closed so I can't show you the code publicly.
I do already have SCSS variables defined in src/styles/settings/_variables.scss and I am importing them into src/styles.scss, but still these variables aren't available for every single component.
Is there any way to make a global file which holds all SCSS variables for the rest of my components? Because writing #import in every single component .scss file it is very frustrating, especially if I have many nested components.
I know, there is a lot of similar questions, but it seems like they're all outdated and do not relate to the recent versions of Angular.
I use Angular 7.3 with CLI.
You just need to add a little more config, so where you are declaring your global variables, you need to wrap it up in :root{}. So in src/styles/settings/_variables.scss.
:root
{
--blue: #00b; // or any global you wish to share with components
}
Then when you use them in the SCSS you will need to access them like so.
.example-class {
background-color: var(--blue)
}
To add to this regarding comments, this method can use mixins, #media and keyframes and is not limited to just colours / font. That was an example.
From my understanding you need a global file src/assets/style/global and then to import each scss file into there where you are defining them like so.
#import 'filename';
If you dont want global variables to be used in within a component look when you have the globals working. Look into ViewEncapsulation, as this can be used to ignore them.
Is there any ways to make global file with scss variables available for all components?
Without importing global file everytime in each component, you want those sass variables been available, it's not possible.
The way it works in SASS, if using partials to better organize code, you can apply #import directive for referencing. So if there're some sass variables in shared/_variables.scss:
$lightslategray: #778899;
$darkgray: #A9A9A9;
and these variables need to be used in another stylesheet, stylesheet with them must be #import-ed into it firstly:
// Shared
#import "shared/variables";
.content {
background: $lightslategray;
}
In Angular it works in a similar way (related referencing external stylesheet). So if you need some sass variables, mixins or functions to be used by a particular component.scss, there is no other clean way, but to reference them in that component.scss using #import directive. To ease the task, you can create a file src/_variables.scss and use syntax like this in your component.scss:
#import “~variables.scss”;
step one : go to custom scss file (shared/css/_variable.scss) and write this part
:root{
--color-text: red;
--color-btn-success: green;
}
after go to style.scss (this is main file) and import this file :
#import './shared/css/Variables';
now you can use variables in all components with this Syntax:
.sample{
color : var(--color-text);
}
Easily possibe to access sass style(s) from a global file with two steps.
Add folder path of the style files to includePaths array in angular.json file.
Import style file by file-name in any component.
let say your files and folder structures is as follows: src > my-styles-folder > var.scss
angular.json
"architect": {
"build": {
...
"options": {
"stylePreprocessorOptions": {
"includePaths": [
"src/my-styles-folder" // add path only, do not include file name
]
},
"styles": [
...
]
}
...
}
}
some-component.scss
#import "var"; // var.scss
mat-toolbar {
height: $toolbar-height;
}
In angular 8 work for me.
In your _variable.scss file you have to add:
:root{--my-var:#fabada}
After that go in your angular.json and add this in "styles":
{"input":"yourPath/_variables.scss"}
I am using css modules for my project, and I have a file positioning.css which has some useful classes that I want to import. e.g. .right, .left
What is the best approach for this using CSS Modules?
At the moment I can see 2 options, but they are not all that great:
composition in the component's style
.right {
composes: right from '../styles/positioning.css';
}
or
multiple css module imports in the component
import positioning from '../styles/positioning.css'
import styles from './myComponent.css';
Object.assign(styles, positioning)
class Menu extends Component {
render() {
return (
<div styleName='menu'>
<div styleName='left'>this is left</div>
<div styleName='right'>this is right</div>
</div>
);
}
};
export default CSSModules(Menu, styles);
I have manage to get this working:
// css file
#value class-to-compose from "file-where-class-is-defined.css";
.someclass {
composes: class-to-compose;
// other styles
}
One approach is to collect all app level css variables and calculations at the top level into app.css
#import "./theme/layout.css";
#import "./theme/colors.css";
...
Then reference app.css using
#import "../../app.css";
This way you can manage #import scope inside one file at the root level.
I'll go with the first proposition. (the result is quiet the same)
both proposition have quiet the same result
If someday you have to edit your Menu css, you'll just have to edit your Menu css and not your component.
You let CSSModules take decisions. (more futur proof?)
You could import the css files that you use frequently into a broader CSS file that you import on specific pages, this is taking the second approach but making it cleaner, especially if you have a lot of common core css files that you import on pretty much all pages.
I would advise you to go with [Sass] [1]. Sass allows for the usage of partials (i.e. distributed / scoped css sheets).
You write scoped (to the components you want) css and import all your partials into your main.css then.
Couple of other advantages:
you can do theming by having one partial that defines your them via variables, which you import first and then all your partials can use these variables.
having the css on a scoped level (at least to me) felt more "reactish" where components are supposed to be stand alone, but it also wasn't inline styling, which I find ugly and weird (I don't like to clutter down my .js files with styles)
[1] http://sass-lang.com/
I find this one line very helpful with importing:
#import 'file.css';
You could set these as globals and update their names to be a tad more semantic, like BootStraps pull-right.
If you declare them as
:global(.right) {
/* ... */
}
You can then just use them in your app by preferably importing globals early on in the entry point.
You should take a look at the option by vue.js component (scoped/overall)
You can choose a precompile css language like SASS, which can use #extend ...etc to reuse the common property, like below:
%common {
width: 100%;
height: inherit;
}
.my-class {
#extend %common;
}