I really like the idea and the concept of LESS. Yet I stumbled upon a bug, which i reported quite a while ago to the author but did not yet get any feedback. Maybe it's just me who is doing something wrong.
My application.less-File that looks similar to this:
#import "reset";
#import "config";
#import "header";
#import "forms";
[…]
I like that it is possible to use the #import rule to split up my files to gain a better overview of my css-declarations. Yet every imported file needs to re-import the config.less-File again to be able to make use of the mixins and variables i defined in there.
I bet you already know about what kind of redundancy I am driving at: Everytime the config.less is imported, its "output" becomes part of the application.css.
My config-file contains about 200 lines of code. Since I split up my CSS-into about 5 files (based on my controller names) that need to re-import the config, I end up having about 1000 lines of generated CSS-Code that are 100% redundant.
Only solution that I can come up with is not to split up my files, what I really like to avoid.
Although not ideal, the practical reason for this is that the files you import theoretically don't need to contain any CSS. Typically, you would have variables and dynamic mixins, which don't contribute to your CSS output:
lib.less:
#colors {
#blue: #0011ff;
#red: #ee2222;
}
.button (#width: 10px) {...}
main.less:
#import "lib";
a { color: #colors[#blue]; }
output, main.css:
a { color: #0011ff; }
#colors {} and .button will not be output in this case.
LESS now supports #import-once "stylename.less";
Maybe you can split them up in your development environment and then merge them together, not needing all the extra code, when you deploy to your live web server?
You can use dynamic mixins in your LESS config file if they are declared and mixed-in using $ instead of ..
In config.less:
$mixin
{
a { color: #light; }
h2 { //etc.
}
In header.less:
#import "config";
.header
{
$mixin;
}
Source. I've also tried this and it works.
Related
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'm wondering if there's a grunt plugin that can compare two files and remove duplicates from one of them.
Example: if both blog.css and main.css contain the rule .button { color: red; } I'd like to remove that rule from blog.css. (main.css should always remain unchaged)
Background:
I've got two LESS-bundles, main.less and blog.less, which I compile into main.css and blog.css
The idea is that my site should load main.css on every page. On blog pages I'll load both both main.css and blog.css.
The problem is that these LESS-files share a few "utility"-files (with variables, mixins and some common classes like .button)
So I end up with blog.css containing duplicates of some rules which are already defined in main.css, and I'd like to get rid of those duplicates to reduce file size.
Found it
https://www.npmjs.com/package/grunt-csscss
csscss: {
dist: {
src: ['css/x.css', 'css/y.css']
}
}
Allthough in my case the solution was actually much simpler. Turns out LESS now has import ("reference") which will import a file to use as a dependency only, without outputting any of it's css.
So now I can use import ("reference") commonstuff.less in blog.less and thus none of the styles from commonstuff.less will be output to blog.css! :)
I'd like the css file produced by the less compiler to contain an #import directive at the beginning of the file.
I.e. given this less file:
#import "external.css" /* this import directive should be left as is */
#import "globals.less"
a { color: #linkColor; } /* defined in globals.less */
the resulting CSS file should look like this:
#import "external.css"
a { color: #00a; }
It seems that none of the various options of the less import directive helps producing this. Is there any other way?
Update: I'm using gulp-less to compile the less files. It might be a problem with that package and not with less itself (#import (css) "external.css"; doesn't give the desired result).
Update: It does seem to be a gulp-less problem (or some other library in the chain) because the code in question should actually output the #import statement as-is even without using the (css) option. The Less compiler seems to be capable of reading the file extension and if it is css then it just leaves the #import directive as-is. So, this should definitely not be a Less compiler issue.
Yes, try using the css keyword like #import (css) "external.css";. When this keyword is used, the Less compiler would output the import statement as-is.
#import (css) "external.css";
#import "globals.less";
a {
color: #linkColor;
}
would compile to
#import "external.css";
a {
color: #00a;
}
As seven-phases-max guessed (in the comments), this issue was not caused by gulp-less, but by the css-minifier (gulp-clean-css) which ran after the gulp compilation.
Using the correct clean-css options (processImport: false) solves the problem.
Let's say I have about 10 css files on my site. I wanted to combine them into one. But when I combining them(just "concatenating" files, in order they are included into html), my style/layout breaks. It's not the problem of paths or something, just selectors doesn't work as before.
Am I missing something, or maybe my file is too big? What could be the problem? I thought there is no difference if styles are in one file or many(they shouldn't be) as long as order is preserved...
Cheers
Make sure you don't have #import directives in your files. According to CSS spec, it may be place only before other rules. All other imports are ignored.
For example:
1.css:
BODY {background: #fff; }
2.css:
#import "foobar.css";
1+2.css:
BODY {background: #fff; }
#import "foobar.css"; /* This import won't work. */