4

I have this simplified Less script

.placeholder(@color: #333333) {
    &::-webkit-input-placeholder  { color: @color; }
}

input {
    .placeholder();
}

.placeholder {
    margin-top: 20px;
}

The output when I run this through my local compiler or winless online less compiler is

input {
  margin-top: 20px;
}
input::-webkit-input-placeholder {
  color: #333333;
}
.placeholder {
  margin-top: 20px;
}

Insted of the desired output

input::-webkit-input-placeholder {
  color: #333333;
}
.placeholder {
  margin-top: 20px;
}

Is this a bug or am I missing something here?

By the result it looks to me like I can't have CSS-selectors with the same name as mixins with default values.

I'm running into this problem when compiling Bootstrap with my site specific code. In this particular case I can work around it, but as the project grows and I include other projects I can't imaging I have to keep track of any mixins with default values?

Edit: I see now that I should have read the manual and pretty much seen on the first page of the docs that everything can be treated as a mixin.

Harry
  • 87,580
  • 25
  • 202
  • 214
opex
  • 234
  • 2
  • 6
  • I don't think there is any straight forward solution to this one as this is the way Less works. However can your `.placeholder` selector be made more specific (like `div.placeholder` or similar)? That should solve the issue. I am not adding it as answer because this still is a workaround but will do so if you wish me to. – Harry Oct 14 '14 at 02:24
  • Thank you Harry. You may do so and I can tick it as accepted. Like you says it's how Less works and I would have known if I had RTFM. – opex Oct 14 '14 at 07:02
  • I have just moved the Edit part to the bottom to make the question get prominence. Also just for your info, mentioning *Edit* etc are generally not required because SO does keep track of changes. It is not that it is bad but just that it is not required :) – Harry Oct 14 '14 at 09:20
  • I put a workaround at the corresponding [issue ticket](https://github.com/less/less.js/issues/2229#issuecomment-59030524) – seven-phases-max Oct 14 '14 at 11:56
  • @seven-phases-max: That is a even more cool option. Would you mind if I update the answer (ofcourse with attribution :))? – Harry Oct 14 '14 at 12:26
  • 1
    @Harry, Sure I do not mind (as always). – seven-phases-max Oct 14 '14 at 12:39

3 Answers3

2

In Less, everything is technically a mixin irrespective of whether we write it with parantheses (as in with parameters) or without parantheses (as in like a CSS class selector). The only difference between the two is that when the parantheses are present, the properties present within it are not output unless called from within a selector block.

Quoting the Less Website:

It is legal to define multiple mixins with the same name and number of parameters. Less will use properties of all that can apply.

In this case, since the other mixin has a default value for its only parameter, both the properties can apply when called without any parameter and hence there is no way to avoid it from happening.

Workaround Solution: One possible solution to work-around this problem is to enclose all such conflicting rules within a parent selector (like body).

.placeholder(@color: #333333) {
    &::-webkit-input-placeholder  { color: @color; }
}

input {
    .placeholder();
}

body{
    .placeholder{
        margin-top: 20px;
    }
}

Compiled CSS:

input::-webkit-input-placeholder {
    color: #333333;
}
body .placeholder {
    margin-top: 20px;
}

Option 2: Extracted from the solution posted by seven-phases-max in the Less GitHub Issue thread.

For the particular use-case one of possible workarounds is to isolate conflicting classes in unnamed scope so they won't interfere with external names:

.placeholder(@color: #333333) {
    &::-webkit-input-placeholder  { color: @color; }
}

input {
    .placeholder();
}

& { // unnamed namespace
    .placeholder {
        background: #ffffff;
    }
} // ~ end of unnamed namespace

Note: The above is a straight copy/paste from the GitHub thread without any modifications so as to not tamper with the information.

Community
  • 1
  • 1
Harry
  • 87,580
  • 25
  • 202
  • 214
1
@mixin placeholder(@color: #333333) {
    &::-webkit-input-placeholder  { color: @color; }
}

input {
    @include placeholder();
}

.placeholder {
    margin-top: 20px;
}

that should work.

Bioto
  • 1,127
  • 8
  • 21
  • First issue is that this does not compile when put into [winnless](http://winless.org/online-less-compiler) second is that the first two are part of Bootstrap and something I'd try to avoid modifying – opex Oct 13 '14 at 23:35
-1

So if i understood right, you just want to add 20px on top of the placeholder ? Add padding-top to input instead.

input {
    padding-top: 20px;
}
TjanB
  • 1
  • 1
  • 1
  • You understood incorrectly. The above code is just psuedo code illustrating the problem I'm having. For some reason the less compiler treats the mixin `.placeholder(@color: #333333) { ... }` and the css-selector `.placeholder { ... }` as mixins. Which renders the undesired output `input { margin-top: 20px }` – opex Oct 14 '14 at 06:41