Thinking系列,旨在利用10分钟的时间传达一种可落地的编程思想。
开发中遇到这样一个诉求:特定class的元素单独占一行,现需要针对其前一个兄弟元素增加相应标识,以使其占据所在行的剩余所有空间。
换句话:就是如何选中特定class的前一个兄弟元素。(如何选中下面每个b
元素前的a
元素)
CSS 不存在选择前一个兄弟元素的选择器!CSS 不存在选择前一个兄弟元素的选择器!
为什么?
流布局
块元素: 按照基于其父元素的书写顺序(默认值: horizontal-tb) 的*块流动方向 (block flow direction)*放置 — 每个块级元素会在上一个元素下面另起一行。=> 从上到下
内联元素: 如果父级块级元素的宽度有足够的空间,它们与其他内联元素、相邻的文本内容(或者被包裹的)被安排在同一行。如果空间不够,溢出的文本或元素将移到新的一行。==> 从左到右
思考
了解了浏览器正常情况下的流布局形式(从左到右,从上到下),我们就可以得知:CSS 之所以不支持,是由于其流布局导致。
如果可以通过当前元素选择前一个兄弟元素,可能会导致额外的重绘操作!
CSS NEXT
:has( <forgiving-relative-selector-list> )
:has()
表示一个元素,如果作为参数传递的任何相对选择器在锚定到该元素时,至少匹配一个元素。这个伪类通过把可容错相对选择器列表作为参数,提供了一种针对引用元素选择父元素或者先前的兄弟元素的方法。
相关规范:https://www.w3.org/TR/selectors-4/#relational
MDN地址:https://developer.mozilla.org/zh-CN/docs/Web/CSS/:has
实现上述诉求:
.a:has(+ .b) {
background-color: blue;
}
其目前浏览器支持程度不是特别理想(Firefox也不支持)
解决方案
无法选择前一个兄弟元素,是有流布局导致,我们是否可以改变布局方式,来解决呢?
通过 flex 的属性flex-direction: row-reverse;
来反转,这样问题就变为了:如何选择特定class的后一个兄弟元素?
div {
display: flex;
flex-direction: row-reverse;
justify-content: flex-end;
}
li {
display: inline-block;
width: 30px;
height: 30px;
margin-right: 10px;
background-color: gainsboro;
}
.b+.a {
background-color: blue;
}
需要注意的是,此时 DOM 顺序需要反转。
<div>
<li class="b">b</li>
<li class="a">a</li>
<li class="b">b</li>
<li class="a">a</li>
<li class="a">a</li>
<li class="b">b</li>
<li class="a">a</li>
<li class="a">a</li>
<li class="a">a</li>
<li class="a">a</li>
</div>
以上就可以实现了!
总结
“既然没有选择前一个兄弟元素的选择器”,那就布局反向(从右向左),这样问题就变为了”如何选择后一个兄弟元素“。
解决这个问题的方式并不难,但思路值得延伸。