简体   繁体   中英

Name clash between Less mixin and CSS selector

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.

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.

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

input {
    @include placeholder();
}

.placeholder {
    margin-top: 20px;
}

that should work.

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;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM