如何扩展Tailwind的peer-修饰符以作用于所有同级元素?
扩展Tailwind的peer修饰符实现跨同级元素样式控制
问题背景
我想扩展Tailwind的peer-修饰符,当编写以下代码时:
<div class="peer peer-hover:opacity-50"></div> <div class="peer peer-hover:opacity-50"></div> <div class="peer peer-hover:opacity-50"></div>
希望鼠标悬停任意div时,未被悬停的div透明度降低。但默认peer-修饰符仅能作用于悬停元素之后的同级元素,无法影响之前的元素。添加has-[~_.peer:hover]:opacity-50类可解决此问题,让样式能作用于悬停元素之前的同级元素。
需求是:使用peer-mod:style修饰符时,自动生成对应的has-[~_.peer:mod]:style规则;或创建新修饰符同时包含原peer-mod和对应has-规则,无需手动重复编写,且支持所有修饰符(不限于hover),询问能否通过自定义Tailwind插件实现。
代码示例
默认Peer Hover效果(仅控制后续同级元素)
<div class="absolute inset-0 flex flex-col items-center justify-center gap-10"> <div class="flex flex-col items-center gap-4"> <p class="text-xl">默认Peer Hover(仅能控制后续同级元素)</p> <div class="flex items-center justify-center gap-12"> <div class="peer size-24 rounded-md bg-lime-400 transition-transform hover:scale-125 peer-hover:scale-50 peer-hover:opacity-50"></div> <div class="peer size-24 rounded-md bg-lime-400 transition-transform hover:scale-125 peer-hover:scale-50 peer-hover:opacity-50"></div> <div class="peer size-24 rounded-md bg-lime-400 transition-transform hover:scale-125 peer-hover:scale-50 peer-hover:opacity-50"></div> <div class="peer size-24 rounded-md bg-lime-400 transition-transform hover:scale-125 peer-hover:scale-50 peer-hover:opacity-50"></div> </div> </div> </div>
改进后的Peer Hover效果(控制所有同级元素)
<div class="absolute inset-0 flex flex-col items-center justify-center gap-10"> <div class="flex flex-col items-center gap-4"> <p class="text-xl">优化后的Peer Hover(控制所有同级元素)</p> <div class="flex items-center justify-center gap-12"> <div class="peer size-24 rounded-md bg-rose-300 transition-transform hover:scale-125 peer-hover:scale-50 has-[~_.peer:hover]:scale-50 peer-hover:opacity-50 has-[~_.peer:hover]:opacity-50"></div> <div class="peer size-24 rounded-md bg-rose-300 transition-transform hover:scale-125 peer-hover:scale-50 has-[~_.peer:hover]:scale-50 peer-hover:opacity-50 has-[~_.peer:hover]:opacity-50"></div> <div class="peer size-24 rounded-md bg-rose-300 transition-transform hover:scale-125 peer-hover:scale-50 has-[~_.peer:hover]:scale-50 peer-hover:opacity-50 has-[~_.peer:hover]:opacity-50"></div> <div class="peer size-24 rounded-md bg-rose-300 transition-transform hover:scale-125 peer-hover:scale-50 has-[~_.peer:hover]:scale-50 peer-hover:opacity-50 has-[~_.peer:hover]:opacity-50"></div> </div> </div> </div>
实现方案:自定义Tailwind插件
可以通过自定义插件实现需求,以下是插件代码及三种实现思路:
tailwind.config = { plugins: [ function({ addVariant, e }) { // 思路1:创建新变体peer-any,直接匹配所有同级peer元素 addVariant('peer-any', ({ modifySelectors, separator }) => { modifySelectors(({ className }) => { return `.${e(`peer-any${separator}${className}`)}:is(.peer ~ &, & ~ .peer)`; }); }); // 思路2:直接扩展原peer变体,让原有peer-*修饰符自动支持前后同级元素 addVariant('peer', ({ modifySelectors, separator }) => { modifySelectors(({ className }) => { return `.${e(`peer${separator}${className}`)}:is(.peer ~ &, & ~ .peer)`; }); }); // 思路3:为每个peer-*修饰符自动生成对应的has-规则 addVariant('peer-auto', ({ container }) => { container.walkRules(rule => { if (rule.selector.startsWith('.peer-')) { const parts = rule.selector.slice(6).split(':'); const modifier = parts[0]; const styleClass = parts.slice(1).join(':'); const newSelector = `.${e(`peer-auto-${modifier}:${styleClass}`)}:has(~ .peer:${modifier})`; const newRule = rule.clone(); newRule.selector = newSelector; container.append(newRule); } }); }); } ] };
使用说明
- 扩展原peer修饰符:采用思路2时,原有
peer-hover:opacity-50会自动同时控制前后同级元素,无需修改代码即可实现需求。 - 使用新变体peer-any:用
peer-any-hover:opacity-50替代peer-hover:opacity-50,即可控制所有同级元素。 - 自动生成has规则的peer-auto:使用
peer-auto-hover:opacity-50,插件会自动生成对应的has-[~_.peer:hover]:opacity-50规则。
内容的提问来源于stack exchange,提问作者Zaytri
相关产品推荐
相关产品推荐

