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
How to Fade in and Out Color of Svg
Refinerycms: Apply Bootstrap Styles to Navigation Menu
CSS Width 100% Including Overflow
CSS-Redundancy When Using Less and Its @Import
Update Source File When CSS Is Changed Through Chrome Developer Tools
How to Access Two Ids in One CSS Selector
How to Make a Small Circle's Border Smooth
Does Source-Maps in Style Tags Work
CSS Inverted Triangle Image Overlay
Does The Order of CSS Stylesheet Definitions Matter
Tailwind CSS How to Code Pixel Perfect Design
2-Column CSS Responsive Layout with a Responsive Image
Why Must a + or - Be Surrounded with Whitespace from Within The Calc() Method
Reverse Svg Line Drawing Animation
CSS3 Transition Fadein with Display:None