[翻译]nth-child的工作机制

本文深入解析CSS中的nth-child选择器,解释其工作原理并提供实例演示。通过不同参数设置,实现对特定子元素的选择与样式调整。同时讨论其浏览器兼容性问题与替代方案,为开发者提供实用的前端开发技巧。

有一种CSS选择器叫做nth-child,是一种伪类选择器,下面是一个使用它的例子:

1
2
3
ul li:nth-child(3n+3) {
  color: #ccc;
}

上面这段CSS做了什么?它选择了一个无序列表(UL)中能被3整除的子元素(LI),第3、第6、第9、第12……都在其作用范围。那么它是如何工作的呢?我们又能用它来做些什么?不妨一起来看一下。

归结起来,括号中的参数使用有2种方式,首先它可以接受关键字,这里只限”even”和”odd”两种关键词可以使用,显而易见,”even”代表偶数项目,而”odd”代表奇数项目。

就像上面那个例子中所见到的,nth-child的参数也可以是一个方程式。最简单的程式是什么?它可以只有一个数字。如果你将一个数字放在括号中,那么它将选择出与其对应的项目。如下面的例子,只选择出了第5个子元素。

1
2
3
ul li:nth-child(5) {
  color: #ccc;
}

让我们回到最上面的例子,看看3n+3是如何工作的。这里的关键在于”n”和数学方程式。想象n从0开始,对应所有正整数,0、1、2、3、……然后完成这个方程式。所以3n=3×n,而3n+3=(3×n)+3。然后将递进的正整数代入,我们得到:

(3 x 0) + 3 = 3 = 第三个子元素
(3 x 1) + 3 = 6 = 第六个子元素
(3 x 2) + 3 = 9 = 第九个子元素
以此类推。

那么:nth-child(2n+1)是什么样的呢?

(2 x 0) + 1 = 1 = 第一个子元素
(2 x 1) + 1 = 3 = 第三个子元素
(2 x 2) + 1 = 5 = 第五个子元素
以此类推。

嗨!等一下,这和”odd”所表示的一模一样,因此或许我们不会很频繁地用到这个方程式。但是等等,这是不是又说明我们原先的那个方程式(3n+3)太复杂了呢?为什么不用(3n+0)或者更简单的(3n)?

(3 x 0) = 0 = 无匹配
(3 x 1) = 3 = 第三个子元素
(3 x 2) = 6 = 第六个子元素
(3 x 3) = 9 = 第九个子元素
以此类推。

所以正如你看到的,(3n+3)、(3n+0)和(3n)实际上没有任何差别,所以完全没有必要+3。我们也可以使用负的n值,以及减法公式。例如(4n-1):

(4 x 0) – 1 = -1 = 无匹配
(4 x 1) – 1 = 3 = 第三个子元素
(4 x 2) – 1 = 7 = 第七个子元素
以此类推。

如果使用负数的n值,看起来会有些怪异,因为如果结果是负数,则不能匹配到任何元素。所以你需要再使用一个加法等式来使结果重新回到正数。
事实证明,这是一个相当聪明的技术,你可以用它来选择前n个子元素。比如(-n+3):

-0 + 3 = 3 = 第三个子元素
-1 + 3 = 2 = 第二个子元素
-2 + 3 = 1 = 第一个子元素
-3 + 3 = 0 = 无匹配
etc.

Sitepoint有一个很好的参考指南,其中包括了下面这个 handy-dandy table,我很不厚道地黏贴了过来。

n2n+14n+14n+44n5n-2-n+3
0114--3
1358432
25912881
3713161213-
4917201618-
51121242023-

浏览器兼容性

nth-child是众多非常不幸的CSS属性之一,它们被浏览器兼容风暴所洗礼,而被很多厂家刨除在外,不被接受。整个IE系列对这个属性是零支持,包括IE8。所以它被使用时,往往是以一种“渐进增强”的形式(例如,提供一个很酷的颜色调板表)。而当你想要创建某些更重要的内容时,类似于某些依托于网站结构的内容,你却不应该使用这个属性。
比如你想给一个三行三列的表格中最右侧的一列删除右间距,你应该让这种效果兼容各种浏览器。

这里还有一个可取的方法是使用jQuery,它支持所有的CSS选择器,也包括这个nth-child。而它会被几乎所有浏览器所支持,也包括IE系列。

还有不理解的?

为了让你更好的理解,这里有一个测试页,在那里,你可以直接输入方程式,并立刻看到的结果是什么。

测试页

 

原文地址:http://www.decimage.com/web/how-nth-child-works.html

<template> <myModal :params="{title: $t(&#39;选择报警类型&#39;)}" :modalWidthSize="&#39;middle&#39;" :visible="visible" @submit="handleOk" @cancel="handleCancel"> <template v-slot:header><span></span></template> <template v-slot:body> <div class="alarm_type_modal"> <div class="main_content" v-if="alarmTypeList.length"> <div class="search_item"> <a-input-search @search="handleAlarmTypeSearch" :placeholder="$t(&#39;请输入报警类型名称&#39;)" /> </div> <template v-if="isShowList"> <div class="check_item"> <div class="all_check"> <a-checkbox :indeterminate="indeterminate" :checked="checkAll" @change="onCheckAllChange"> {{ $t("用电告警")}} </a-checkbox> <img class="down" @click="changeIcon" :class="{&#39;up&#39;: expanded}" src="~@/assets/img/down.png" /> </div> <div :class="[&#39;check_group_list&#39;, expanded ? &#39;checkboxUp&#39;: &#39;checkboxDown&#39; ]"> <a-checkbox-group v-model="checkedList" @change="onCheckChange"> <template v-for="el in alarmTypeList"> <a-checkbox v-if="el.isShow" :key="el.alarmTypeCode" :value="el.alarmTypeCode"> <span :title="$t(el.alarmTypeName)"> {{ $t(el.alarmTypeName) }} </span> </a-checkbox> </template> </a-checkbox-group> </div> </div> </template> <noData v-else /> </div> <a-space :size="64" v-else> <a-spin tip="加载中,请稍候..." /> </a-space> </div> </template> </myModal> </template> <script> import factory from &#39;../../factory&#39;; import noData from &#39;@/components/tableNoData&#39; import myModal from "@/components/scfComponents/modalComponents/modal.vue"; export default { components: { noData, myModal }, data() { return { visible: false, isShowList: true, indeterminate: false, checkAll: false, expanded: true, checkedList: [], // 所有选中项 alarmTypeList: [], // 原始数据 checkListBak: [] } }, computed: { }, watch: { }, methods: { getAlarmTypeList() { factory.getAlarmTypeList().then(res => { this.alarmTypeList = res.map(item => ({ …item, isShow: true })) || [] this.updateCheckStatus() }) }, // 打开弹窗 showModal(data) { this.visible = true this.checkedList = [...data]; this.getAlarmTypeList(); }, // 报警类型搜索 handleAlarmTypeSearch(val) { const searchTerm = val.toLowerCase().trim(); if (!searchTerm) { this.alarmTypeList.forEach(item => { item.isShow = true }) if (this.checkListBak.length) { this.checkedList = [...this.checkedList, ...this.checkListBak] } } else { this.checkListBak = this.checkedList // 搜索将之前选中数据备份 this.alarmTypeList.forEach(item => { if (item.alarmTypeName.toLowerCase().includes(searchTerm)) { item.isShow = true } else { item.isShow = false } }) this.checkedList = [] } this.updateCheckStatus() this.$forceUpdate() }, updateCheckStatus() { let alarmTypeCodes = this.alarmTypeList.filter(item => item.isShow) let checkedList = this.checkedList this.indeterminate = !!checkedList.length && checkedList.length < alarmTypeCodes.length; this.checkAll = alarmTypeCodes.length > 0 && checkedList.length === alarmTypeCodes.length; this.isShowList = alarmTypeCodes.length > 0 }, // 全选 onCheckAllChange(e) { const alarmTypeCodes = this.alarmTypeList.filter(item => item.isShow).map(el => el.alarmTypeCode) Object.assign(this, { checkedList: e.target.checked ? [...alarmTypeCodes] : [], indeterminate: false, checkAll: e.target.checked, }); }, changeIcon() { this.expanded = !this.expanded }, // 单选 onCheckChange() { this.updateCheckStatus() }, // 确定 handleOk() { this.visible = false }, // 取消 handleCancel() { this.visible = false } }, } <style lang="less" scoped> .alarm_type_modal { width: 100%; display: flex; padding: 24px; box-sizing: border-box; justify-content: center; .main_content { width: 100%; min-height: 400px; position: relative; border-radius: 8px; border: solid 1px #c5cdd6; padding: 23px 10px 10px 16px; .search_item { width: 100%; margin-bottom: 15px; } .check_item { border-radius: 4px; margin-bottom: 10px; border: 1px solid var(--split); .all_check { display: flex; padding: 10px 16px; align-items: center; justify-content: space-between; background-color: #f0f3f7; .down { width: 13px; height: 8px; transition: all 0.5s; cursor: pointer; } .up { transform: rotate(180deg); } } .check_group_list { width: 100%; overflow: hidden; transition: all 1s; .ant-checkbox-group { width: 100%; padding: 8px 0 8px 14px; .ant-checkbox-wrapper { margin: 0; width: 25%; padding: 4px; overflow: hidden; line-height: 28px; padding-left: 18px; white-space: nowrap; text-overflow: ellipsis; border-right: 1px solid #f0f3f7; &:nth-child(4n) { border-right: none; } } } } .checkboxDown { height: 0px; } .checkboxUp { min-height: 30px; } } } } </style> 代码评审 alarmTypeList数据量1800条 不可以分页优化 不可以使用虚拟列表
08-15
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值