How to Use SASS to Properly Avoid Embedding Twitter Bootstrap Class Names on HTML

Is there a way make HTML code independent from changes in CSS class names?

If you're using SASS then you can use the @extend function.

However, it's recommended to avoid doing this as it copies the selected class into the new one thus, essentially, doubling the size of your CSS

The solution is either to not upgrade to BS-4, unless you have a requirement to. Or to update all your HTML when you do

Edit

Reading through the SASS docs, it seems the functionality has been changed to work using the comma syntax. So this would be your best option going forward.

It still generates excess CSS by doubling the number of classes, but not as bad as duplicating all your CSS

How to use twitter bootstrap with bootstrap-sass in rails app?

It's your use of @extend, or rather, Sass' inability to deal with wildcard class matching, which is rather unsurprising, since it gets rather complex.

Bootstrap uses a number of what I might refer to as 'nonstandard' methods to address some classes. You've mentioned one of those in your post above - [class*="span"].

Naturally, when you use @extend x, Sass is extending the x class. Unfortunately, it (currently) has no way of knowing that a wildcard matcher also affects the output of the class. So yes, in an ideal world, [class*="span"] would also be extended to define [class*="span"], .user-filter, but Sass can't currently do that.

While extending .row-fluid is enough to include the rules nested underneath it wrt. the span classes, as per above, it won't adjust the wildcards for extended spans.

bootstrap-sass already had a mixin for fixed width columns/rows, makeRow() and makeColumn(). I've just pushed a makeFluidColumn() mixin, that, well, makes a fluid span. Your code would then become:

.user-container {
@extend .row-fluid;
}

.user-filter {
@include makeFluidColumn(2);
}

.user-list {
@include makeFluidColumn(10);
}

Unfortunately (as per usual) it's not quite so simple. Bootstrap uses this snippet to reset the margin on the first spanx class that is a child of the row.

> [class*="span"]:first-child {
margin-left: 0;
}

However, we cannot redefine this for each call of makeFluidColumn, and so we must manually set no margin-left on any element that will be the first child of a fluid row. It's also worth noting that mixing spanx classes and makeFluidColumn classes will cause the first spanx class to have its margin reset, regardless of whether it's actually the first column in the row.

Your code would therefore be

.user-container {
@extend .row-fluid;
}

.user-filter {
@include makeFluidColumn(2);
margin-left: 0; // reset margin for first-child
}

.user-list {
@include makeFluidColumn(10);
}

It's not a particularly pretty solution, but it works, and is all to do with how Bootstrap uses wildcard class matching, as you gathered in your question update. I've only just pushed this to the 2.0.2 branch, so you'll have to use Bundler with Git to install it, but I'm hoping for a release in the next couple of days.

Twitter Bootstrap witih Saas MakeFluidColumn mixin is missing - trying to not hardcode span into a class in HTML

I ended up rolling my own @mixin.

so instead of using bootstrap's @include makeColumn(i); i can do @include col(i) to apply a width of i number of columns to a div or other element. Just include this SCSS file

    /*=VARIABLES - GRID
------------------------------------------------*/
$columns: $gridColumns; //from bootstrap/_variables.scss
$column-width: $gridColumnWidth; //from bootstrap/_variables.scss
$gutter-width: $gridGutterWidth; //from bootstrap/_variables.scss
$max-width: $columns * ($column-width + $gutter-width);

/*=VARIABLES - FONTS
------------------------------------------------*/
$font-base: $baseFontSize; //from bootstrap/_variables.scss
$font-base-line-height: $baseLineHeight; //from bootstrap/_variables.scss
$font-base-line-height-half: $font-base-line-height / 2;
$font-base-percentage: (($font-base / 16px) * 100) + 0%;

/*MIXINS
------------------------------------------------*/
@mixin col($n, $padding: 0px, $border: 0px, $container-width: $max-width) {
float: left;
margin-left: percentage($gutter-width / $container-width);
width: percentage(($n * ($column-width + $gutter-width) - $gutter-width - ($padding * 2) - ($border * 2)) / $container-width);
border-width: $border;
padding: em($padding, $font-base) percentage($padding / $container-width);
}

/*FUNCTIONS
------------------------------------------------*/
@function em($target, $context: $font-base) {
@if $target == 0 { @return 0 }
@return $target / $context + 0em;
}

@function perc($width, $container-width: $max-width) {
@return percentage($width / $container-width);
}

@function lh($amount: 1, $context: $font-base) {
@return em($font-base-line-height * $amount, $context);
}

@function heading-line-height($size) {

$line-height: $font-base-line-height;

$match: false;
@while $match != true {

@if $size == $line-height {
$match: true;
} @else if $size < $line-height {
$match: true;
} @else if $size > $line-height {
$line-height: $line-height + $font-base-line-height;
} @else {
$match: true;
}

}

@return ($line-height / $size) + 0em;
}

How to extend/modify (customize) Bootstrap with SASS

Update 2022 (Bootstrap 5)

Generally speaking, customizing Bootstrap 5 SASS works the same way as it did in Bootstrap 4. However, some of the maps have changed (and new ones have been added) so you should follow the Bootstrap SASS documentation for details on how to add, remove or modify any of the maps.

Recent comments on this post indicate there's still some confusion about the order of customizations and imports. However, this concept hasn't changed...

"Variable overrides must come after our functions are imported, but before the rest of the imports"

Because of the way SASS variable defaults work, bootstrap ("the rest of the imports") should be imported AFTER any variable customizations/changes. Since your variable changes will not contain the !default flag, your changes will not be overridden by the Bootstrap defaults when bootstrap is imported at the end.

The proof is in the pudding


Here's how to override / customize Bootstrap 4 with SASS...

Overrides and customizations should be kept in a separate custom.scss file that is separate from the Bootstrap SASS source files. This way any changes you make don't impact the Bootstrap source, which makes changes or upgrading Bootstrap later much easier.

1- Consider Bootstrap's SASS folder structure, alongside your custom.scss...

|-- \bootstrap
| |-- \scss
| | |-- \mixins
| | |-- \utilities
| | |-- bootstrap.scss
| | |-- variables.scss
| | |-- functions.scss
| | |-- ...more bootstrap scss files
| custom.scss

2- In your custom.scss, import the Bootstrap files that are needed for the overrides. (Usually, this is just variables.scss. In some cases, with more complex cutomizations, you may also need the functions, mixins, and other Bootstrap files.). Make the changes, then @import "bootstrap". It's important to import Bootstrap after the changes...

/* custom.scss */    

/* import the necessary Bootstrap files */
@import "bootstrap/functions";
@import "bootstrap/variables";

/* make changes to the !default Bootstrap variables */
$body-color: green;

/* finally, import Bootstrap to set the changes! */
@import "bootstrap";

2a (optional) - Also, you can extend existing Bootstrap classes after the @import "bootstrap"; to create new custom classes. For example, here is a new .row-dark class that extends (inherits from) the Bootstrap .row class and then add a background-color.

 /* create new custom classes from existing classes */
.row-dark {
@extend .row;
background-color: #333333;
color: #ffffff;
}

3- Compile the SASS (node-sass, gulp-sass, webpack/NPM, etc..). The CSS output will contain the overrides! Don't forget to check the includePaths if your @imports fail. For a full list of variables you can override, see the variables.scss file. There are also these global variables.

Bootstrap SASS Demo on Codeply

In summary, here's how it works:

1_ First, when the custom.scss file is processed using SASS, the !default values are defined in the bootstrap/variables.scss

2_ Next, our custom values are set, which will override any of the variables that had !default values set in bootstrap/variables.scss

3_ Finally, Bootstrap is imported (@import "bootstrap") which enables the SASS processor (A.K.A. compiler) to generate all the appropriate CSS using both the Bootstrap defaults and the custom overrides.

For those that don't know SASS, try this tool that I made.


Also see:

How to get 15 columns in Bootstrap 4 in SASS CSS?

Bootstrap v4 grid sizes / Sass List

Customizing Bootstrap CSS template

Extending Bootstrap 4 and SASS

Tweaking Bootstrap 2.0 for Semantic Markup

ok in less, this is how I figured it out. Its the best I could do, and I couldn't figure out how to deal with .row semantically, but oh well.

Basically I created a custom-mixins.less and created a mixin called .col and the variable is @col. So when you write your selector and do something like .col(3); .col(4); .col(5); or something like that. It should create the proper width. I don't know how this would work for nested columns.

//custom-mixins.less
.col (@col) {
#gridSystem > .gridColumn(@gridGutterWidth);
#gridSystem > .columns(@gridGutterWidth, @gridColumnWidth, @gridRowWidth, @col);
}

//styles.less
.greetings {
.col(3);
}

lessc will generate the following in styles.css

//styles.css
.greetings {
float: left;
margin-left: 20px;
width: 220px;
}

Use SASS mixin or create separate class is better?

To begin with, I'd like to mention that applying overflow: hidden to an element with floating children clears the floats much like how including the clearfix mixin you're talking about does it.

For readability and performance, this is probably the clear winner. I don't have any data supporting that overflow: hidden actually renders faster than the clearfix, but I wouldn't be surprised if it does. It's much less CSS, though, so it's definitely a winner in terms of downloaded data.

It's not always possible to use overflow: hidden though as your layout may have some relative positioning going on. In those cases, the best performant method is to create a global class for .clearfix and apply it to all elements that are supposed to clear their children. While it doesn't sound like it's easily maintainable, I'd argue that it is more easily maintainable that including that mixin throughout your CSS since you won't have to clear the cached CSS whenever you make changes.

My recommendation is to use both overflow: hidden and .clearfix. Scrap @include clearfix.

The reasoning is that you can't always get away with just one method (sometimes you may want to use the :after element for something else, sometimes you may want content to stretch outside their containers) so having both available makes sense anyway.

With both methods available you're able to adapt to any scenario. Just remember you could tie overflow: hidden to a class name to keep it just as DRY as .clearfix.

My 2¢.

Edit:

Alternatively, but maybe not ideally, you could use @extend to create an output like this:

.element-1,
.element-2,
.element-3,
.element-4,
.element-5 {
// clearfix stuff
}

So that clearfix is defined at one place rather than multiple times through the document. Personally I'm not a big fan of it, but perhaps it makes sense to you.



Related Topics



Leave a reply



Submit