Search code examples
csslessmedia-queries

Variable interpolation for a media query property in less - missing closing ")"


I'm trying to "translate" a sass function into a less function. Here is the original SASS one :

@mixin bp($feature, $value) {
    // Set global device param
    $media: only screen;

    // Media queries supported
    @if $mq-support == true {

        @media #{$media} and ($feature: $value) {
            @content;
        }

        // Media queries not supported
    } @else {

        @if $feature == 'min-width' {
            @if $value <= $mq-fixed-value {
                @content;
            }
        } @else if $feature == 'max-width' {
            @if $value >= $mq-fixed-value {
                @content;
            }
        }

    }
}

And here is the function I started to make in less as it seems every declaration can not be implemented the same as in sass :

.bp(@feature; @val) when (@mq-support = true) {
    @med: ~"only screen";

    @media @{med} and (@{feature}:@val) {
        @content;
    }
}

When I'm compiling this, I got the following error :

Missing closing ')' on line 15, column 34:
15     @media @{med} and (@{feature}:@val) {
16         @content;

So this error seems to come from the closing @{feature} closing bracket but following the documentation and several blog posts on the internet, it seems that since the 1.6.0 version of less, the css property interpolation is a feature that should work.

Does anybody have an idea of what could be wrong here ? Is it actually possible to use a variable as a property in a media query ?

Maybe I'm doing it totally wrong but it seems the mixins guard feature in less does not work exactly the same as with SASS and the @if condition so the "translation" is a little bit different.

Thank you in advance

Sébastien


Solution

  • Interpolation or using variables in media queries work slightly differently in Less.

    • First of all, you shouldn't use the normal interpolation syntax (@{med}). Instead it should just be @med.
    • Next the second condition should also be set to a variable and then appended to the media query just like the @med variable or it should be included as part of the @med variable itself. I've given a sample for both approaches below.
    .bp(@feature; @val) when (@mq-support = true) {
      @med: ~"only screen and";
      @med2: ~"(@{feature}:@{val})";
      @media @med @med2{
        @content();
      }
    }
    

    or

    .bp(@feature; @val) when (@mq-support = true) {
      @med: ~"only screen and (@{feature}:@{val})";
      @media @med {
        @content();
      }
    }
    

    Below is a sample conversion of that Sass code completely into its Less equivalent. Less does not support the @content like in Less, so it should be passed as a detached ruleset with the mixin call.

    @mq-support: true;
    @mq-fixed-value: 20px;
    
    .bp(@feature; @val; @content) {
      & when (@mq-support = true) {
        @med: ~"only screen and (@{feature}:@{val})";
        @media @med {
          @content();
        }
      }
      & when not (@mq-support = true) {
        & when (@feature = min-width) {
          & when (@val <= @mq-fixed-value){
            @content();
          }
        }
        & when (@feature = max-width) {
          & when (@val >= @mq-fixed-value){
            @content();
          }
        }
      }
    }
    
    a{
      .bp(max-width, 100px, { color: red; } );
    }
    b{
      .bp(min-width, 10px, { color: blue; } );
    }