Importing variables from components, benefit? - css

First some background. We have a main sass file main.scss where we are basically just importing other scss files.
/* ==========================================================================
Base
========================================================================== */
#import "base/colors";
#import "base/variables";
#import "base/typography";
#import "base/layout";
#import "base/font-icons";
#import "base/base";
#import "base/ie-fixes";
Later we import components too from outside of the styles folder because we have a components like development approach where we have components with it's .js .html .scss files "bundled" in a folder.
Now the question. Say I have such a component e.g /account. In account.scss I am using variables from styles/base/variables if I write the account.scss file with #import "../../styles/base/variables" then I am duplicating code for the sass output IF i have other rules defined in the variables.scss and NOT only true variable declarations. Okay, in variables.scss I should only have variables but say in colors.scss I may have variable declarations as well as rule declarations e.g
$grey: grey;
.grey { color: $grey; }
Now if I import colors my output sass file will contain .grey { .. } at least two times so it is duplicated. Okay, let's split colors up and move rules into a different file and let variables declarations only. Then I can freely import the file without duplication.
Now my question is why would I import? Is there any benefit of importing variable decalarions into account.scss outside of documentation?
I hope I was clear I tried to be as clear as I could.

You already answered your own question:
Okay, let's split colors up and move rules into a different file and
let variables declarations only. Then I can freely import the file
without duplication.
I would always separate mixins from functions from variables – and most important: separate all of these from output that is being generated. This way you can safely import modules or single parts of your SCSS anywhere.
For example:
/setup
_variables.scss
_functions.scss
_mixins.scss
...
_module.scss
/global
_base.scss
_layout.scss
_typography.scss
_helpers.scss
...
_module.scss
/components
_slideshow.scss
_pagination.scss
_widgets.scss
...
_module.scss
main.scss
Every _module.scss in one of the subfolders would like like this:
/* setup/_modules.scss */
#import 'variables';
#import 'functions';
#import 'mixins';
The main.scss would look like this:
/* main.scss */
#import 'setup/module';
#import 'global/module';
#import 'components/module';
Your question after what would be the benefit of importing: I don’t know. You have to know since only you know your application. If a 'standalone' component uses the same color set, for example, importing one single _colors.scss is indeed a good idea and keeps you DRY.

Related

global scss variable with #import at top

Is it possible? I've using scss with react and I've to create many .scss files, what's annyoing is that I always have to #import variable although it's global.
First create a entry point scss file name "app.scss"
Then create "_variables.scss" file which will contain all variables.
Then you create other component files like "_header.scss, _button.scss" ...
Then import the _variables.scss file in app.scss.
app.scss
#import "variables.scss" /*Note that this should be before any other components*/
#import "header"
#import "button"
...
Importing it at the top will ensure that all remainig components will
have acess to the variables
Then import the app.sccs file in your reactjs app.

Why does my SASS #import, go onto my CSS #import?

Ok so for example, lets say I have main.css, main.sass, about.sass, and contact.sass.
main.sass should have #import about.sass and #import contact.sass. Then, when main.sass is compiled, main.css should have all the content of about.sass and contact.sass. Not #import's.
Main.sass
#import 'tools/fonts'
#import 'tools/normalize'
#import 'tools/grid'
Now when this is converted to main.min.css it looks exactly the same as in main.sass
#import url(tools/fonts.css);
#import url(tools/normalize.css);
#import url(1-tools/grid.css);
Shouldn't there be no #imports, just the combined css code?
The files you are importing don't have names that start with an underscore. If the file starts with an underscore then SASS knows that it is a partial file, and should be included wherever it is imported.
If a file name does not start with an underscore, then it will be generated as it's own CSS file.
This behaviour is described here.
Partials
If you have a SCSS or Sass file that you want to import but don’t want to compile to a CSS file, you can add an underscore to the beginning of the filename. This will tell Sass not to compile it to a normal CSS file. You can then import these files without using the underscore.
For example, you might have _colors.scss. Then no _colors.css file would be created, and you can do
#import "colors";
and _colors.scss would be imported.
Note that you may not include a partial and a non-partial with the same name in the same directory. For example, _colors.scss may not exist alongside colors.scss.

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.

Abstracting your variables in SCSS

I have a parent SCSS file that is importing my other CSS files:
#import 'variables.css';
#import 'helpers.css';
#import 'layout.css';
And I have three scss files: variables.css.scss;helper.css.scss & layout.css.scss.
In variables I am defining colours, fonts and sizes to be used throughout the site. The trouble is I assumed these variables will be available to the other documents so long as it is imported first, but I am getting Undefined Variable errors.
I assume I just have the process wrong. Where am I going wrong?
You can do it that way if you're ok with an extra file as a middleman.
_master.css.scss:
#import 'variables.css';
#import 'helpers.css';
#import 'layout.css';
site.css.scss:
#import '_master.css';
The problem is how you named the scss files. The way you are importing the files makes SASS think that you are using the #import CSS rule https://developer.mozilla.org/en-US/docs/CSS/#import
Rename those files only with the scss extensions, remove the ".css", and import them like this
#import 'variables.scss';
#import 'helpers.scss';
#import 'layout.scss';
or you can even skip the extension at all
#import 'variables';
#import 'helpers';
#import 'layout';
If you want variables to be available on the other files you'll need to include that css in them as well. So basically layout.css.scss and helper.css.scss will need to have #import 'variables.css'

Proper SCSS Asset Structure in Rails

So, I have an app/assets/stylesheets/ directory structure that looks something like this:
|-dialogs
|-mixins
|---buttons
|---gradients
|---vendor_support
|---widgets
|-pages
|-structure
|-ui_elements
In each directory, there are multiple sass partials (usually *.css.scss, but one or two *.css.scss.erb).
I might be assuming a lot, but rails SHOULD automatically compile all the files in those directories because of *= require_tree . in application.css, right?
I recently have tried restructuring these files by removing all color variables and placing them in a file in the root app/assets/stylesheets folder (_colors.css.scss). I then created a file in the root app/assets/stylesheets folder called master.css.scss which looks like this:
// Color Palette
#import "colors";
// Mixins
#import "mixins/buttons/standard_button";
#import "mixins/gradients/table_header_fade";
#import "mixins/vendor_support/rounded_corners";
#import "mixins/vendor_support/rounded_corners_top";
#import "mixins/vendor_support/box_shadow";
#import "mixins/vendor_support/opacity";
I don't really understand how rails handles the order of asset compilation, but it's obviously not in my favor. It appears none of the files realize they have any variables or mixins being imported, and so it throws errors and I can't compile.
Undefined variable: "$dialog_divider_color".
(in /home/blah/app/assets/stylesheets/dialogs/dialog.css.scss.erb)
Undefined mixin 'rounded_corners'.
(in /home/blah/app/assets/stylesheets/widgets.css.scss)
The variable $dialog_divider_color is clearly defined in _colors.css.scss, and _master.css.scss is importing colors and all my mixins. But apparently rails didn't get that memo.
Is there some way I can fix these errors, or will I need to resort to putting all my variable definitions back into each individual file, as well as all the mixin imports?
Unfortunately, this guy doesn't seem to think it's possible, but I'm hoping he's wrong. Any thoughts are greatly appreciated.
The problem with CSS is, you do not want to automatically add all files.
The order of which your sheets are loaded and processed by the browser is essential. So you will always end up explicitly importing all your css.
As an example, lets say you have a normalize.css sheet, to get a default look instead of all the horrible different browser implementations. This should be the first file the browser loads. If you just randomly include this sheet somewhere in your css imports, it will then not only override the browser default styles, but also any styles defined in all css files that were loaded before it. This goes the same for variables and mixins.
After seeing a presentation by Roy Tomeij at Euruko2012 I decided for the following approach if you have a lot of CSS to manage.
I generally use this approach:
Rename all existing .css files to .scss
Remove all contents from application.scss
Start adding #import directives to application.scss.
If you are using twitters bootstrap and a few css sheets of your own, you have to import bootstrap first, because it has a sheet to reset styles.
So you add #import "bootstrap/bootstrap.scss"; to your application.scss.
The bootstrap.scss file looks like:
// CSS Reset
#import "reset.scss";
// Core
#import "variables.scss";
#import "mixins.scss";
// Grid system and page structure
#import "scaffolding.scss";
// Styled patterns and elements
#import "type.scss";
#import "forms.scss";
#import "tables.scss";
#import "patterns.scss";
And your application.scss file look like:
#import "bootstrap/bootstrap.scss";
Because of the order of the imports, you can now use the variables, loaded with #import "variables.scss"; in any other .scss file imported after it. So they can be used in type.scss in the bootstrap folder but also in my_model.css.scss.
After this create a folder named partials or modules. This will be the place of most of the other files. You can just add the import to the application.scss file so it will look like:
#import "bootstrap/bootstrap.scss";
#import "partials/*";
Now if you make a bit of css to style an article on your homepage. Just create partials/_article.scss and it will be added to the compiled application.css. Because of the import order you can also use any bootstrap mixins and variables in your own scss files.
The only drawback of this method I found so far is, sometimes you have to force a recompile of the partial/*.scss files because rails wont always do it for you.
Create the following folder structure:
+ assets
|
--+ base
| |
| --+ mixins (with subfolders as noted in your question)
|
--+ styles
|
--+ ...
In folder base create a file "globals.css.scss". In this file, declare all your imports:
#import 'base/colors';
#import 'base/mixins/...';
#import 'base/mixins/...';
In you application.css.scss, you should then have:
*= require_self
*= depends_on ./base/globals.css.scss
*= require_tree ./styles
And as the last step (this is important), declare #import 'base/globals' in every style file where you want to use variables or mixins. You might consider this overhead, but I actually like the idea that you have to declare the dependencies of your styles in every file. Of course, it is important that you only import mixins and variables in the globals.css.scss as they do not add style definitions. Otherwise the style definitions would be included multiple times in your precompiled file ...
to use variables and such across files, you need to use the #import directive. files are imported in order specified.
then, use application.css to require the file that declares the imports. this is the way to achieve the control you want.
finally, in your layout.erb file, you can specify which "master" css file to use
example will be more helpful:
let's say you have two modules in your app that need different sets of css: "application" and "admin"
the files
|-app/
|-- assets/
|--- stylesheets/
| // the "master" files that will be called by the layout
|---- application.css
|---- application_admin.css
|
| // the files that contain styles
|---- config.scss
|---- styles.scss
|---- admin_styles.scss
|
| // the files that define the imports
|---- app_imports.scss
|---- admin_imports.scss
|
|
|-- views/
|--- layouts/
|---- admin.html.haml
|---- application.html.haml
here's what the files look like inside:
-------- THE STYLES
-- config.scss
// declare variables and mixins
$font-size: 20px;
-- app_imports.scss
// using imports lets you use variables from `config` in `styles`
#import 'config'
#import 'styles'
-- admin_imports.scss
// for admin module, we import an additional stylesheet
#import 'config'
#import 'styles'
#import 'admin_styles'
-- application.css
// in the master application file, we require the imports
*= require app_imports
*= require some_other_stylesheet_like_a_plugin
*= require_self
-- application_admin.css
// in the master admin file, we require the admin imports
*= require admin_imports
*= require some_other_stylesheet_like_a_plugin
*= require_self
-------- THE LAYOUTS
-- application.html.haml
// in the application layout, we call the master css file
= stylesheet_link_tag "application", media: "all"
-- admin.html.haml
// in the admin layout, we call the admin master css file
= stylesheet_link_tag "application_admin", media: "all"
According to this question, you can ONLY use application.css.sass in order to define import and share variables between your templates.
=> It seems to be only a matter of name.
An other way can be to include everything and disable this pipeline.
I had a very similar problem. What helped me was to put in the underscore to the #import statement when importing the partial. So
#import "_base";
instead of
#import "base";
It might be a strange bug...
My solution was to have an application.css.scss with all the imports:
#import "./inputs";
#import "./buttons";
#import "./rails";
#import "./base";
#import "./checked-border";
#import "./tailwind-extended";
#import "./helpers";
#import "./custom";
#import "./overrides";
And then add:
#import "./constants";
to the files that use the constants

Resources