考察如下的 HTML 片段,通过 CSS 的 nth-child() 伪选择器实现列表的颜色循环,比如每三个一次循环。

<ul>
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
<li>6</li>
</ul>

很容易地,我们能得出如下样式代码:

ul {
li:nth-child(3n + 1) {
color: indigo;
}
li:nth-child(3n + 2) {
color: red;
}
li:nth-child(3n + 3) {
color: green;
}
}

以上,只三种颜色循环,简单情况下可这样处理。但样式多起来之后,上面代码显得很臃肿且不易维护。

既然是使用 SASS,很容易想到可通过编写循环语句来将其简化。

循环过程就是遍历一个预设的颜色列表,为每一个颜色生成相应的样式。

List & Map

首先需要定义一个对象来保存预设的颜色列表,SASS 中的 Lists 可满足条件。

$colors: indigo, red, green;

使用上面的 list:

$colors: indigo, red, green;

@each $color in $colors {

.color-#{$color} {

color: $color;

}

}

编译后输出:

.color-indigo {
color: indigo;
} .color-red {

color: red;

} .color-green {

color: green;

}

当然,也可以定义 Map 类型,为每种颜色指定名字,这样使用的时候比较语义:

$colors: (
"indigo": indigo,
"red": red,
"green": green
); @each $name, $color in $colors {

.color-#{$name} {

color: $color;

}

}

索引

列表对象及其遍历如上,现在还需要在遍历过程中获得一个 index 索引值,用于生成 3*n+index

通过 index() 函数可以达到目的:

$colors: (indigo, red, green);

@each $color in $colors {

$index: index($colors, $color);

.color-#{$index} {

color: $color;

}

}

编译后输出:

.color-1 {
color: indigo;
} .color-2 {

color: red;

} .color-3 {

color: green;

}

生成 nth-child 样式

结合上面所有,可以得出生成 nth-child 样式的代码:

$colors: (indigo, red, green);

ul {

@each $color in $colors {

$index: index($colors, $color);

li:nth-child(3n + #{$index}) {

color: $color;

}

}

}

编译后输出:

ul li:nth-child(3n + 1) {
color: indigo;
}
ul li:nth-child(3n + 2) {
color: red;
}
ul li:nth-child(3n + 3) {
color: green;
}

注意到 nth-child(3n + #{$index}) 中的 3 是硬编码。既然我们的颜色是在一个数组中,所以我们是知道总个数的,也就能替换掉这里硬编码的写法。

通过 length() 函数可获得 list 的长度。改进后的代码如下:

$colors: (indigo, red, green);

ul {

@each $color in $colors {

$index: index($colors, $color);

li:nth-child(#{length($colors)}n + #{$index}) {

color: $color;

}

}

}

这样,如果后续有颜色增加,或顺序的调整,我们只需要更新 $colors 变量的值即可。

@mixin

进一步,我们可以将上面遍历生成 nth-child 的代码抽取成 mixin,这样可以被其他地方使用。

$colors: (indigo, red, green);

@mixin nth-color {

@each $color in $colors {

$index: index($colors, $color);

li:nth-child(#{length($colors)}n + #{$index}) {

color: $color;

}

}

} ul {

@include nth-color;

}

mixin 的优化

但像上面这样还不能达到完全公用,因为 mixin 中使用了 li 选择器,不是所有需要 nth-child 样式的地方,都使用的 li 元素,所以此处需要进行优化,使得 mixin 中的这部分内容灵活一点,以适用不同的使用环境。

首先,使用 & 父选择器便可快速解决,这样生成的样式便由包含这个 mixin 的选择器决定了。

$colors: (indigo, red, green);

@mixin nth-color {

@each $color in $colors {

$index: index($colors, $color);

&:nth-child(#{length($colors)}n + #{$index}) {

color: $color;

}

}

} ul {

li {

@include nth-color;

}

}

诚然,这样修改过后,确实可以将该 mixin 使用于多个地方了。

但考虑这么一种情况,因为上面列表比较简单,更加常见的情况是,列表中是另外复杂的元素,而不是单纯的一个元素,比如像下面这样:

<ul>
<li>
<div className="item">
<h3>title</h3>
<div>desc goes here...</div>
</div>
</li>
<li>
<div className="item">
<h3>title</h3>
<div>desc goes here...</div>
</div>
</li>
<li>
<div className="item">
<h3>title</h3>
<div>desc goes here...</div>
</div>
</li>
</ul>

现在想针对列表元素中的 h3 进行颜色的设置,即 nth-child 中设置的 color 只针对 h3 而不是整个 li 元素。

结合前面的优化,似乎可以这样写:

$colors: (indigo, red, green);

@mixin nth-color {

@each $color in $colors {

$index: index($colors, $color);

- &:nth-child(#{length($colors)}n + #{$index}) {

+ &:nth-child(#{length($colors)}n + #{$index}) h3{

color: $color;

}

}

} ul {

li {

@include nth-color;

}

}

编译后的结果:

ul li:nth-child(3n+1) h3 {
color: indigo;
}
ul li:nth-child(3n+2) h3 {
color: red;
}
ul li:nth-child(3n+3) h3 {
color: green;
}

从结果来看,达到了目标。但又在 nth-color 这个 mixin 中引入了 h3,使其变得不再通用,问题又回到了之前。

所以 & 只解决了 nth-child 父级嵌套的问题,对于 nth-child 后面还需要自定义选择器的情况,就需要用别的方式进一步优化。

@mixin 传参

mixin 是可以接收参数的,通过外部传递选择器进来,可以达到将 h3 从 mixin 从剥离的目的。

@mixin nth-color($child) {
@each $color in $colors {
$index: index($colors, $color);
&:nth-child(#{length($colors)}n + #{$index}) #{$child}{
color: $color;
}
}
} ul {

li {

@include nth-color("h3");

}

}

@mixin 将参数传递到外面

最后,nth-color 这个 mixin 还有一处不够灵活的地方,便是其样式内容。

现在在其中写死了只有一个 color: $color; 属性,也就是说,使用该 mixin 的地方只能用它来设置元素的字色。如果 mixin 能够将颜色传递出来,这样外部使用的时候就可以用到其他属性上,更加的灵活了。

SASS 确实也提供了这么种机制,即 mixin 能够身外传递参数,借助 @content 指令。

@content 指令指代调用 mixin 时书写的模式内容部分。如下的代码直观展示了其功能:

@mixin nth-color($child) {
@each $color in $colors {
$index: index($colors, $color);
&:nth-child(#{length($colors)}n + #{$index}) #{$child}{
color: $color;
+ @content;
}
}
} ul {

li {

- @include nth-color("h3")

+ @include nth-color("h3"){

+ border:1px solid orange;

+ };

}

}

编译后内容为:

ul li:nth-child(3n+1) h3 {
color: indigo;
border: 1px solid orange;
}
ul li:nth-child(3n+2) h3 {
color: red;
border: 1px solid orange;
}
ul li:nth-child(3n+3) h3 {
color: green;
border: 1px solid orange;
}

可以看到,外部书写的 border: 1px solid orange; 通过 @content 指代而放进了每个 nth-child 样式中。只是这个 border 的颜色现在还是写死的 orange,现在来将其设置成跟随相应的字色,即跟着 color 属性走。

当我们使用 @content(<arguments...>) 形式的 @content 时,可以传递一些参数,外部调用该 mixin 时需要使用如下形式来获取传递的参数:

@include <name> using (<arguments...>)

NOTE::这里的 using 语法只部分 SASS 实现(Dart Sass since 1.15.0, LibSass, Ruby Sass)中有支持,node-sass 还没有。

最终的 mixin

所以,最终版的代码为:

$colors: (indigo, red, green);

@mixin nth-color($child) {

@each $color in $colors {

$index: index($colors, $color);

&:nth-child(#{length($colors)}n + #{$index}) #{$child} {

color: $color;

@content ($color);

}

}

} ul {

li {

@include nth-color("h3") using($color) {

border: 1px solid #{$color};

}

}

}

编译后得到的 CSS:

ul li:nth-child(3n+1) h3 {
color: indigo;
border: 1px solid indigo;
}
ul li:nth-child(3n+2) h3 {
color: red;
border: 1px solid red;
}
ul li:nth-child(3n+3) h3 {
color: green;
border: 1px solid green;
}

总结

通过将生成 nth-child 样式的规则自动化的过程中,顺带使用了 SASS 中另外一些特性,

  • 定义和使用数组及对象
  • 数组及对象的遍历
  • 遍历过程中索引的获取
  • @mixin 的使用,参数的传递
  • @mixin@content 的使用
  • @mixin 中向外传递参数

相关资源

利用 SASS 简化 `nth-child` 样式的生成的更多相关文章

  1. 利用Helm简化Kubernetes应用部署(1)

    目录 利用Helm简化Kubernetes应用部署  Helm基础  安装Helm  使用Visual Studio 2019为Helm编写一个简单的应用    利用Helm简化Kubernetes应 ...

  2. 利用Helm简化Kubernetes应用部署(2)

    目录 定义Charts  使用Helm部署Demo  Helm常用操作命令  定义Charts 回到之前的“charts”目录,我们依次进行解读并进行简单的修改. Chart.yaml 配置示例: a ...

  3. 利用StringList对象来管理这些动态生成的对象

    如果程序需要动态创建大量的对象,那么我们可以利用StringList对象来管理这些动态生成的对象.1.创建StringList对象:OBJ := TStringList.Create; 2.保存动态生 ...

  4. 机器学习实战 - 读书笔记(14) - 利用SVD简化数据

    前言 最近在看Peter Harrington写的"机器学习实战",这是我的学习心得,这次是第14章 - 利用SVD简化数据. 这里介绍,机器学习中的降维技术,可简化样品数据. 基 ...

  5. 【工具篇】利用DBExportDoc V1.0 For MySQL自动生成数据库表结构文档

    对于DBA或开发来说,如何规范化你的数据库表结构文档是灰常之重要的一件事情.但是当你的库,你的表排山倒海滴多的时候,你就会很头疼了. 推荐一款工具DBExportDoc V1.0 For MySQL( ...

  6. 【机器学习实战】第14章 利用SVD简化数据

    第14章 利用SVD简化数据 SVD 概述 奇异值分解(SVD, Singular Value Decomposition): 提取信息的一种方法,可以把 SVD 看成是从噪声数据中抽取相关特征.从生 ...

  7. C# 利用VS自带的WSDL工具生成WebService服务类

    C# 利用VS自带的WSDL工具生成WebService服务类   WebService有两种使用方式,一种是直接通过添加服务引用,另一种则是通过WSDL生成. 添加服务引用大家基本都用过,这里就不讲 ...

  8. 机器学习实战(Machine Learning in Action)学习笔记————09.利用PCA简化数据

    机器学习实战(Machine Learning in Action)学习笔记————09.利用PCA简化数据 关键字:PCA.主成分分析.降维作者:米仓山下时间:2018-11-15机器学习实战(Ma ...

  9. 如何利用反射简化Servlet操作

    如何利用反射简化Servlet操作   一.反射的实现 新建类BaseServlet,继承HttpServlet(不需要在web.xml文件中配置) 1.在doPost()方法中处理请求乱码,并调用d ...

随机推荐

  1. 牛客练习赛51 A abc

    A. abc 题意: 给出一个字符串s,你需要做的是统计s中子串”abc”的个数.子串的定义就是存在任意下标a<b<c,那么”s[a]s[b]s[c]”就构成s的一个子串.如”abc”的子 ...

  2. Oracle 优化器_表连接

    概述 在写SQL的时候,有时候涉及到的不仅只有一个表,这个时候,就需要表连接了.Oracle优化器处理SQL语句时,根据SQL语句,确定表的连接顺序(谁是驱动表,谁是被驱动表及 哪个表先和哪个表做链接 ...

  3. 弄懂goroutine调度原理

    goroutine简介 golang语言作者Rob Pike说,"Goroutine是一个与其他goroutines 并发运行在同一地址空间的Go函数或方法.一个运行的程序由一个或更多个go ...

  4. 行数据库VS列数据库

    一.介绍 目前大数据存储有两种方案可供选择:行存储和列存储.业界对两种存储方案有很多争持,集中焦点是:谁能够更有效地处理海量数据,且兼顾安全.可靠.完整性.从目前发展情况看,关系数据库已经不适应这种巨 ...

  5. Winform中通过代码给PanelControl添加子控件并进行定位

    场景 DevExpress的PanelControl常用进行窗体页面的布局. 一般是拖拽一个PannelControl,然后是再拖拽其他控件. 如果是由代码生成控件并控制布局的话,怎样实现. 关注公众 ...

  6. 去掉first li 的list图标

    ul中,第一个 li 前的小图标,默认情况下为小圆点,在这种情况下,给 first li 设置 list-style-type: none;可以成功去除前面的小圆点的. 当给 li 设置了 list ...

  7. 纯css耍个透明正方体转一转

    效果 效果图如下 ​ 实现思路 定义一个最外层的容器,用来控制显示的位置 定义一个父容器,用来设置元素被查看位置的视图,这里使用到CSS3的perspective 属性 定义子容器,设置为相对定位,利 ...

  8. Fortify漏洞修复总结

    1.代码注入 1.1 命令注入 命令注入是指应用程序执行命令的字符串或字符串的一部分来源于不可信赖的数据源,程序没有对这些不可信赖的数据进行验证.过滤,导致程序执行恶意命令的一种攻击方式. 问题代码: ...

  9. Rocksdb基本用法

    rocksdb 用法 rocksdb 介绍 RocksDB是使用C++编写的嵌入式kv存储引擎,其键值均允许使用二进制流.由Facebook基于levelDB开发, 提供向后兼容的levelDB AP ...

  10. Java8虚拟机(JVM)内存溢出实战

    前言 相信很多JAVA中高级的同学在面试的时候会经常碰到一个面试题 你是如何在工作中对JVM调优和排查定位问题的? 事实上,如果用户量不大的情况下,在你的代码还算正常的情况下,在工作中除非真正碰到与J ...