How can I set baseFontFamily for bootstrap? - ruby-on-rails

I am trying to set base font family in my bootstrap_and_overrides.css.scss file but for some reason rendered HTML is still taking default font type instead of overriding it. Is there any way to change default values of bootstrap variables?
bootstrap_and_overrides.css.scss
#import "bootstrap";
$baseFontFamily: Arial,Helvetica,sans-serif !default;
$baseFontSize: 11px !default;
Rendered css:
body {
color: #333333;
font-family: "Helvetica Neue",Helvetica,Arial,sans-serif;
font-size: 14px;
line-height: 1.42857;
}

Here are two links on whether you want to alter the source:
http://www.codeproject.com/Articles/594098/How-to-customize-Twitter-Bootstrap-to-fit-your-web
or alter the source via your custom css.scss file:
http://www.sitepoint.com/how-to-customize-twitter-bootstraps-design-in-a-rails-app/
basically you want to put your overrides BEFORE the import of bootstrap.
$baseFontFamily: Arial,Helvetica,sans-serif !default;
$baseFontSize: 11px !default;
#import "bootstrap";
The Font Family is defined with
#import "bootstrap";
#sansFontFamily: Arial,Helvetica,sans-serif
#serifFontFamily: Font you want
These are LESS variables and should be defined after the import of bootstrap.

Per the latest bootstrap documentation, the LESS variables that can be overridden are described here http://getbootstrap.com/customize/#less-variables
Here are a few examples:
#body-bg
#text-color
#font-family-sans-serif
Since you are using SASS, just replace the # prefix with a $ prefix. Like below.
$body-bg
$text-color
$font-family-sans-serif
And override them before importing the bootstrap files.
So to override the base font family,
// note: per the bootstrap docs above, $font-family-base inherits
// from $font-family-sans-serif
$font-family-sans-serif: NewFont !default;
#import "bootstrap";
See more information here for bootstrap-sass https://github.com/twbs/bootstrap-sass

The point here is you have to specify right variable names in right position.
Right variable names: bootstrap less variable names. You need to change # character to $ for sass syntax.
Right position: define your custom variables before call #import "bootstrap";. If bootstrap has been loaded, your custom variables will never been used, that's the reason why your code doesn't work.
In this situation, your code should be:
bootstrap_and_overrides.css.scss
$font-family-base: Arial, "Helvetica", sans-serif;
$font-size-base: 11px;
#import "bootstrap";

Your variables names are incorrect. It should be
$base-font-family:Arial, "Helvetica", sans-serif;

If you are using bootstrap-sass gem, the correct name for this variables are
font-family-base and font-size-base
Also, from the SASS documentation:
You can assign to variables if they aren’t already assigned by adding
the !default flag to the end of the value. This means that if the
variable has already been assigned to, it won’t be re-assigned, but if
it doesn’t have a value yet, it will be given one.
!default it's the SASS equivalent of ||= operator in Ruby.
So, in your case the following will work:
$font-family-base: Arial,Helvetica,sans-serif
$font-size-base: 11px

Related

How to refer to rails assets from stylesheets?

I have a background image:
app/assets/images/bg.jpg
It works ok in development with the stylesheet as:
body {
background: #111 url('bg.jpg') repeat-x;
color: #DDD;
font: normal 90% "Trebuchet MS",Verdana,sans-serif;
margin-left: 1.2em;
}
But in production it doesn't show and the logs show:
ActionController::RoutingError (No route matches [GET] "/assets/bg.jpg"):
When I am using html and js templates I can add .erb to add the rails pre-processing that will let me use things like paths and helpers, e.g. images_url
How can I either:
a) Do a similar thing with my stylesheet
b) Use a path that works in both dev and prod. I tried [nothing] and images/ and they didn't work.
In the newer versions of rails, when you have a .css.scss stylesheets you have available a couple of helpers that will help you achieve that (you don't have to use .erb at all) like image-path and image-url (please take a look at the helpers section here https://github.com/rails/sass-rails)
basically what you need to do to get it working is replace
background: #111 url('bg.jpg') repeat-x;
for this
background: #111 image-url('bg.jpg') repeat-x;
and thats it. (also add the scss extension if you haven't already)
Precompile
You'll want to make use of the asset_path_helpers, specifically asset_url with one of the Rails asset preprocessors (SCSS / SASS)
The problem you'll have in production is that Rails appends what's known as a "fingerprint" to the assets. This fingerprint serves to define the uniqueness of the precompiled files:
Fingerprinting is a technique that makes the name of a file dependent
on the contents of the file. When the file contents change, the
filename is also changed. For content that is static or infrequently
changed, this provides an easy way to tell whether two versions of a
file are identical, even across different servers or deployment dates.
This means that when you push to production (and by virtue, precompile) the assets, you'll end up with the "bg.png" in a totally different location than that which you're referencing in the standard file.
--
Helpers
The trick is to use a dynamic path helper with the preprocessors:
#app/assets/stylesheets/application.css.scss
body {
background: #111 asset-url('bg.jpg') repeat-x;
color: #DDD;
font: normal 90% "Trebuchet MS",Verdana,sans-serif;
margin-left: 1.2em;
}
This should work for you
The fix that worked for me was to have
background: #111 url('<%= image_path "bg.jpg" %>') repeat-x;
and name my file .erb as in default.scss.css.erb
The other approaches didn't work.

Precompiling SCSS: variable is undefined (Rails 4)

The scenario
In /products.css.scss:
#import 'partials/colors';
#import 'partials/boxes';
#wrapper {}
In /partials/_colors.css.scss:
$light-gray: #ccc;
In /partials/_boxes.css.scss:
#box-light-gray {
background-color: $light-gray;
width: 50px;
height: 50px;
}
The problem
It happens on rake assets:precompile, in production environment:
Sass::SyntaxError: Undefined variable: "$light-gray".
(in /partials/_boxes.css.scss:2)
My thoughts
The file /partials/_boxes.css.scss doesn't have the variable $light-gray by itself – and here I have to agree with rake assets:precompile. The point is: how do I do to make rake recognize the injection of $light-gray into /partials/_boxes.css.scss?
I think rake is not matching the points of the puzzle because it doesn't know how SCSS works. I feel I'm missing something related to SCSS in couple with rake.
This is a tricky problem with the current version of Sprockets and sass-rails. You would think that the *= require lines in your application.css file would load the variables in order so that they would be available to all scss files, but it does not. Here is what the asset pipeline Rails guide says about it:
If you want to use multiple Sass files, you should generally use the
Sass #import rule instead of these Sprockets directives. Using
Sprockets directives all Sass files exist within their own scope,
making variables or mixins only available within the document they
were defined in. You can do file globbing as well using #import "",
and #import "*/*" to add the whole tree equivalent to how
require_tree works. Check the sass-rails documentation for more info
and important caveats.
In other words, you have a two choices:
#import your variables in each file as you need them
Use #import in your application.css.scss file instead of *= require
If you go with the first option, just drop in #import 'partials/colors'; to the top of _boxes.css.scss.
With the second option, you just need to #import your stylesheets in your application.css.scss once (in the proper order), then your variables in mixins will be available to all stylesheets. You're still using the asset pipeline here so precompilation will still work fine, but you're letting sass-rails work its sass magic. Your application.css.scss would look something like this:
#import 'partials/colors';
#import 'partials/*';
#import '*';
Be warned though, there is currently a bug with sass-rails. If you have .erb stylesheets, sass-rails won't be able to import them by wildcard if they're in a seperate folder.
Without modifying your scss, I think your best option is to put #import 'partials/colors'; in your _boxes.css.scss file also. The biggest drawback with #import is that it includes an additional http request, however since you are precompiling your assests I'm not entirely sure that is still an issue.
Potential refactoring option:
_colors.css.scss
$light-gray: #ccc;
_box-sizes.css.scss
.small-box{
width: 50px;
height: 50px;
}
products.css.scss
#import 'partials/colors';
#import 'partials/box-sizes';
.small-light-grey-box{
#extend .small-box
background-color: $light-gray;
}
Again, this is just an example. There are countless ways you could refactor your scss and html to get the desired outcome.

extending bootstrap is ignored in Rails

I want to do this
.bip_control{
#extend .form-control;
color:red;
}
but the resulting css looks like
.bip_control{
color: red;
}
Am I missing something?
I tried out your code and for me it seems to work as expected. Assuming you are importing the bootstrap files into the Sass file were you define .bip-control, as this is the only way you can extend the bootstrap rules with your selectors. I added an example on Sassmeister:
http://sassmeister.com/gist/8973529
#import "bootstrap";
.bip_control{
#extend .form-control;
color:red;
}
Importing bootstrap like this should include all bootstrap rules that you can extend (see here, however you can also import only individual components/mixins files, then you just need to make sure that you include the rules you want to extend and their dependencies).
If you look at the generated CSS, from line #2015 on, you will find all the .form-contro rules extended with the .bip_control selector.
For expample:
.form-control, .bip_control { ...
...
.form-control:focus, .bip_control:focus { ...
...
All the additional properties that belong only to .bip_control are added as another ruleset at the end of the rest of the imported bootstrap rules (or where ever you have defined it). This CSS rule set will also be returned, if the rules that you are trying to extend are not imported/included properly, and not available to the #extend directive.
You can maybe see better on how #extend works from the example in this answer (in case I haven't showed it well enough on the above bootstrap example): SCSS - override an #extend with another #extend

Is there a way to extend the SASS preprocessor to manipulate arbitrarily each declared property?

I am developing an embeddable widget that needs to have all its CSS properties declared as important to prevent CSS bleed of the embedding page. This means that if I want to use some pre-existing CSS framework (like Bootstrap), or some jQuery plugin that uses a CSS stylesheet, I have to manually copy-paste the CSS in my assets folder and add !important declarations to each property. This seems a rather unmaintainable and error prone process.
As per title, is there a way to extend the SASS preprocessor to add !important to any declared property for an imported file or partial?
No,
Sass doesn't have that functionality, because it is the most uncommon thing you would want to do in Sass, or CSS, or anywhere for that matter.
However, from what I understand, you want to add in the !important to all the CSS properties in a particular file. In that case, you can just simply do a Search & Replace:
Search for ; and replace with !important;
The most obvious solution is to create a new mixin, potentially with the word important appended like so:
%margin-none-important {
margin: 0 !important;
}
And then in your code:
.no-margin {
#extend %margin-none-important;
}

User theme switching with SASS - Ruby on Rails

So I have an rails admin system that will allow a user to choose a theme, basically a set of SASS color variables that will recompile application.css.scss with the new colors. How would be the best way of going about changing this when the user selects from a drop down and submits? I read some up on some problems with caching and recompiling but I'm not totally clear how to set it up.
Currently I have..
application.css.scss
#import "themes/whatever_theme";
#import "common";
#import "reset";
#import "base";
themes/_whatever_theme
$theme_sprite_path: '/images/sprite_theme_name.png';
$main_color:#009DDD;
$secondary_color:#b3d929;
$light_background:#f2f2f2;
$border_line:#e6e6e6;
$off_white:#f9f9f9;
$white:#ffffff;
$font_body:#565b59;
$font_headers:#363a36;
Say I have 5 different themes the user will switch between, it would be nice to set variable names for each theme in Rails then pass these down to SASS and change them on the fly and recompile. Is this the best way to go about this?
3 easy steps:
Compile all themes into different files upon deploy. This will take care of timestamping, zipping, etc.
Render page with default theme.
Use javascript to load alternate theme CSS.
No need to mess with dynamic compilation and all that.
To load a CSS dynamically you can use something like this:
function loadCSS(url) {
var cssfile = document.createElement("link");
cssfile.setAttribute("rel", "stylesheet");
cssfile.setAttribute("type", "text/css");
cssfile.setAttribute("href", url);
}
Sergio's answer is valid, but omits the sassy details and I'd used a slightly different approach.
You're using SASS in Rails- don't fight the current, be Railsy and let the asset pipeline precompile all your CSS. Unless you're trying to do something extreme like CSSZenGarden with hundreds of themes, or each theme is thousands of lines I'd recommend setting each theme as it's own CSS class rather than it's own file.
1kb of extra CSS in the rendered application.css file won't bog down your users
It's straightforward to switch theme classes with JQuery: $(".ThemedElement").removeClass([all your themes]).addClass("MyLittlePonyTheme");
As implied, you will have to tag the elements you want the update with the ThemedElement class
You could alternatively just change the class on your top level element and make liberal use of inheritance and the !important declaration, although I find the other approach more maintainable.
If you think you can manage your themes with classes rather than files, here's how we generate them with SASS. SASS doesn't support json style objects, so we have to reach way back and set up a bunch of parallel arrays with the theme properties. Then we iterate over each theme, substitute the dynamic properties into the auto generated theme class, and you're off to the races:
themes.css.scss
#import "global.css.scss";
/* iterate over each theme and create a CSS class with the theme's properties */
#for $i from 1 through 4{
/* here are the names and dynamic properties for each theme class */
$name: nth(("DefaultTheme",
"MyLittlePonyTheme",
"BaconTheme",
"MySpaceTheme"
), $i);
$image: nth(("/assets/themes/bg_1.png",
"/assets/themes/bg_2.png",
"/assets/themes/bg_3.png",
"/assets/themes/bg_4.png"
), $i);
$primary: nth((#7ca8cb,
#3c6911,
#d25d3a,
#c20d2c
), $i);
$font: nth((Rosario,
Helvetica,
Comic Sans,
WingDings
), $i);
/* Now we write our Theme CSS and substitute our properties when desired */
.#{$name}{
&.Picker{
background-image:url($image);
}
color: $primary;
.BigInput, h1{
color: $primary;
font-family: $font, sans-serif !important;
}
.Frame{
background-image:url($image);
}
.Blank:hover{
background-color:mix('#FFF', $primary, 90%) !important;
}
.BigButton{
background-color:$primary;
#include box-shadow(0,0,10px, $primary);
}
/* and so on... */
}
It's a bit of a hack, but it's served us really well. If your themes are uber complicated or you have too many of them it gets more painful to maintain.
One option is to simply load a set of custom css rules (your theme) after your application.css and let your theme override the default colors from application.css. You could just add a database column "theme" and load the css with this name dynamically like.
SASS is not designed for compiling dynamic data on the fly. If you want dynamic css processing, you could add a controller method called "custom_css" and make this respond to the css format and load this dynamically with inline variables, but I don't think SASS is meant to be used for it at all.
I believe that you could use erb to inline variables in sass. I'm not positive, but I think it would look something like this:
themes/_whatever_theme.sass.erb
$theme_sprite_path: '<%= Theme.sprite_path %>';
$main_color: <%= Theme.main_color %>;
$secondary_color: <%= Theme.secondary_color %>;
These should be created dynamically for each page load. I'm not sure how the caching would work here.

Resources