如何在data属性或nth-child选择器中使用CSS变量动态显示子元素?
问题描述
现有一个场景:通过设置父元素的data-scp_parent属性,展示对应data-scp值的子元素。当前实现需要在CSS中逐个枚举对应值,但无法提前知晓子元素总数。尝试过用CSS变量在data属性或nth-child()中使用,发现不生效(六年前的Stack Overflow问题也表明当时nth-child不支持该用法)。需求如下:
- 仅修改父元素相关CSS,即可显示目标子元素,无需提前知道子元素总数
- 超过第5行的元素默认不显示
示例代码
HTML
<p>Input an integer from 1 to 7 for data-scp.</p> <div><input type="text"><button>Show</button></div> <div data-scp_parent=""> <div data-scp="1">SCP 1</div> <div data-scp="2">SCP 2</div> <div data-scp="3">SCP 3</div> <div data-scp="4">SCP 4</div> <div data-scp="5">SCP 5</div> <div data-scp="6">SCP 6</div> <div data-scp="7">SCP 7</div> </div>
CSS(当前实现)
div[data-scp] { display: none; } div[data-scp_parent="1"] > div[data-scp="1"], div[data-scp_parent="2"] > div[data-scp="2"], div[data-scp_parent="3"] > div[data-scp="3"], div[data-scp_parent="4"] > div[data-scp="4"], div[data-scp_parent="5"] > div[data-scp="5"] { display: block; }
JS
var scpParent = document.querySelector('div[data-scp_parent]'); document.querySelector('button').addEventListener('mousedown', handler, false); function handler(evt) { let e = evt.target v = e.previousElementSibling.value ; scpParent.dataset.scp_parent = v; }
解决方案
方案一:兼容多数浏览器(无需枚举所有子元素,仅处理1-5范围)
利用属性选择器组合,结合“超过第5行隐藏”的限制,只需要枚举1-5的匹配规则即可,无需关心子元素总数(超过5的元素会被直接隐藏):
/* 默认隐藏所有子元素 */ div[data-scp] { display: none; } /* 强制隐藏第6个及以后的子元素,满足“超过第5行不显示”的要求 */ div[data-scp_parent] > div[data-scp]:nth-child(n+6) { display: none; } /* 匹配父元素data-scp_parent与子元素data-scp值相等的情况,仅处理1-5的有效范围 */ div[data-scp_parent="1"] > div[data-scp="1"], div[data-scp_parent="2"] > div[data-scp="2"], div[data-scp_parent="3"] > div[data-scp="3"], div[data-scp_parent="4"] > div[data-scp="4"], div[data-scp_parent="5"] > div[data-scp="5"] { display: block; }
注:若需兼容更旧浏览器,可保留原选择器写法,但仅需维护1-5的规则即可,无需跟随子元素总数扩展。
方案二:现代浏览器最优解(无需枚举,用CSS变量)
目前主流浏览器(Chrome 111+、Firefox 109+、Safari 16.4+)已支持在nth-child()中使用CSS变量,结合JS设置变量即可实现完全动态匹配,无需提前枚举任何值:
修改后的CSS
div[data-scp_parent] { --target-index: 0; /* 默认值,无元素显示 */ } /* 默认隐藏所有子元素 */ div[data-scp] { display: none; } /* 隐藏第6个及以后的子元素 */ div[data-scp_parent] > div[data-scp]:nth-child(n+6) { display: none; } /* 显示目标索引对应的子元素 */ div[data-scp_parent] > div[data-scp]:nth-child(var(--target-index)) { display: block; }
修改后的JS(仅需新增设置CSS变量的代码)
var scpParent = document.querySelector('div[data-scp_parent]'); document.querySelector('button').addEventListener('mousedown', handler, false); function handler(evt) { let e = evt.target; let v = e.previousElementSibling.value; // 设置CSS变量,用于nth-child匹配 scpParent.style.setProperty('--target-index', v); // 保留原data属性设置(可选,若无需其他用途可移除) scpParent.dataset.scp_parent = v; }
这个方案完全不需要提前知道子元素总数,只要输入的索引≤5,就能显示对应子元素;输入>5的话,由于第6个及以后的元素已被强制隐藏,不会显示任何内容,完全符合需求。
内容的提问来源于stack exchange,提问作者Gary
相关产品推荐
相关产品推荐

