能否以HTML元素类为条件在SCSS中实现变量递增?
问题:能否用HTML元素的类作为SCSS/CSS逻辑判断条件?
我有一个动态下拉菜单,部分选项会添加.hidden类隐藏。每个选项包含按钮和hover时显示的.list元素,希望将所有非.hidden选项的.list元素对齐到底部,需为其设置基于父元素高度百分比的bottom样式,且仅对无.hidden类的元素递增计算变量值。
HTML结构如下:
<ul class="dropdown-menu components" role="dropdown"> <li class="dropdown-item hidden"> <!-- 不递增$c --> <button class="btn icon"></button> <div class="list"></div> </li> <li class="dropdown-item"> <!-- $c = 4 --> <button class="btn icon"></button> <div class="list"></div> <!-- bottom: calc(-400% - 2rem) --> </li> <li class="dropdown-item hidden"> <!-- 不递增$c --> <button class="btn icon"></button> <div class="list"></div> </li> <li class="dropdown-item"> <!-- $c = 3 --> <button class="btn icon"></button> <div class="list"></div> <!-- bottom: calc(-300% - 2rem) --> </li> <li class="dropdown-item"> <!-- $c = 2 --> <button class="btn icon"></button> <div class="list"></div> <!-- bottom: calc(-200% - 2rem) --> </li> <li class="dropdown-item hidden"> <!-- 不递增$c --> <button class="btn icon"></button> <div class="list"></div> </li> <li class="dropdown-item"> <!-- $c = 1 --> <button class="btn icon"></button> <div class="list"></div> <!-- bottom: calc(-100% - 2rem) --> </li> </ul>
尝试了以下SCSS代码,但@for循环会忽略:not(.hidden)条件,每次迭代都递增$c:
$elements: 10; $c:0; @for $i from 0 to $elements { &:not(.hidden){ $c: $c + 1; &:nth-last-child(#{$c}){ .list{ bottom: calc(calc(-100% * #{$c}) - 2rem); } } } }
我知道可以用JavaScript实现,但希望仅通过SCSS/SASS实现纯CSS方案,请问是否可行?
解决方案
纯SCSS可以实现,但需要利用CSS的:has()伪类(注意浏览器兼容性),因为预编译的SCSS无法直接感知DOM中的类存在,必须通过CSS选择器筛选符合条件的元素。
实现代码
$max-items: 10; // 设置最大可能的非.hidden元素数量 @for $c from 1 through $max-items { $selector: '&:not(.hidden)'; // 匹配从下往上第1个非.hidden元素(无后续非.hidden元素) @if $c == 1 { $selector: $selector + ':not(:has(~ &:not(.hidden)))'; } // 匹配从下往上第c个非.hidden元素(后续有c-1个非.hidden元素,且无第c个) @else { // 构建"后续有c-1个非.hidden元素"的条件 $selector: $selector + ':has('; @for $i from 1 through $c - 1 { $selector: $selector + '~ &:not(.hidden)'; @if $i < $c - 1 { $selector: $selector + ':has('; } } // 闭合所有:has(括号 @for $i from 1 through $c - 1 { $selector: $selector + ')'; } // 排除后续有第c个非.hidden元素的情况 $selector: $selector + ':not(:has('; @for $i from 1 through $c { $selector: $selector + '~ &:not(.hidden)'; @if $i < $c { $selector: $selector + ':has('; } } @for $i from 1 through $c { $selector: $selector + ')'; } } #{$selector} { .list { bottom: calc(-#{$c} * 100% - 2rem); } } }
代码说明
- 循环生成计数选择器:从
c=1到设定的最大数量,为每个计数生成对应的CSS选择器 - 筛选非.hidden元素:通过
:not(.hidden)排除隐藏项 - 精准计数:利用
:has()伪类检测当前元素后续的非.hidden元素数量,确保只对从下往上的第c个非.hidden元素应用样式 - 动态适配:如果.hidden类是动态添加/移除的,CSS会自动重新匹配选择器,无需重新编译SCSS
兼容性说明
:has()伪类目前支持Chrome、Edge、Safari 15.4+;Firefox需要手动开启layout.css.has-selector.enabled配置- 如果需要兼容旧浏览器,纯CSS/SCSS方案无法实现,建议使用JavaScript辅助
内容的提问来源于stack exchange,提问作者Mironek
相关产品推荐
相关产品推荐

