CSS :not(:first-of-type)选择器作用于div不生效问题排查
CSS原生的:first-of-type选择器匹配规则是选中同父元素下、同标签类型的第一个子元素,该类选择器(包括:last-of-type、:nth-of-type系列)仅按标签名做匹配,完全不识别class、id等自定义属性筛选条件,这是逻辑失效的核心原因。
查看你的DOM结构,.accordion-container下的直接子元素全部是div标签,排列顺序为:
- 第1个div:
.accordion-title(Standard套餐标题) - 第2个div:
.accordion-content(第一个内容区) - 第3个div:
.accordion-title(Pro套餐标题) - 第4个div:
.accordion-content(第二个内容区) - 第5个div:
.accordion-title(Elite套餐标题) - 第6个div:
.accordion-content(第三个内容区)
你写的$(".accordion-content:not(:first-of-type)")逻辑,实际执行时会先找所有带.accordion-content类的div,再排除其中「父容器下第一个div」的元素——但所有.accordion-content对应的div分别是父容器下的第2、4、6个子元素,没有一个符合“同层级第一个div”的条件,因此该选择器选不到任何元素,隐藏逻辑完全不生效。
你之前测试把.accordion-content的标签换成p、h5就能正常运行,本质是换标签后,第一个.accordion-content成了父容器下第一个该标签类型的元素,剩余同标签的内容区刚好被:not(:first-of-type)命中,属于巧合匹配,并非原有逻辑正确。
顺带一提,你代码里$(".js-accordion-title:first-of-type")能正常给第一个标题加open类,只是因为第一个.accordion-title刚好是父容器下的第一个div,碰巧符合选择器规则,同样存在标签类型依赖的隐患。
方案1:用jQuery集合过滤器(改动最小,零侵入)
jQuery自带的:first过滤器、.first()方法是针对已匹配到的jQuery元素集合取第一个元素,不受标签类型限制,完全匹配你的需求,只需要修改两行初始化代码即可,不需要调整HTML和CSS:
$(function() { // 选中所有内容区,排除集合内第一个,全部隐藏 $(".accordion-content").not(":first").css("display", "none"); // 给第一个标题添加open类 $(".js-accordion-title").first().addClass("open"); $(".js-accordion-title").click(function() { $(".open").not(this).removeClass("open").next().slideUp(300); $(this).toggleClass("open").next().slideToggle(300); }); });
方案2:默认状态写在CSS里(体验最好,无加载闪烁)
把默认展开/隐藏的逻辑直接写在CSS里,HTML提前给默认展开的项加状态类,既可以避免选择器匹配问题,还能解决JS初始化延迟导致的页面加载瞬间所有手风琴全展开的闪烁问题:
- 首先修改HTML,给默认展开的项预置状态类:
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script> <div id="accordion" class="accordion-container"> <!-- 给第一个标题预置open类 --> <div class="accordion-title js-accordion-title open"> <h2 class="price-plan-name">Standard</h2> <h3 class="starting-price">Starting at <span class="price-number">$1,650</span></h3> </div> <!-- 给第一个展示的内容区预置active类 --> <div class="accordion-content is-active"> <p>Accordion Content1</p> </div> <div class="accordion-title js-accordion-title"> <h2>Pro</h2> <h3 class="accordion-subtitle">Starting at <span class="price-number">$2,950</span></h3> </div> <div class="accordion-content"> Accordion Content2 </div> <div class="accordion-title js-accordion-title"> <h2>Elite</h2> <h3 class="accordion-subtitle">Starting at <span class="price-number">$3,950</span></h3> </div> <div class="accordion-content"> Accordion Content3 </div> </div>
- 补充CSS默认状态规则:
.accordion-content { padding-left: 2.3125em; display: none; /* 所有内容区默认隐藏 */ } .accordion-content.is-active { display: block; /* 激活状态的内容区展示 */ } /* 其余原有CSS保持不变 */
- 简化JS逻辑,去掉初始化操作:
$(function() { $(".js-accordion-title").click(function() { // 重置其他展开项的状态 $(".open").not(this).removeClass("open").next().removeClass("is-active").slideUp(300); // 切换当前项状态 $(this).toggleClass("open").next().toggleClass("is-active").slideToggle(300); }); });
该方案维护性更强,后续新增手风琴项不需要调整选择器逻辑,首屏加载体验更好,是生产环境推荐的写法。
内容的提问来源于stack exchange,提问作者Versa

