通过SASS循环嵌套选择器

时间:2014-03-12 11:11:31

标签: css sass

我有这个HTML

<ul> // first level
  <li>
    <ul></ul> // second level
  </li>
  <li>
    <ul> // second level
      <li>
        <ul></ul> // third level
      </li>
    </ul>
  </li>
</ul>

是否有可能将嵌套列表相互循环,以获得类似这样的内容:

ul {
 padding: 10px;
 ul {
  padding: 20px;
  ul {
    padding: 30px;
    ... through 10 * ul
  }
 }
}  

有了这个我只有列表乘法。

@for $i from 1 through 10 {
    ul {
        padding-left: 100 - (10 * $i) + px;
    }
  }

2 个答案:

答案 0 :(得分:8)

对于3.4之前的Sass版本,您需要执行此操作的功能不是本机Sass的一部分(并且递归mixin不能在某些版本中工作)。您需要名为nest()的Compass函数。

$sel: '';
@for $i from 1 through 10 {
    // remove !global flag if you're using Sass < 3.3
    $sel: if($i == 1, "ul", nest($sel, "ul")) !global;

    #{$sel} {
        padding-left: 10px * $i;
    }
}

Sass 3.4具有此函数的本机版本,名为selector-nest()

$sel: '';
@for $i from 1 through 10 {
    $sel: if($i == 1, "ul", selector-nest($sel, "ul")) !global;

    #{$sel} {
        padding-left: 10px * $i;
    }
}

输出:

ul {
  padding-left: 10px;
}

ul ul {
  padding-left: 20px;
}

ul ul ul {
  padding-left: 30px;
}

ul ul ul ul {
  padding-left: 40px;
}

ul ul ul ul ul {
  padding-left: 50px;
}

ul ul ul ul ul ul {
  padding-left: 60px;
}

ul ul ul ul ul ul ul {
  padding-left: 70px;
}

ul ul ul ul ul ul ul ul {
  padding-left: 80px;
}

ul ul ul ul ul ul ul ul ul {
  padding-left: 90px;
}

ul ul ul ul ul ul ul ul ul ul {
  padding-left: 100px;
}

如果你想拼出最初的ul,你可以这样做:

ul {
    // parent styles
    border: 1px solid;

    $sel: '';
    @for $i from 2 through 10 {
        $sel: if($i == 2, 'ul', nest($sel, 'ul')); // note no !global flag

        #{$sel} {
            padding-left: 10px * $i;
        }
    }
}

请注意,可以使用简单的字符串连接而不是其中任何一个函数,但它只适用于您只嵌套单个选择器的情况。如果你有2个或更多选择器,这是绝对必要的:

$sel: '';
@for $i from 1 through 3 {
    $sel: if($i == 1, "article, section", selector-nest($sel, "article, section")) !global;

    #{$sel} {
      h1 {
        padding-left: 10px * $i;
      }
    }
}

输出:

article h1, section h1 {
  padding-left: 10px;
}

article article h1, article section h1, section article h1, section section h1 {
  padding-left: 20px;
}

article article article h1, article article section h1, article section article h1, article section section h1, section article article h1, section article section h1, section section article h1, section section section h1 {
  padding-left: 30px;
}

答案 1 :(得分:0)

以@cimmanon的答案(我用作我的基础)为基础,可以简化此过程,并使用&选择器来做到这一点:

.listitem {
  padding: 0;
  
  $self: &;

  @for $i from 1 through 10 {
    #{$self} {
      padding-left: #{ $i * 1em };
    }
    
    $self: #{ $self + ' ' + & };
  }
}

这样,您可以将.listitem更改为所需的任何内容,而无需更改列表中的任何选择器-循环中没有任何内容是硬编码的。

作为可重复使用的混合

一旦self的值被继承且未进行硬编码,您还可以自由地将其全部移至mixin,如下所示:

@mixin nested($depth: 5) {
  $self: &;

  @for $i from 1 through 10 {
    $nestedDepth: $i !global;
    
    #{$self} {
      @content;
    }
    
    $self: #{ $self + ' ' + & };
  }
}

边注: 与其他语言相比,令人困惑的是,CSS中的!表示以下单词描述了变量-例如color: green !important表示颜色green很重要,因此!global同样意味着SCSS变量是全局变量-并不是说它不是全局变量...我知道,很奇怪的标准,但我偏离题名了

上面的mixin可以用作:

.listitem {
  padding: 0;
  
  @include nested(4) {
    padding-left: #{ $nestedDepth * 1em  };
  }
}

.otherlist {
  margin: 0;
  
  @include nested(8) {
    margin-left: #{ $nestedDepth * 1em  };
  }
}

并且现在可以在任何深度,可变深度等位置重复使用