LESS importing CSS and relative paths - css

I am using LESS to organize and import all my CSS files. I am also using Twitter Bootstrap which I integrated inside my style.less. It works fine like below however when I use lessc to minify the less file and compress it to one all hell breaks loose with my twitter bootstrap css. The reason is that my bootstrap.min.css has a relative path to images as "../img" so when I minify all these files and dump my output file, it no longer finds this path.
How exactly should I fix this, I don't want to be hardcoding absolute urls in my css?
style.less
#import './folder_one/file_one';
#import './folder_one/file_two';
#import './folder_two/file_one';
#import './folder_three/file_one';
// this bootstrap css references images relatively ../img/
#import './bootstrap/bootstrap.min.css';

When running lessc use the --relative-urls flag.
lessc --relative-urls
It's poorly documented, but by default it is false which means that all #imported files will maintain their urls (e.g. background-image, font-face, etc) as they are. This is because less was already doing this and many users expect it to leave their urls alone.
When the relative-urls flag is used, lessc rewrites all of the urls according to the location of the less/css file being imported.
Example
/dir1/style/main.less
// if you don't include (less) lessc will leave bootstrap
// as an #import at the top of the lessified css file
#import (less) '../bootstrap/bootstrap.min.css';
/dir1/lib/bootstrap/bootstrap.min.css
background-image:url("../img/bs-img.gif");
Result:
/dir1/style/main.css
background-image:url("../bootstrap/img/bs-img.gif");

Check out the docs for command line usage.
https://github.com/cloudhead/less.js/wiki/Command-Line-Usage. There's an option called --root-path that will prepend existing urls so that they will work in the output css file.
lessc [option option=parameter ...] <source> [destination]
lessc -rp=will/be/prepended sourcefile.less path/to/destination
For example:
Here is the original url, with the file in css/src/nest
background-image: url('../../../imgs/bg.png');
And this is what I would do on the command line. Note that the -rp argument should point from the output directory to the original file location
lessc -rp=src/nest css/src/nest/nesty.less css/nesty.less
And the output, with the file in css/
background-image:url('src/nest/../../../imgs/bg.png')
There is a --relative-urls option, but I can't get it to work. I'm working build script that uses the workaround I described above. Build-o-Matic
This is how I handled determining the path [link]

i just had this problem and solved it.
the solution is to prepend ../ to the path of the style sheet that you want to import until it finds it. look here :
then i added ../ multiple times until i escaped to the wanted directory and it worked

--relative-urls flag has its in-browser counterpart.
<script>
less = {
env: "development",
relativeUrls: true
};
</script>
<script src="less.min.js"></script>

Related

Questions about CSS bundling in Rails 7

Rails 7. New App with Bootstrap CSS, JS Bundling, and CSS Bundling. This results in structure of:
app/assets/builds,
app/images/foo.jpg,
app/assets/stylesheets/application.bootstrap.scss
and using Yarn to add Bootstrap to package.json, with ESBuild for JS build and Sass for CSS build.
It all works until I try add a simple CSS class to the application.bootstrap.scss sass file:
.bg {
background-image: url("foo.com");
}
What I really want here, is the asset in app/assets/images/foo.jpg to be referenced properly. It is a scss file, so sass. When I use the sass commands:
background-image: image-url("foo.com");
or
background-image: url(image-path("foo.com"));
nothing works in development, or production, so that my application.css build file is correct. I get errors about syntax ending in a "we found a .jpg but should be (1px 0 solid) or something like that. In other words, the sass compile is not making a valid css build.
What am I supposed to be doing here to make a simple class with an image asset be part of my delivered application.css bundle? Should I be creating a separate css file and adding that to the sprockets manifest? Seems like overkill.
At the moment the only thing that worked was just adding an inline style to my ERB layout, which is totally bogus bad, but all I could do to just move on.
As an extra question, which I know I should not ask here, I also want to reference an image I add to the Rails App, so that https://myapp.com/my-image.png is just available. I used to park this in /public/my-image.png but if I wanted to instead use /app/assets/images/my-image.jpg what would my link be? I guess it would be all fingerprinted and not accessible, but perhaps I am wrong. Is there any point to referencing an asset instead of parking it in /public or am I forced to use /public?
see
https://github.com/rails/cssbundling-rails/issues/102
did you try
.test {
background-image: url("foo.jpg");
}
https://github.com/rails/sprockets-rails#initializer-options
config.assets.resolve_assets_in_css_urls
When this option is enabled, sprockets-rails will register a CSS postprocessor to resolve assets referenced in url() function calls and replace them with the digested paths. Defaults to true.

How to import part of an scss file

For example I am trying to import .navbar-nav from bootstrap's _navbar.scss and not the whole _navbar.scss file to my compiled css file. Is there a way to do it?
Sorry if this was asked before.
You can try doing an extend:
.your-class{
#extend .navbar-nav;
}
However, this would only work if you had imported the _navbar.scss somewhere else or the bootstrap.scss.
Additional
// main.scss
#import ../wherever bootstrap file is/_navbar.scss;
#import _custom.scss;
// _custom.scss
.your-class{
#extend .navbar-nav;
}
One of the way to import .scss in javascript is
import { navbar-nav } from '_navbar.scss'
When using in your component you can do.
<div className={navbar-nav} />
if you want to import it in your .scss file then you can do.
#import '_navbar.scss'
.class {
#extend .navbar-nav
}
As you are learning Sass here are some explanations which may help:
Better wording helps ...
At first some wording to get a correct understandable communication here and anywhere else you are talking about coding:
SASS don't minify a given CSS, it writes the CSS. Minify means the process that a given CSS code is compressed by a postprocessor to a shorter way to write it, - i.e. comments and spaces will be removed ... But yes: as SASS writes CSS it is able to write code in a minified format.
What you mean is to 'reduce code' or 'avoid not needed code' as you only try to import, use and write! the only needed parts of a given module which is a good practice.
.navbar is a CSS class. SASS don't load CSS classes, it writes CSS classes. It doesn't matter if you 'write the code on your own to a SCSS file' or 'get the code from a framework/module' ... SASS writes the however prepared CSS classes to your CSS file.
What you mean is the SASS includes/imports files with code from a framework/module to write that code/classes to css. So yes: maybe you can say you 'load' that module/scss-file ... but you don't load as css class. (This is as important as 'classes' in coding allways means a special construct of excutable code which does something in your programm. CSS classes don't execute anything, in SASS they are content you want to write/output to css.)
Please: these wordings are important to understand each other and to understand the mechanic of the process how SASS works is going on as well.
Reducing code by importing only selected file is good practice
So, I am not sure if I did understand your question right:
No. You are not able to include/import/load a part of the code of a single scss-file only. If you do #import 'somefile.scss' you always get the whole code of the whole file.
Yes. you are able to include/import/load parts of a given framework/module as you are able to load only the special FILES(!) of a framework/module you need for your project.
Yes. That is a really good practice.
As you mentioned Bootstrap indeed is developed and allows you to do that. But head up. If you import i.e. the part navbar.scss (or other selected elements) it only works if you also load the other files navbar.scss depends on. That are almost variables, functions, mixins and sometimes needed JS components to this element as well. Please note, that importing the files the elements are based on (i.e. vars, functions, mixins) has to be done BEFORE you load the element (i.e. like navbars, grid,...) itself.
A way to organize your project
Yes. A good way to organize your project is to have a single(!!!) file which brings all the code together you write in other partial files yourself or which you import from other framework/modules.
In case of Bootstrap this can be (simplified example):
// ###> file: your 'custom.scss'
// Note: file is without leading underscore
// as this files GENERATES/WRITE the css to custom.css
// Files with underscore as _partial-footer-styling.scss
// are not compiled to write css on their own
// that files are only compiled to css when they are imported to files without underscore
#import 'path/your-own-vars';
// Note: technique importing files
// you don't need to write underscore and '.scss'
// Note: function of this file
// the file '_your-own-vars.scss' is to organize you needed vars special to your project
// it includes your own vars and bootstrap vars as well
// --> the Bootstrap vars in this file will overwrite the vars of Bootstrap which will be included next
#import 'bootstrap-path/functions';
#import 'bootstrap-path/variables';
#import 'bootstrap-path/mixins';
#import 'bootstrap-path/your-selected-component-1';
#import 'bootstrap-path/your-selected-component-2';
#import 'bootstrap-path/your-selected-component-3';
...
#import 'path/partial-your-own-additional-css-special-section';
#import 'path/partial-your-own-additional-css-footer-settings';
....
A detailed explanation how to include and use Bootstrap (partly if you like to do so) to your project is here: https://getbootstrap.com/docs/4.6/getting-started/theming/

How to generate CSS from Sass in Bulma

This is my first time working with Scss, although I have run the command in terminal to convert a simple input.sass to output.css in the case of other libraries, it seems a little bit difficult, since it's new to me.
I have a profile with index.html which should require a style.css, but I need this style.css to be generated from Bulma directory which is currently in this format:
index.html
vendors
bulma
css
bulma.css
bulma.css.map
sass
base
_all.sass
generic.sass
helpers.sass
minireset.sass
components
elements
grid
layout
utitlities
bulma.sass
The problem here is that, unlike the sass input.scss output.css example which converts Scss files to CSS, the above seems complicated.
I don't know which file to convert, or if I should alter the Sass file and modify them but do I save the output in individual CSS file or one master style...
in every sass directory such as base, components and so on, they all have _all.sass file. which include all of the files in that directory. So, all you need is to include one _all.sass file from every folder within sass folder.
So in your sass file, that you will watch with sass gem, make includes for all fo the _all.sass.
Something like this would work.
#import "utilities/_all"
#import "base/_all"
#import "elements/_all"
#import "components/_all"
#import "grid/_all"
#import "ayout/_all"
Also, I am not 100% sure, but I think it is a bad idea to mix sass with scss, so my advice would be to do something like this:
In your sass folder of your project create a sass file and name it styles.sass. In that file write imports to all the _all.sass files.
And then just go do this in the terminal: sass --watch sass:css

How to avoid multiple #imports of SASS variables?

The site I'm working on uses the rails asset pipeline and an application.scss file to import and process different CSS files.
However, some stylesheets are used in specific places, and for those, it makes little sense to import them into the global manifest. But not so importing them requires importing variables.scss, and possibly mixins.scss into the sheet itself (so they'll process correctly), resulting in duplicate code in the final CSS.
Is there a way to basically tell the preprocessor - "trust me, the variable/mixin you're seeing will be defined by the time everything gets processed"?
Otherwise, I don't see how to avoid importing every sheet into a single manifest, which seems bloated.
Thanks.
The short answer to your question is no. The variables need to be defined in a logical order from when they are called in compilation. It's like a "chicken and the egg" scenario.
From what I can ascertain in your description, the project you're working on is not compiling into a unified workflow, but chunking out into modular portions relational to your file structure. IF this is the case, what you can do at the beginning of each file is reference the variables file from the root.
In a normal workflow, you would import your scss files based on your defined hierarchy like so:
sass/style.scss
/* Main Stylesheet */
#import "variables";
#import "mixins";
/* Modular Sections */
#import "layout/header";
#import "layout/body";
#import "layout/footer";
would compile out to one stylesheet style.css with a command sass sass/style.scss:style.css
What I'm assuming your project does is have all the /* Modular Sections */ files compile out into their own CSS files.
layout/header.scss
/* Header Stylesheet */
#import "../variables";
#import "../mixins";
Given a files structure that resembles:
/root
style.scss
variables.scss
mixins.scss
/layouts
header.scss
body.scss
footer.scss
This all seems kinda silly though. I don't know all the parameters that go into your current sass compilation, but I'd recommend using a unified workflow.
You can use Partials so the compiler will not try to interpret variables etc.
Basically, rename the files that you do not want the compiler to interpret -- but will be available when compiled -- with an underscore before the filename.
eg.
_filename.scss
If I understood well you want to avoid copies of the same css in css files caused by using #import in scss. I solved this problems by doing a hierarchical three.
For exemple consider the home.scss file, where you import header.scss and footer.scss.
Both header.scss and footer.scss use specific colors that you import from a file named colors.scss:
// colors.scss
$MidnightBlue: #00478f;
$RedOrange: #ff5d00;
$MistyBlue: #d8e1e7;
$Ebony: #2a231f;
Now you could import colors in header.scss, footer.scss and maybe even in home.scss. The result is that in home.css the code of colors.scss is repeated 3 times.
A solution is importing colors.scss only in header.scss. Then in home.scss the first #import that you specify is #import "header.scss"; and then #import "footer.scss";, thus you can use the colors variables in footer.scss and in home.scss even if you don't import them directly in footer.scss and home.scss. That's because the variables of colors are imported before the footer and compiled before the rest of the code in home.scss.
Now if you check home.css you shouldn't see repeated code
When at first you write the color variables in footer you will receive an error because they are not defined, but it disappear when you import footer in home.scss
If you #import the same SASS file (e.g. variables.sass) in multiple files and then #import those files in the one main.sass file, the resulting main.css file will contain the content of variables multiple times.
A good way of structuring SASS files is to obey the rule of importing each file only once. Iconic architecture is the 7-1 Pattern. You basically decompose your SASS files into atomic parts and then import those in appropriate order only once in the main file.

Java FX CSS #import path issue

In Java8_31 I imported different CSS files like that in my main.css:
#import "style/common/test1.css";
#import "style/common/test2.css";
All files were in the package style/common and it worked great.
Now with the build Java8_40 I did the same thing, but I get the following error message:
Could not find stylesheet:
file:/mypath/../style/common/style/common/test2.css
com.sun.javafx.css.parser.CSSParser handleImport
All my styles from the CSS file test1.css are working. What I was curious about was the fact that my path style/common is showing up two times.
So I tried to change my imports to the following:
#import "style/common/test1.css";
#import "test2.css";
With these imports, both styles of the file test1 and the file test2 are working. But both files are still in the same package.
Whats happening here? Is there a known issue about the #import and probably a problem in the CSSParser?
It actually is a known issue:
https://javafx-jira.kenai.com/browse/RT-40346
There is a temporary fix available and the issue should be fixed in the next build Java8_u60.
The temporary fix can be made in the CSSParser class. Link to the git diff:
http://hg.openjdk.java.net/openjfx/8u-dev/rt/rev/839912277bf0
If you dont want to try the fix or wait for u60, just add all css files to the same folder and import it like that (temporary solution!):
#import "css/test1.css";
#import "test2.css";
#import "test3.css";
#import "testX.css";
Just contributing to the discussion (not directly to your question):
You don't have to explicitly set the full .css file path. All you need is to specify the .css folder and the file name:
Original path:
#import "css/nodes/path/CssFile.css";
Full path without folder specification:
#import "../../path/CssFile.css";
Both work the same. Notice that, in the second example, "../" refers to the path level, not the specific folder name.
So in your case, that would be
#import "../common/test1.css";

Resources