Including Bootstrap in more than one Rails engine overwrites custom definitions - css

I am working on extracting behavior from a Rails app, and packaging it as a rails engine, to be included as a gem in the original app. My team has already successfully done this with another piece of functionality.
For the purpose of this discussion we can call the existing rails engine Foo and the one I'm creating Bar.
Foo has its own set of scss stylesheets, some of which depend on variables imported from Bootstrap. Bar is going to as well.
The main app's application.scss looks like this:
#import 'bootstrap';
#import 'foo/application'; // main stylesheet for Foo
#import 'bar/application'; // main stylesheet for Bar
foo/application looks like this:
#import 'bootstrap';
.cc-tab__icon {
#extend .lead;
font-size: 12px;
} // class which extends the Bootstrap .lead class
bar/application:
#import 'bootstrap'; // needs bootstrap too
Now, with bootstrap re-imported, my .cc-tab__icon elements have font-size 21px, which comes from a #media declaration on Bootstrap's .lead class. If I leave #import 'bar/application' out of my main application.scss file my .cc-tab__icon elements have the correct 12px font size.
I think the issue must be something I don't understand about #media declarations. Why would re-importing the same library affect a class that's already been declared and which just extends a class of said library?

Related

How can I use a third party CSS library in an Angular component's CSS without duplicating the library?

I have a two components that both rely on effects from hover.css. Both components have SASS files that (simplified) look something like this:
#import '~hover.css/scss/hover';
.some-class a {
#include underline-from-left;
}
Additionally, I have the hover.css library included in my global styles in style.css:
#import '~hover.css/scss/hover';
.some-global-class {
#include some-other-mixin-from-hover;
}
This all works and compiles fine, except for the rather large fly in the ointment that I end up with full hover.css in my compiled application three times - once in styles.js and twice in main.js (once for each component). This is obviously not a sustainable pattern.
If I don't #import hover.css in my components though, Angular won't compile them because they reference a mixin that can't be found. I've tried deep linking just the effects I need from hover.css but that's a hornet's nest because those files have downstream dependencies on other parts of the hover library. This obviously isn't specific to hover, but any scenario in which you'd want to import and use a vendor library in an Angular component's CSS file without duplicating the library.
Any ideas?
What do you have on your hover.scss file? Is it only mixins or other CSS as well? If you only have mixins then you should be fine, if you have some CSS then it will get taken. For example:
This would not cause repetition:
#mixin underline-from-left {
text-decoration: underline;
}
If you have something like this, then the span block will be repeated as many times as you would import it:
#mixin underline-from-left {
text-decoration: underline;
}
span {
display: block;
}
Perhaps an idea is to separate mixins from actual CSS, and then import only the mixins file.

Webpack Encore: unexpected SCSS import order

I use Symfony + Webpack Encore and try to split styles into "layout" and "page-based", but only to make development more comfortable: I still want to compile one css file for them (in fact, there is a limited number of such css files, each one for block of pages, but for easier understanding let's assume only one is necessary). So I do like this:
_global.scss
// ... bootstrap variables redefenition here
#import "~bootstrap/scss/bootstrap";
// ... common functions, mixins, font-face definitions here
.my_style1 {
padding-left: 12px;
padding-right: 12px;
}
.my_style2 {
#include make-container-max-widths();
}
app.css
#import "_global"
// other styles here
During the compilation (require('../css/app.scss'); only in my app.js) styles are ordered: [ global, bootstrap, app ] and I don't understand why. I mean, if you use them as:
<div class="container my-style1"></div>
container's padding will override defined in my-style1.
The most strange thing is that in dev app.css they are ordered as expected (my-style is lower than container), but in prod not (container is lower than my-style). When you work in dev (and Chrome display non-compiled styles, you also see that _grid.scss overrides _global.scss)
Sorry for this quick self-answer, I've really spent a lot of time before asking, but after it found the solution quickly. Hope, can save smb's time.
You should simply add other styles to app.js. This way they will recompile on any file change (in previous example they recompile only on app.scss change) and the order will become correct:
app.js
require('_global.scss');
require('app.scss');

How to isolate Vuetify global styles

I've started to use Vue.js with Vuetify within an old existing project. So I did not rewrite all frontend, I just imported Vue and replaced some parts.
And then I've noticed quite an unexpected behavior - Vuetify has global styles for common classes like .title and it effects the whole page, not only Vue part.
So, the questions is, how can I isolate vuetify styles inside Vue components?
UPD: As suggested #DigitalDrifter I tried to use stylus block-level import. So I removed
import 'vuetify/dist/vuetify.min.css'
from main.js and created a new .styl file (which was imported instead css) with the following content:
.vuetify-styles
#import '~vuetify/src/stylus/main'
And then added this class to the root component: <App class="vuetify-styles">
UPD2: After that you can get bug related to stylus compilation. More about it -> https://github.com/vuetifyjs/vuetify/issues/4864
UPD3: less also works fine for me.
# vuetify-styles.less
.vuetify-styles {
#import (less) '../../node_modules/vuetify/dist/vuetify.min.css';
}
And then just import it in your main.js
import './vuetify-styles.less'
Stylus supports block level imports.
If you've got the following:
// bar.styl
.bar
width 10px
// foo.styl
.foo
#import 'bar.styl'
The end result will be:
.foo .bar {
width: 10px;
}

How NOT to combine all CSS into one file with SASS and bootstrap

I'm relatively new to SASS and bootstrap. I use bootstrap with SASS and struggle a little bit with a concept.
I always used CSS like this: one base CSS-file with the basic layout (eq. base.css). Every template includes additionally a different CSS-file (eq. sitemap.css, team.css, news.css). This CSS-files only contain the parts of the respective templates. So I can overwrite the definitions in the previous files.
In SASS everything is compiled in one file. In combination with bootstrap I actually struggle with the concept I used until now.
Every time I want to add a new CSS-file to the existing definitions, I get an error because I have to reinclude the complete bootstrap structure. But if I reinclude it, the whole bootstrap code gets written into the additional files (eq. sitemap.css, team.css, news.css) too. If I include both files in my HTML-tree, the bootstrap definitions (like the whole normalize block) gets defined two or more times.
I have this setup:
- css
|-- source
| |-- base.scss
| |-- team.scss
| |-- vendors
| | |-- bootstrap...
└-- output
|-- base.css
└-- team.css
In base.scss I include the bootstrap stuff. I do also need the bootstrap stuff in team.scss, but not all the main stuff like the normalize things.
How do I achieve that? Is that even possible or do I have to switch my css needs by adding a css-class to the body tag (like body.team)? But then I have to carry the whole CSS stuff of every page in one file. Isn't this crab?
Edit to clear things up a bit:
This is in base.scss:
#import "settings/vars";
#import "vendors/bootstrap";
...
header {
#extend .container;
...
.contentbox {
margin-top: $mainGap;
}
...
}
...
and this is in team.scss:
header .contentbox {
#extend .sr-only;
}
It's absolutely clear that "#extend .sr-only;" doesn't work in team.scss because of the absence of bootstrap. But if I include bootstrap with
#import "vendors/bootstrap";
in the first line of team.scss, I would automatically add all the standard 16kb bootstrap things to team.css as well. However, these definitions are already in base.css. So I would have a preventable overhead.
I think I know there is no way to say: "Hey bootstrap. I already included you in base.scss. So you don't have to write the whole main definition of yourself into team.scss again. But I need you because I like you as an usable framework. So please provide me the functions and variables anyway.". But perhaps?
What I do in this case is to compile base.scss with Bootstrap and all the base code and my customized _variables.scss. Then if I want to add team.scss I just import the mixins and the custom variables that I will need to use from Bootstrap. Sounds great!
but...
Since .sr-only and other are just provided as classes instead SASS mixins, you can't #include it, like you could do with the .transition mixin for example.
So, for the moment if you are using SASS, you have 2 options:
Import the Bootstrap module with the class you want to extend/reuse
//contain the .sr-only definition
#import "vendors/bootstrap/_scaffolding";
#import "vendors/bootstrap/_variables";
header .contentbox {
#extend .sr-only;
}
Copy/Paste the class from the Bootstrap source and extend it:
#import "vendors/bootstrap/_variables";
// Copy/Paste the .sr-only class to reuse, very un-DRY
.sr-only {
position: absolute;
width: 1px;
height: 1px;
margin: -1px;
padding: 0;
overflow: hidden;
clip: rect(0 0 0 0);
border: 0;
}
header .contentbox {
#extend .sr-only;
}
What you're searching for is named a partial in Sass I guess:
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.
FYI, in LESS it'd be an import option: #import (reference) "colors"

Import css/scss file into a class

I have a problem. I'm using vaadin inside liferay. I've successfully written a fully responsive (yeah, tables too) theme for vaadin, based on bootstrap. Now I'm importing it to liferay. Everything went fine 'till I needed to upgrade Liferay, where their new responsive theme is using same classes name as bootstrap, but with different behaviour (sad, very sad face).
The solution I've thought so far is to apply a class to the vaadin compiled css, like:
.daVaadinTheme {
#import bootstrap.css;
}
so the content will be compiled like:
.daVaadinTheme h1.insideTheFile{
}
.daVaadinTheme h2.insideTheFile{
}
But, as you may figured out, is not obviously working.
Do you have any solution?
Read carefully! This is NOT a duplicate of the answer you've posted. I'm trying to import a CSS file inside a CSS/SCSS class of another file, like the example I've written above. My problem is not to simply import a CSS file inside another one...
SOLUTION: (kudos to Mathias Jørgensen)
using #import from another scss file:
in test.scss:
.daVaadinTheme{
#import "bootstrap.scss";
}
Name your inner file with an underscore, and ending in scss. .Yes, even if it's plain css, i.e. foo.css → _foo.scss
Have an outer File like so:
#main .content { // if that's, where you want them to rule only
#import 'foo';
}
Reasons:
import only works with scss
underscore-files are glady skipped by sass (also as in gulp.src(<some wildcards).sass())
if you have no influence in your repo about the css filename whatsoever. or it's a major pain on upgrades, consider using a symbolic link under an .scss extension...
You need move your code into mixin:
// botstrap.scss
#mixin bootstrap {
h1.insideTheFile{
}
h2.insideTheFile{
}
}
Then, you can import normal:
// test.scss
#import "bootstrap"; // No extension
#include bootstrap; // The name of "mixin"
or with context:
// test.scss
#import "bootstrap"; // No extension
.daVaadinTheme {
#include bootstrap; // The name of "mixin"
}
If you want to add certain styles to a class using sass/scss I think what you're looking for is
.myClass { #import bootstrap.css; }

Resources