How to get $values of Array in SCSS?

2019-08-02 17:18发布

问题:

I'm making my own plugins that makes multiple media queries automatically by writing single @include line in SCSS.

So when I type @include medias($bp-values, width);, the output should be like this:

@media all and (min-width: 564px) {
    width: 200px;
}
@media all and (min-width: 768px) {
    width: 300px;
}
@media all and (min-width: 992px) {
    width: 400px;
}
@media all and (min-width: 1200px) {
    width: 500px;
}

And this is the code:

$breakpoints: (
    564,
    768,
    992,
    1200
);

$bp-values: (
    width: (
        200px, 300px, 400px, 500px
    ),
    font-size: (
        20px, 30px, 40px, 50px
    )
);

@function gridnum($m, $v) {
    @return map-get($m, $v);
}

@mixin medias($map, $key) {
    $myList: map-get($map, $key);
    @each $value in $myList {
        $number: index($myList, $value);
        $grid: gridnum($breakpoints, $num);
        @if $value == $num {
            @media all and (min-width: $grid + px) {
                #{$key}: $value;
            }   
        } @else {
            @warn "There is an error to make @media queries.";
        }
    }
}

What I need is to get the $values of $breakpoints for setting it as prefixes of @media queries' width.

But the code doesn't run, and I get this:

Error: Undefined variable: "$num".

Most idle solution would be to merge 2 $maps in single @each directive, but seems like SCSS doesn't support this.

Is there any ways to fix this problem?

回答1:

In my opinion you did not understand very well the difference between maps and lists.

The list is an array of values:

$breakpoints: (
    564,
    768,
    992,
    1200
);

or

$breakpoints: 564, 768, 992, 1200;

or

$breakpoints: 564 768 992 1200;

So this @return map-get($m, $v); will get you always errors because $breakpoints is not a map.

The maps have keys and values:

 $breakpoints: (
        xs: 564,
        md: 768,
        lg: 992,
        xl: 1200
    );

To help you in your project, maybe it is better to write a map of nested maps:

$myMap:(
  xs:(
    min-width: 564px,
    width: 200px,
    font-size: 20px
  ),
  md:(
    min-width: 768px,
    width: 300px,
    font-size: 30px
  ),
  lg:(
    min-width: 992px,
    width: 400px,
    font-size: 40px
  ),
  xl:(
    min-width: 1200px,
    width: 500px,
    font-size: 50px
  )
);

It is more clear the correlation to every values. Now we can write a @mixin to get those values:

@mixin medias($map, $key) {
  @each $keyMap, $valueMap in $map {
    @media all and (min-width: map-get($valueMap, min-width)) {
        #{$key}: map-get($valueMap, $key);
    }   
  }
}

And now we can include it!

@include medias($myMap, width);

This is the result you asked for:

@media all and (min-width: 564px) {
  width: 200px;
}

@media all and (min-width: 768px) {
  width: 300px;
}

@media all and (min-width: 992px) {
  width: 400px;
}

@media all and (min-width: 1200px) {
  width: 500px;
}

I posted your new sass file, much more understandable, I think

$myMap:(
  xs:(
    min-width: 564px,
    width: 200px,
    font-size: 20px
  ),
  md:(
    min-width: 768px,
    width: 300px,
    font-size: 20px
  ),
  lg:(
    min-width: 992px,
    width: 400px,
    font-size: 20px
  ),
  xl:(
    min-width: 1200px,
    width: 500px,
    font-size: 20px
  )
);

@mixin medias($map, $key) {
  @each $keyMap, $valueMap in $map {
    @media all and (min-width: map-get($valueMap, min-width)) {
        #{$key}: map-get($valueMap, $key);
    }   
  }
}

@include medias($myMap, width);