减少CSS - 减少重复

时间:2015-02-11 11:14:31

标签: css less less-mixins

我在Less中有以下代码:

我很确定这可以用某种混合物进一步抽象出来,但我现在已经摸不着头脑了。我希望能够传入一个变量,如@xs或@ xs-gutter,并让函数填充代码。

有什么想法吗?

.padding
{
    &.bottom {
        padding-bottom: @xs-gutter;
    }
    &.left {
        padding-left: @xs-gutter;
    }
    &.right {
        padding-right: @xs-gutter;
    }
    &.top {
        padding-top: @xs-gutter;
    }

    @media @sm-screen {
        &.bottom {
            padding-bottom: @sm-gutter;
        }
        &.left {
            padding-left: @sm-gutter;
        }
        &.right {
            padding-right: @sm-gutter;
        }
        &.top {
            padding-top: @sm-gutter;
        }
    }
    @media @md-screen {
        &.bottom {
            padding-bottom: @md-gutter;
        }
        &.left {
            padding-left: @md-gutter;
        }
        &.right {
            padding-right: @md-gutter;
        }
        &.top {
            padding-top: @md-gutter;
        }
    }
    @media @lg-screen {
        &.bottom {
            padding-bottom: @lg-gutter;
        }
        &.left {
            padding-left: @lg-gutter;
        }
        &.right {
            padding-right: @lg-gutter;
        }
        &.top {
            padding-top: @lg-gutter;
        }
    }
}

2 个答案:

答案 0 :(得分:2)

您可以使用循环和数组列表来减少代码中的重复。以下是关于如何实现简化的示例片段。请参阅内联注释以解释代码的作用。

  

注意:我已经将实际的padding生成mixin作为一个单独的一个,它将sides作为参数,因为你可以重新使用mixin来为多个边生成填充(通过传递边和gutter作为参数)而不为它们生成媒体查询。

@gutters: 4px, 6px, 8px, 10px; // the gutter sizes corresponding to each screen size
@media-sizes: xs, sm, lg, md; // possible screen sizes
@media-conditions: ~"(min-width: 100px)", ~"(min-width: 150px)", ~"(min-width: 200px)", ~"(min-width: 250px)"; // media condition for each screen size

.media-generator(){
    .loop-sizes(length(@media-sizes)); // loop through all screen sizes
    .loop-sizes(@screenIndex) when (@screenIndex > 0) {
        & when (extract(@media-sizes, @screenIndex) = xs){ // since we need xs as default
            .padding-per-side(extract(@gutters, 1); left; right; bottom; top);
        }
        & when not (extract(@media-sizes, @screenIndex) = xs){ // when screen size is not xs
            @condition: extract(@media-conditions, @screenIndex); // extract media condition corresponding to screen type
            @media @condition{
                .padding-per-side(extract(@gutters, @screenIndex); left; right; bottom; top); // call the mixin to generate padding for all sides
            }
        }
        .loop-sizes(@screenIndex - 1);
    }
}
.padding-per-side(@gutter; @sides...){
    .loop-sides(length(@sides));
    .loop-sides(@index) when (@index > 0){
        @side: extract(@sides, @index);
        &.@{side}{
            padding-@{side}: @gutter;
        }
        .loop-sides(@index - 1);
    }
}
.padding{
    .media-generator(); // generate padding for all sides and screens like in question
}

#demo{ // extra :)
    .padding-per-side(10px; left;right); // generates 10px padding for left and right
}

以下是上述的增强版本,它允许我们仅为某些方面生成带有媒体查询的填充。下面的代码片段与上面的代码片段之间的区别在于,您可以在此处仅为特定边生成填充以及媒体查询版本。

@gutters: 4px, 6px, 8px, 10px;
@media-sizes: xs, sm, lg, md;
@media-conditions: ~"(min-width: 100px)", ~"(min-width: 150px)", ~"(min-width: 200px)", ~"(min-width: 250px)";

.media-generator(@sides...){
    & when (length(@sides) = 0){
        .loop-sizes(length(@media-sizes));
        .loop-sizes(@screenIndex) when (@screenIndex > 0) {
            & when (extract(@media-sizes, @screenIndex) = xs){
                .padding-per-side(extract(@gutters, 1); left; right; bottom; top);
            }
            & when not (extract(@media-sizes, @screenIndex) = xs){
                @condition: extract(@media-conditions, @screenIndex);
                @media @condition{
                    .padding-per-side(extract(@gutters, @screenIndex); left; right; bottom; top);
                }
            }
            .loop-sizes(@screenIndex - 1);
        }
    }
    & when not (length(@sides) = 0){
        .loop-sizes(length(@media-sizes));
        .loop-sizes(@screenIndex) when (@screenIndex > 0) {
            & when (extract(@media-sizes, @screenIndex) = xs){
                .padding-per-side(extract(@gutters, 1); @sides);
            }
            & when not (extract(@media-sizes, @screenIndex) = xs){
                @condition: extract(@media-conditions, @screenIndex);
                @media @condition{
                    .padding-per-side(extract(@gutters, @screenIndex); @sides);
                }
            }
            .loop-sizes(@screenIndex - 1);
        }
    }   
}
.padding-per-side(@gutter; @sides...){
    .loop-sides(length(@sides));
    .loop-sides(@index) when (@index > 0){
        @side: extract(@sides, @index);
        &.@{side}{
            padding-@{side}: @gutter;
        }
        .loop-sides(@index - 1);
    }
}
.padding{
    .media-generator(left; right); // specify sides if needed else leave blank
}

答案 1 :(得分:1)

我个人详细阐述了3个可能的解决方案,从最简单的解决方案开始,然后优化到第3个。最容易获得更好的可读性,最难使用双嵌套LOOP

在这里,我报告"普通" 3个解决方案之间的代码(我决定保留可能的大小定义,更直观):

@sm-screen:~"(min-width: 320px)";
@md-screen:~"(min-width: 720px)";
@lg-screen:~"(min-width: 1200px)";

@xs-gutter:20px;
@sm-gutter:30px;
@md-gutter:40px;
@lg-gutter:50px;

@property:padding;
//@property:margin;

请注意,@property可以是" margin"或" padding"无动于衷,只需转换评论。

对于此变量定义,您可以附加以下3个提议:


解决方案1 ​​

这是最简单的解决方案。缺点是它为每个规则生成不同的媒体查询,导致冗余代码:

.side(top, right, bottom, left);

.side(@possible-values...) 
{
  .generate-property-loop(1, @possible-values);
}

.generate-property-loop(@var; @possible-values) when (@var <= length(@possible-values)) 
{
  //Let's extract values in @var position from list @possible-values
  @direction: extract(@possible-values, @var);

  .@{property}.@{direction} 
  {
        @{property}-@{direction}: @xs-gutter;

        @media @sm-screen 
        {
           @{property}-@{direction}: @sm-gutter;
        }

        @media @md-screen 
        {
           @{property}-@{direction}: @md-gutter;
        }

        @media @lg-screen 
        {
           @{property}-@{direction}: @lg-gutter;
        }

  }

  .generate-property-loop((@var + 1), @possible-values);
}

解决方案2

一种可能的解决方案是将媒体查询移到LOOP之外,但它仍然需要显式的媒体查询定义:

.side(top, right, bottom, left);

.side(@possible-values...) 
{
  .generate-property-loop(1, @possible-values, @xs-gutter);

  @media @sm-screen 
  {
    .generate-property-loop(1, @possible-values, @sm-gutter);
  }

  @media @md-screen 
  {
    .generate-property-loop(1, @possible-values, @md-gutter);
  }

  @media @lg-screen 
  {
    .generate-property-loop(1, @possible-values, @lg-gutter);
  }

}

.generate-property-loop(@var, @possible-values, @gutter) when (@var <= length(@possible-values)) 
{
  //Let's extract values in @var position from list @possible-values
  @direction: extract(@possible-values, @var);

  .@{property}
  {
     &.@{direction} 
     {
        @{property}-@{direction}: @gutter;
     } 
  }

  .generate-property-loop((@var + 1), @possible-values, @gutter);
}

解决方案3

使用双嵌套循环,您可以实现完全的灵活性,只需通过&#34;指示&#34;和&#34; scren-size&#34;作为参数,但以较小的可读性为代价:

.side(top, right, bottom, left);

.side(@possible-values...) 
{
  .generate-property-loop(1, @possible-values, @xs-gutter);

  .mediaquery-loop(sm,md,lg);
}

.mediaquery-loop(@possible-screens...)
{
  .generate-mediaquery-loop(1, @possible-screens);
}

.generate-property-loop(@var, @possible-values, @gutter) when (@var <= length(@possible-values)) 
{
  @direction: extract(@possible-values, @var);

  .@{property}
  {
     &.@{direction} 
     {
        @{property}-@{direction}: @gutter;
     } 
  }

  .generate-property-loop((@var + 1), @possible-values, @gutter);
}

.generate-mediaquery-loop(@var, @possible-sizes) when (@var <= length(@possible-screens)) 
{
  @sizes: extract(@possible-sizes, @var);

  @screen-size: ~"@{sizes}-screen";
  @gutter-size: ~"@{sizes}-gutter";

  @media @@screen-size
  {
    .generate-property-loop(1, @possible-values, @@gutter-size);
  }

  .generate-mediaquery-loop((@var + 1), @possible-screens);
}