1

Ultimately I'm trying to accomplish the following styles with LESS.

<div class="filter btn-group">
    <button class="btn btn-default" type="button" data-filter="*">show all</button>
    <button class="btn btn-default" type="button" data-filter=".cd">CD</button>
    <button class="btn btn-default" type="button" data-filter=".vinyl">Vinyl</button>    
</div>

I have the following HTML

<div class="filter">
    <button type="button" data-filter="*">show all</button>
    <button type="button" data-filter=".cd">CD</button>
    <button type="button" data-filter=".vinyl">Vinyl</button>
</div>

And I have this in a LESS file with imports of Bootstrap 3

.filter {
    .btn-group;
    button {
        .btn;
        .btn-default;
    }
}

When adding .btn and .btn-default to the button works just fine. But adding .btn-group to the wrapper ".filter" doesn't work. I can't figure out what I'm doing wrong. If I add the class .btn-group manually to the

class="filter btn-group"
It works.
julzmon
  • 111
  • 4
  • did you see the generated css? what does that looks like? – Fikri Marhan Jun 09 '14 at 04:02
  • It's missing some CSS for instance .btn-group>.btn:first-child:not(:last-child):not(.dropdown-toggle) { border-bottom-right-radius: 0; border-top-right-radius: 0 }' – julzmon Jun 09 '14 at 04:16
  • Well, in short, it's not supposed to work the way you probably expect. Note that `.btn-group`, `.btn` and `.btn-default` are are just plain CSS classes not meant to be used as mixins (even if Less allows you do do this). You do get a copy of properties of these particular CSS classes within your own classes but you *don't* get properties of *other* Bootstrap classes containing `.btn-group`, `.btn` etc. selectors. Bootstrap's `.btn-group > .btn` class styles are defined on their own and neither `.btn` not `.btn-group` copy those styles into your `.filter button` class. – seven-phases-max Jun 09 '14 at 04:31
  • See also my comments at [0](http://stackoverflow.com/q/23840711/2712740) and [1](http://stackoverflow.com/q/22983475/2712740). – seven-phases-max Jun 09 '14 at 04:31
  • That helped me out. Thank you for the comments guys. – julzmon Jun 09 '14 at 15:36

1 Answers1

3

EDITED

While I couldn't think of a way to fully accomplish what you wanted, with some help and inspiration from @seven-phases-max, I was able to adapt that gist to get your desired result.

To get a picture of how it works, the 'steps' are: First, treat the button selector as .btn.btn-default. Second, find all instances of the .btn-group selector and replace it with .filter. Then, finally, find all instances of .btn within the .filter and replace those with button.

You can accomplish this with extend (available in Less v1.4.0+). Here is a simple example of the less file:

@import "bootstrap.less";
button {
    .btn-default();
    &:extend(.btn, .btn.btn-default all);
}
.filter:extend(.btn-group all) {}
.filter > button:extend(.btn-group > .btn all) {}
.filter button + button:extend(.btn-group .btn + .btn all) {}

You need to make sure that any extend is placed after your other imports because the extend all acts like (a non-destructive) search & replace. So, the first extend above, for example, finds all instances of .btn within any rule selector and makes a copy of the selector, replacing .btn with button.

The resulting output allows the following to be styled like a btn-group:

<div class="filter">
  <button type="button">BUTTON ONLY</button>
  <button type="button">BUTTON ONLY</button>
  <button type="button">BUTTON ONLY</button>
</div>

CAVEATS

  1. As pointed out in several comments by seven-phases-max, this is going to add a fair bit of additional weight to your output because it's a non-destructive search and replace. It adds about 9Kb to the unminified/uncompressed output.
  2. You cannot use this type of extend the labels for checkboxes or radio buttons with the data-toggle="buttons" attribute as the BUTTON DATA-API inside button.js is looking specifically for the class .btn versus looking for a button element.
jme11
  • 17,134
  • 2
  • 38
  • 48
  • Thank you for your comment but that still isn't working unless I have the wrapper a class of .btn-group and give the button .btn class. It comes close but still doesn't group them unless actually giving them those class names. – julzmon Jun 10 '14 at 18:11
  • Sorry it didn't work for you. If you didn't get any error messages when you compiled and you have the button added after your other imports, I can't imagine why it doesn't work. Works flawlessly for me. :-( – jme11 Jun 10 '14 at 19:00
  • If I'm not mistaken the only way to actually make it is something like [this](https://gist.github.com/seven-phases-max/3bc77e5fcf8886ee0e3f#file-24113419-less) but it also generates a lot of redundant garbage selectors. – seven-phases-max Jun 10 '14 at 23:25
  • @seven-phases-max you rock... I had to make 2 changes to your gist, but in the end I did get it to work. You are totally right about the extra overhead though, adds about 9KB to the unminified output. – jme11 Jun 11 '14 at 10:51
  • Yeah that's pretty cool and almost works. There are some oddities that happen like 2px lines between the buttons instead of 1px and missing hover effects. @jme11 what did you have to change? Did it fix any of the issues I mentioned? – julzmon Jun 11 '14 at 19:47
  • You're right about the hover and 2px between the buttons. I didn't notice that before. I edited my answer (again). The new rules above fix both. Also, if you set up your import statements individually, and import the button-groups.less by reference, you can effectively reduce the extra output to 1Kb. However, that will also mean that you will no longer be able to use the standard .btn-group markup at all because reference means that the rules won't be copied into the resulting compiled file unless used. – jme11 Jun 12 '14 at 06:54