18
头图

I believe that everyone has heard about :has recently. The specification has been mentioned for so long, but there has been no movement. Recently, the browser has finally started to support it~🎉🎉

:has Pseudo-class is a very powerful pseudo-class, which is unbelievably powerful and can do a lot of dream things. Many functions that used to only change the DOM structure or can only be achieved with JS can now be made with pure CSS It's done, let's see it together

1. A brief introduction :has

:has The syntax of the pseudo-class is very simple, which means that the element will be matched when certain conditions are met.

For example, the following selector will only match ---b479b4075d144dc8c523fbc5f016f897--- elements that directly contain the --- a img child element:

 a:has(> img)

For another example, the following selector will only match the p h1 element

 h1:has(+ p)

From my personal understanding, after removing :has() , the remaining selectors are still intact

 a>img

After adding :has() , the first element a can be selected.

Well, the grammar is actually so much, it is estimated that it is not attractive, the key is practical application. Let's take a few examples to feel the powerful charm of pseudo-classes :has

Reminder: Chrome 101+ is required for compatibility, and experimental features are started (105+ is officially supported), Safari 15.4+, Firefox officially says that the experimental features can be supported, but the actual measurement does not (???)

2. Form elements are required

Let's first look at a simple example, there is a form element below, some of which are required

 <form>
  <item>
    <label>用户名</label>
    <input required>
  </item>
  <item>
    <label>备注</label>
    <input>
  </item>
</form>

image-20220903120206213

This is now available via :has with a red asterisk in front of the required fields

 label:has(+input:required)::before{
  content: '*';
  color: red;
}

这个应该还比较好理解, :has + label ,然后::before伪元素。 If it was before, you may need to manually add the class name, or change the writing order of html

image-20220903120438968

You can also visit the full demo online: has+required(runjs.work)

3. Drag and drop the designated area

Sometimes the list needs to have the drag and drop function, but in order to drag and drop the experience without affecting the internal operation of the list, it may be necessary to specify a small area to be dragged, for example

image-20220903122254388

The HTML structure is as follows

 <div class="content">
  <div class="item">列表<span class="thumb"></span></div>
  <div class="item">列表<span class="thumb"></span></div>
  <div class="item">列表<span class="thumb"></span></div>
</div>

Now we hope that the drag handle will appear when hover , and you can drag and drop by pressing and holding the drag handle. It seems very troublesome, but now with the help of :has pseudo-class can be easily implemented, the key CSS is as follows

 .thumb{
  /**/
  opacity: 0
}
.item:hover .thumb{
    opacity: 1;
}
.item:has(.thumb:hover){
    -webkit-user-drag: element;
}

Here :has means that when .thumb is in the :hover state, the element can be selected and dragged, so as to add the draggable attribute to .item as follows

Kapture 2022-09-03 at 12.29.04

You can also visit the full demo online: drag_thumb(runjs.work)

4. Multi-level hover

Let's look at another example. The CSS multi-level hover problem I mentioned four years ago is finally solved~

It is like this, there is a multi-level structure such as

 <div class="box-1">
  <div class="box-2">
    <div class="box-3"></div>
  </div>
</div>

If you add hover style to div 491e6a589c82f0d2de4c08801df8e814---

 div:hover{ 
  outline:4px dashed rebeccapurple
}

The effect is this

Kapture 2022-09-03 at 12.34.58

It can be seen that when hover goes to the inner element, the outer element also triggers the hover style. This is a bit like the bubbling effect in JS 4b1fd96308125e76a2bbd897cbf90c8b---, so how to make hover only trigger the current element? That is to exclude his parent element, yes, :has can solve this problem very well

 div:not(:has(:hover)):hover{ 
  outline:4px dashed rebeccapurple
}

Is it getting more and more round?别急,我们拆解分析一下, div:has(:hover)表示有子元素正hoverdiv ,比如当hoverbox-3时, div:has(:hover)就是除box-3父级, :not ,只选中box-3 itself, understandable? This can be tried more, the actual effect is as follows

Kapture 2022-09-03 at 12.48.10

You can also visit the full demo online: CSS hover(runjs.work)

In some visual drag and drop platforms, it will be very useful in various nested components

5. Star rating components

This function is also very suitable to use :has to achieve, the HTML structure is as follows

 <star>
  <input name="star" type="radio">
  <input name="star" type="radio">
  <input name="star" type="radio">
  <input name="star" type="radio">
  <input name="star" type="radio">
</star>

Just make up

 star{
  display: flex;
}
star [type="radio"]{
  appearance: none;
  width: 40px;
  height: 40px;
  margin: 0;
  cursor: pointer;
  background: #ccc;
  transition: .3s;
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'%3E %3Cpath d='M462.3 62.6C407.5 15.9 326 24.3 275.7 76.2L256 96.5l-19.7-20.3C186.1 24.3 104.5 15.9 49.7 62.6c-62.8 53.6-66.1 149.8-9.9 207.9l193.5 199.8c12.5 12.9 32.8 12.9 45.3 0l193.5-199.8c56.3-58.1 53-154.3-9.8-207.9z'%3E%3C/path%3E %3C/svg%3E") center / 80% no-repeat;
}

The effect is as follows

image-20220903142242324

The following is an interactive function. When :hover or :checked , both the current element and the element before the current element are triggered to be selected.

Previously, since there was only a post-sibling selector ~ , the dom elements had to be reordered and then visually flipped by other means. Now that we have :has , we can say goodbye to these tricks and tricks. The implementation is as follows

 star [type="radio"]:hover,
star [type="radio"]:has(~:hover),
star:not(:hover) [type="radio"]:checked,
star:not(:hover) [type="radio"]:has(~:checked){
  background: orangered;
}

I believe it is not too complicated, [type="radio"]:has(~:hover) means that the element before the current hover element is selected, so the effect of scoring can be easily achieved

Kapture 2022-09-03 at 14.30.31

You can also visit the full demo online: CSS rate(runjs.work)

6. Date range selection

If there are other alternatives to the above examples, or can be achieved with a little JS, then here is a heavyweight case. In the past, even relying on JS would have some troubles, but with :has , everything becomes easier~

Kapture 2022-09-14 at 10.35.11

Suppose the HTML structure is as follows

 <div class="date">
  <span>1</span>
  <span>2</span>
  <span>3</span>
  ...
  <span>30</span>
  <span>31</span>
</div>

This part of the interaction has two parts, one is the mouse over, and the other is the selection.

Let's look at the selected function first. When two elements are selected, the elements between the two elements will be matched. Suppose the selected class name is select

 <div class="date">
  <span>1</span>
  <span>2</span>
  <span class="select">3</span>
  ...
  <span class="select">30</span>
  <span>31</span>
</div>

So, how to make the elements in this area match? The answer is to find the elements before select 2bd16149f5f945fd71cf52049323a7a3--- through :has , and then combine the elements after matching with ~ , the combination of the two can match the elements in the middle. as follows

 .select,
.select~span:has(~.select){
   background-color: blueviolet;
   color: #fff;
}

The effect is as follows

image-20220903144510712

Then there is the effect of hover , assuming one has been selected

 <div class="date">
  <span>1</span>
  <span>2</span>
  <span class="select">3</span>
  ...
  <span>30</span>
  <span>31</span>
</div>

Now when the mouse needs to slide over, match the end point of the mouse with the selected range. This is a little more complicated. We need to consider whether the mouse is before or after the selected element, and use :has Make judgments as follows

 span:hover~span:has(~.select),
.select~span:has(~:hover)
{
  background-color: blueviolet;
  color: #fff;
}

Are you a little dizzy? The first line indicates that the mouse is selected before it matches the current hover after .selelct and before .selelct . hover The previous element, the actual effect is as follows

Kapture 2022-09-03 at 14.36.33

There is another problem. It is necessary to distinguish between two selected and only one selected, because two indicate that the interval selection has been completed. At this time, hover will not have an effect. With the help of :has pseudo class, which can easily distinguish the number of sub-elements, as follows

 .date:not(:has(.select~.select)){
  /*匹配到没有两个.select的父级*/
}

.select~.select .select .select ,也就是.select:has It is possible to distinguish between the two

 .date:not(:has(.select~.select)) .select,
.date:not(:has(.select~.select)) span:hover{
  background-color: transparent;
  color: inherit;
  outline: 2px solid blueviolet;
  outline-offset: -2px;
}

.date:not(:has(.select~.select)) span:hover~span:has(~.select),
.date:not(:has(.select~.select)) .select~span:has(~:hover)
{
  background-color: blueviolet;
  color: #fff;
}

The selection of elements is achieved through JS , at this time JS is completely just a tool person, completely irrelevant to vision, only need to record the selected elements, the logic is extremely simple, as follows

 date.addEventListener('click', ev => {
  const current = date.querySelectorAll('.select');
  if (current.length == 2) {
    current.forEach(el => {
      el.classList.remove('select')
    })
  }
  ev.target.classList.add('select')
})

Then you can get this effect

Kapture 2022-09-14 at 10.35.11

You can also visit the full demo online: CSS date-range(runjs.work)

When the time is right, the date-picker in xy-ui will follow up to use this scheme~

7. Don't wait, learn now

The above are some of the application scenarios that came to my mind at the first time after researching the :has pseudo-classes, such a useful pseudo-class, why don't you learn it?

Of course, its role is much more than that. It can be said that the scenarios that needed to consider the order of the dom in the past can be solved. In the future, the dom will be more semantic. Most of the interactive state pseudo-classes can be well combined, and more than 80% of the interaction The related JS code can be removed, and JS can do what it needs to do with more peace of mind, such as data conversion, business logic, and so on.

After another year, some internal projects of the company can be used boldly. Hey, I already have new ideas. I will share them next time. Finally, if you think it's good and helpful to you, please like, bookmark, and forward ❤❤❤


XboxYan
18.1k 声望14.1k 粉丝