2

Can anyone offer any solutions for combining encapsulation and mixin reuse for Less/CSS? I'm trying to keep my variables encapsulated by namespace, but I haven't figured out how to reuse mixins for it.

Example:

#signup-module {

    @button-width:      100px; 
    @button-height:     30px;

    @textfield-width:   300px;
    @textfield-height:  20px; 

    .width( @value, @mod:0 ) {
        width: @@value + @mod;
    }

    .height( @value, @mod:0 ) {
        height: @@value + @mod;
    }

}

.home-page-signup-module {

    #signup-module > .width( button-width, -20px );
    #signup-module > .height( button-height, -20px );
    #signup-module > .width( textfield-width );
    #signup-module > .height( textfield-height );

}

The problem is when I create a new module, the width() and height() mixins are repeated.

#contact-us-module {    

    @button-width:      50px; 
    @button-height:     20px;

    @textfield-width:   300px;
    @textfield-height:  20px; 

    .width( @value, @mod:0 ) {
        width: @@value + @mod;
    }

    .height( @value, @mod:0 ) {
        height: @@value + @mod;
    }

}

Is there a way to maintain variable encapsulation and eliminate the mixin repetition? I'd like to write .width() and .height() once, but :extend() doesn't seem to work in this context.

Update: May 15, 2014

seven-phases-max offered a great solution below for reusing mixins, but I think I ran into a variable scope issue and the statement below returned an error. It said, "variable @textfield-width is undefined."

.home-page-signup-module {
    .module-a.width(textfield-width, -20px);
}

So I tried adding .module-a which seems to work. I'm not 100% sure if this is correct usage but it does fix the error and return the correct value.

.home-page-signup-module {
    .module-a;
    .module-a.width(textfield-width, -20px);
}
Harry
  • 87,580
  • 25
  • 202
  • 214
xff0000
  • 53
  • 5
  • it seems .width and .height does the same thing in both modules, can't you make them public and use it that way? – Huangism May 14 '14 at 17:17
  • In the simple example above it's the same, but in practice I need the ability to rewrite pseudo-private mixins as needed. It's better if the mixin name isn't global, so you you don't have to manage the namespace (keeps the mixin name short too). So, a .signup-module.width() does not have to be the same as a .contact-us.width() for example. In any case, the solution below pretty much solves it. Thanks! – xff0000 May 15 '14 at 18:52
  • Speaking your update. Hmm, I wonder what was the context that makes `@textfield-width` invisible. Your workaround will work (actually that way you don't even need to repeat `.module-a`, just `.module-a; .width(textfield-width, -20px);` should be enough) but that way you won't be able to use more then one module in the same scope: If `@textfield-width` is invisible w/o exposing a "module" to current scope then any mixins will use the variables exposed by *the last* invoked module and not the module of the mixins itself (e.g. `module-a.width` will use `module-b` variables). – seven-phases-max May 15 '14 at 19:58
  • Yeah, I spoke too soon. I'm testing it some more by invoking the mixins in additional classes and in various orders and it does in fact pick up the previous variable values from the other modules, so the encapsulation isn't working correctly. Ugh. It seems that reusing mixins isn't friendly with the basic encapsulation method in Less. I feel like I'm back to square one. Hmm. Maybe for now the best that I can do is just repeat the mixins within each .module-a, .module-b, etc. That's the only way I've been able to maintain the encapsulation. Unless I'm missing something... – xff0000 May 15 '14 at 21:17
  • Still, can you give an example of code that leads to `undefined @textfield-width`? By the way, don't you use Less version below 1.7.0? If so, do upgrade because there're a few known issues related to variable visibility of various scopes in older versions. – seven-phases-max May 15 '14 at 23:11
  • Thanks, at the moment I'm using Codekit 1.9.3 to compile, until a back-end processor is set up for the project I'm working on. I'll post the 'undefined' issue below, as an answer. (Sorry, can't seem to format code in the comments section.) – xff0000 May 16 '14 at 16:46
  • Sorry, delayed - I'm seeing inconsistent results trying to recreate the bug in a standalone environment. Right now the bug is happening in a private repo. I'm getting different results between using #foo > .mixin() vs. .foo.mixin() syntax. I have a feeling this might have something to do with my outdated version of CodeKit (older Less compiler maybe?). I'll try 2.* on a Mavericks machine or try a different compiler. – xff0000 May 17 '14 at 00:16
  • I think that was it. I downloaded the most recent version of Codekit for my Mavericks machine at home and it compiles ok (no `undefined @textfield-width` error). I'm still stuck with pre-Mavericks at work though so that will have to wait. – xff0000 May 19 '14 at 19:57

1 Answers1

1

You can collect shared mixins into another namespace/mixin and expand it in each "module" you need, something like this for example:

.shared-stuff() {
    .width(@value, @mod: 0) {
        width: @@value + @mod;
    }

    .height(@value, @mod: 0) {
        height: @@value + @mod;
    }
}

.module-a {
    .shared-stuff();

    @button-width:     100px;
    @button-height:    30px;

    @textfield-width:  300px;
    @textfield-height: 20px;
}

.module-b {
    .shared-stuff();
    @button-width:     200px;
    // etc.
}

// usage:
.home-page-signup-module {
    .module-a.width(button-width, -20px);
    .module-b.width(button-width, +33px);
}
seven-phases-max
  • 11,765
  • 1
  • 45
  • 57