4

Is it possibile to add span3 class in a mixin to avoid putting it in every element in my HTML? Something like:

.myclass {
    .span3;
    // other rules...
}

EDIT

I apologize I forgot to specify an important detail: span3 is a standard class of Bootstrap. I didn't find its definition in any file of the Bootstrap framework.

ScottS
  • 68,932
  • 12
  • 117
  • 139
Federico Bellucci
  • 515
  • 2
  • 6
  • 21
  • 4
    The short answer is "yes," assuming `.span3` is defined in the code. What is not working for you? You may need to edit your question with more specifics. – ScottS Mar 21 '13 at 16:28

3 Answers3

11

New Answer (requires LESS 1.4.0)

What you actually desire is something known as extending in LESS and SASS terminology. For example, you want an HTML element (just an example)...

<div class="myclass"></div>

...to fully behave as if it had a span3 class from bootstrap added to it, but without actually adding that class in the HTML. This can be done in LESS 1.4.0 using :extend(), but still not easily, mainly because of the dynamic class generation of bootstrap will not be picked up by :extend().

Here is an example. Assume this initial LESS code (not dynamically generated .span3 classes as bootstrap does):

.span3 {
  width: 150px;
}

.someClass .span3 {
  font-size: 12px;
}

.someOtherClass.span3 {
  background: blue;
}

You add this LESS code in 1.4.0:

.myclass {
  &:extend(.span3);
}

Which produces this CSS:

.span3,
.myclass {
  width: 150px;
}
.someClass .span3 {
  font-size: 12px;
}
.someOtherClass.span3 {
  background: blue;
}

NOTE how it did not automatically extend the other instances of .span3. This is different than SASS, but it only means you need to be a bit more explicit in extending. This has the advantage of avoiding excessive CSS code bloat.

To fully extend, simply add the all keyword in the extend() (this is updated from my original code, as I was unaware of the all option):

.myclass {
  &:extend(.span3 all);
}

Which produces this:

.span3,
.myclass {
  width: 150px;
}
.someClass .span3,
.someClass .myclass {
  font-size: 12px;
}
.someOtherClass.span3,
.someOtherClass.myclass {
  background: blue;
}

That makes your .myclass fully equivalent (in my example) to the .span3 class. What this means in your case, however, is that you need to redefine any dynamic class generations of bootstrap to be non-dynamic. Something like this:

.span3 {
  .span(3);
}

This is so the :extend(.span3) will find a hard coded class to extend to. This would need to be done for any selector string that dynamically uses .span@{index} to add the .span3.

Original Answer

This answer assumed you desired to mixin properties from a dynamically generated class (that is what I thought your issue was).

Okay, I believe I discovered your issue. First of all, bootstrap defines the .spanX series of classes in the mixins.less file, so you obviously need to be sure you are including that in your bootstrap load. However, I assume it is a given that you have those included already.

Main Problem

The main issue is how bootstrap is generating those now, through a dynamic class name in a loop. This is the loop that defines the .spanX series:

.spanX (@index) when (@index > 0) {
      .span@{index} { .span(@index); }
      .spanX(@index - 1);
 }
.spanX (0) {}

Currently, because the class name itself is being dynamically generated, it cannot be used as a mixin name. I don't know if this is a bug or merely a limitation of LESS, but I do know that at present time of writing, any dynamically generated class name does not function as a mixin name. Therefore, .span3 may be in the CSS code to put as a class in your HTML, but it is not directly available to access for mixin purposes.

The Fix

However, because of how they have structured the code, you can still get what you need, because as you can see above in the loop code, they use a true mixin itself to define the code for the .spanX classes. Therefore, you should be able to do this:

.myclass {
    .span(3);
    // other rules...
}

The .span(3) code is what the loop is using to populate the .span3 class, so calling it for your classes will give the same code that .span3 has. Specifically bootstrap has this defined in mixins.less for that mixin:

.span (@columns) {
  width: (@fluidGridColumnWidth * @columns) + (@fluidGridGutterWidth * (@columns - 1));
  *width: (@fluidGridColumnWidth * @columns) + (@fluidGridGutterWidth * (@columns - 1)) - (.5 / @gridRowWidth * 100 * 1%);
}

So you will get the width properties for the .span3 in your .myclass.

Taryn
  • 224,125
  • 52
  • 341
  • 389
ScottS
  • 68,932
  • 12
  • 117
  • 139
  • Awesome explanation of the main problem and nifty idea for the fix, but unfortunately it doesn't work for me. Have you tried it? Less is compiled to css with no errors and some width properties are added to the element, but the span3 class itself is not added, so other rules based on the span3 class presence are not executed. – Federico Bellucci Apr 08 '13 at 14:52
  • There is a difference between _including_ the `.span3` class as a mixin (which is what your question appears to seek an answer for) and having a class _added_ to an element, which is not something done through css or LESS, but in the HTML. So yes, a rule like `.span3 .someChildClass` will not apply to an element that has had `.span3` included as a mixin. If that is what you need, you have to do that through the HTML. – ScottS Apr 08 '13 at 17:12
  • @Uccio: Just to clarify my previous comment. A mixin does not add classes to an element with the class it is mixing into. So your `.myclass` does not gain the `.span3` class through a mixin. What it gains are the _properties_ of the `.span3` class into the `.myclass`. – ScottS Apr 08 '13 at 17:21
  • My question was clear about that: "Is it possibile to add span3 class in a mixin to **avoid putting it in every element in my HTML**?" My objective was to reproduce the presence of span3 class without explicitly adding it to every element. So adding the span(x) to the mixin is not a solution for that and evidently there isn't one at all. – Federico Bellucci Apr 09 '13 at 07:21
  • @Uccio: What was a bit confusing was the interpretation of "add span3 class in a mixin." Knowing LESS's capabilities, I read that as "add the span3 class properties by a mixin" because that is what mixins do, they add properties from classes, not the classes themselves. I was not aware that you were not aware of that fact :-). There is a partial solution in LESS 1.4. I'll update my answer, but it is still not going to be as "pretty" a resolution as you desire. – ScottS Apr 09 '13 at 13:31
  • I'm sorry I didn't check StackOverflow since long time and I didn't notice your updated answer. Now I don't need it any more and, as you said, it is not as pretty as I desired. Nonetheless you deserve an accepted mark, because probably there isn't a better answer. Cheers – Federico Bellucci Jul 09 '13 at 14:27
1

This is easy to accomplish with Less.js, but the real question is: "Should I mix structural grid classes with my non-structural classes?"

And the answer is no.

This is a bad idea, the advantage of a grid system is that it creates a separation of concerns between structural styling and other styling. I'm not saying "it should never, ever, ever be done". But in general, it shouldn't. I don't even like seeing this:

<div class="span3 sidebar">
  <ul class="nav">
    ...
  </ul>
</div>

Where the span3 is in the same div as the .sidebar class. The problem with this is that now your sidebar is not just "floating around" inside a column of the grid, it has become part of the grid - which (in general) makes it even more difficult to maintain your styles because of the workarounds you need to create to force this kind of styling to be responsive.

jonschlinkert
  • 10,046
  • 3
  • 38
  • 50
0

Well you can do it but you have to define .somethign first, in this example I will do it font-wight: bold; and font-size 20px. As you can see in second class .body I didn't have to define font-weight: bold; and font-size: 20px; I just added .something into it

.something {
    font-weight: bold;
    font-size: 20px;
}
.body {
    background-color: gray;
    border: ridge 2px black;
    .something
}

You can see example here. http://jsfiddle.net/7GMZd/

YOU CAN'T DO IT THIS WAY

.body {
    background-color: gray;
    border: ridge 2px black;
    .something {
         font-weight: bold;
         font-size: 20px;
    }
}
Kyrbi
  • 1,992
  • 6
  • 19
  • 40
  • Thanks for your answer, but I forgot to specify an important detail in my question. I updated my question – Federico Bellucci Mar 22 '13 at 08:51
  • FYI, unless I'm missing something, you didn't add an external resource to the jsfiddle (e.g. less.js) which would allow it to compile less. A better resource for testing is less2css.org – jonschlinkert May 15 '13 at 01:15