如何使用CSS匹配动态生成日期类名的首个同日期元素
问题场景
你当前需要处理按日期升序排列的事件列表,生成DOM时会给每个事件的日期节点拼接格式为event_date_dd-mm-yyyy的动态类名,DOM结构示例如下:
<div class="event"> <div class="event_date_20-06-2020">title</div> </div> <div class="event"> <div class="event_date_20-06-2020">title</div> </div> <div class="event"> <div class="event_date_21-06-2020">title</div> </div> <div class="event"> <div class="event_date_22-06-2020">title</div> </div> <div class="event"> <div class="event_date_22-06-2020">title</div> </div>
需求是仅展示每个日期对应的第一个事件,你之前尝试的通配类CSS规则没有生效,失效代码如下:
.event_date_[all-dates] {display:none;} .event_date_[first-iteration-of-a-date]:first-of-type {display:block;}
原因说明
你之前的写法无法生效有两个核心原因:
- CSS本身不支持
[all-dates]这类占位符通配语法,属性选择器只能匹配固定的属性值片段 :first-of-type是按标签类型匹配同级第一个元素,无法实现「按动态类名分组取第一个」的效果
纯CSS没有提供直接匹配「拥有相同类名片段的第一个元素」的选择器,推荐按优先级选以下方案实现:
可行方案
方案1:渲染层加标记类(推荐,无兼容问题、性能最优)
你本身是动态拼接生成DOM的,只需要在遍历事件列表生成结构时加一层判断:
- 用变量记录上一个渲染的事件日期
- 如果当前事件日期和上一个日期不一致,给当前外层
.event节点追加一个固定标记类,比如first-of-date - 同日期的后续事件不加这个类
配套CSS非常简单:
/* 默认隐藏所有事件 */ .event { display: none; } /* 只显示每个日期组的第一个事件 */ .event.first-of-date { display: block; }
这个方案不依赖「列表已按日期排序」的前提,兼容所有浏览器,是生产环境最优选择。
方案2:JS后置加标记(无需修改渲染逻辑)
如果已经生成了静态DOM、无法修改前端渲染/服务端渲染的拼接逻辑,可以用几行JS遍历节点,自动给每个日期组的第一个事件加标记类:
const appearedDate = new Set(); document.querySelectorAll('.event [class*="event_date_"]').forEach(dateNode => { // 提取当前节点上的完整日期类名 const dateCls = Array.from(dateNode.classList).find(cls => cls.startsWith('event_date_')); if (!appearedDate.has(dateCls)) { appearedDate.add(dateCls); dateNode.closest('.event').classList.add('first-of-date'); } });
配套CSS和方案1完全一致即可。
方案3:纯CSS实现(不推荐,依赖高版本浏览器+严格DOM结构)
如果你的项目只需要兼容支持:has()选择器的现代浏览器(Chrome 105+、Firefox 121+、Safari 15.4+),且能保证事件列表严格按日期排序、同日期事件连续排列,可以用以下纯CSS规则实现,但不推荐生产环境使用,鲁棒性很差:
/* 默认隐藏所有日期节点 */ .event [class*="event_date_"] { display: none; } /* 第一个日期节点默认显示 */ .event:first-child [class*="event_date_"] { display: block; } /* 匹配相邻日期切换的第一个节点 */ .event:has(.event_date_20-06-2020) + .event:has(.event_date_21-06-2020) .event_date_21-06-2020, .event:has(.event_date_21-06-2020) + .event:has(.event_date_22-06-2020) .event_date_22-06-2020 { display: block; }
注意:这个写法依赖你提前枚举所有可能的日期值,无法真正做到动态通配,仅做原理演示。
内容的提问来源于stack exchange,提问作者nots0pro
相关产品推荐
相关产品推荐

