Skip to content

hover 父对子、子对父、同级之间的控制 ​

  1. hover 父对子
    • 指父元素触发hover事件,并且控制父元素中的子元素做出响应。
      js
          <div class="d1">
            <p class="p1">hello</p>
          </div>
      
          .d1:hover .p1{
            color:#fff
          }
  2. hover 同级之间
    • 控制后续同层级的元素,使用~或者+
    • 用+号控制兄弟元素,但是只能控制一个元素,并且是相邻的后面的兄弟元素
    • 用~号来控制兄弟元素,可以控制后面的所有兄弟元素,不用是相邻的元素
      js
        <div class="d1">
          <p class="p1">hello</p>
        </div>
        <div class="d2">
          <p class="p1">hello</p>
        </div>
      
        .d1:hover + .d2{
          background-color: #fff;
        }
        .d1:hover ~ .d2 .p1{
          color: #fff;
        }
  3. hover 子对父
    • 这里首先要了解:has伪类选择器
      1. :has伪类的语法非常简单,表示满足一定条件后,就会匹配该元素。
        js
            a:has(> img)  //只会匹配直接包含 img 子元素的 a 元素:
            h1:has(+ p)   //只会匹配其后紧跟着 p 元素的 h1 元素
      2. 表单元素必填项
        html
            <form>
              <item>
                <label>用户名</label>
                <input required />
              </item>
              <item>
                <label>备注</label>
                <input />
              </item>
            </form>
            <style>
              label:has(+input:required)::before{  /*可以通过 :has 在必填项的前面加上红色的星号 */
                content: '*';
                color: red;
              } 
            </style>
      3. 拖拽指定区域
        html
            <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>
              <style>
                .thumb{
                  /**/
                  opacity: 0
                }
                .item:hover .thumb{
                    opacity: 1;
                }
                .item:has(.thumb:hover){
                    -webkit-user-drag: element;
                }
              </style>
      4. 多层级 hover
        html
            <div class="box-1">
              <div class="box-2">
                <div class="box-3"></div>
              </div>
            </div>
              <style>
                div:hover{ 
                  outline:4px dashed rebeccapurple  /*会有类似冒泡的效果,hover里层,外层元素也会触发同样的hover*/
                }
        
                div:not(:has(:hover)):hover{ 
                  outline:4px dashed rebeccapurple    /* div:has(:hover) 表示有子元素正处于 hover 的 div ,比如当 hover 到 box-3 时, div:has(:hover) 选中的就是除 box-3 以外的两个父级,然后加上 :not 就刚好反过来,只选中 box-3 本身*/
                }
              </style>
      5. 评星组件
        html
            <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>
        
              <style>
                  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;
                  }
                 /*交互功能,当 :hover 或者 :checked 时,当前元素和当前元素之前的元素都触发选中.在之前,由于只有后置兄弟选择器 ~ ,所以必须要将 dom 元素更改顺序,然后通过其他方式在视觉上再翻转过来。*/
                 /*[type="radio"]:has(~:hover) 表示选中当前 hover 元素之前的元素*/
                  star [type="radio"]:hover, 
                  star [type="radio"]:has(~:hover),
                  star:not(:hover) [type="radio"]:checked,
                  star:not(:hover) [type="radio"]:has(~:checked){
                    background: orangered; 
                  }
        
              </style>
      6. 日期范围选择
        html
          <div class="date">
            <span>1</span>
            <span>2</span>
            <span class="select">3</span>  <!--先看选中的功能,当有两个元素被选中时,这两个元素之间的元素都会匹配上,假设选中的类名是 select-->
            ...
            <span class="select">30</span>
            <span>31</span>
          </div>
        
              <style>
                /*通过 :has 找到 select 之前的元素,再结合 ~ 匹配之后的元素,两者结合就可以匹配到中间的元素了*/
                .select,
                .select~span:has(~.select){
                  background-color: blueviolet;
                  color: #fff;
                }
              /*第一条表示鼠标在已选中之前,匹配当前 hover 之后、 .selelct 之前的元素, 第二条表示已选中之后,匹配 .selelct 之后、 hover 之前的元素*/
              span:hover~span:has(~.select),  
              .select~span:has(~:hover)
              {
                background-color: blueviolet;
                color: #fff;
              }
              /*,需要区分一下选中两个和只选中一个的情况,因为两个表示区间选择已经完成,此时 hover 不会有效果,借助 :has 伪类,可以很轻易的区分子元素的个数*/
              .date:not(:has(.select~.select)){
                  /*匹配到没有两个.select的父级*/
                }
              .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;
              }
        
              /*.select~.select表示选中.select 后面的 .select ,也就是表示至少有两个 .select ,然后通过 :has 就可以区分这两种情况了*/
              .date:not(:has(.select~.select)) span:hover~span:has(~.select),
              .date:not(:has(.select~.select)) .select~span:has(~:hover)
              {
                background-color: blueviolet;
                color: #fff;
              }
              </style>
              <script>
                //元素的选中时通过 JS 实现的,这时候的 JS 完全就只是工具人了,和视觉完全不相干,只需要记录选中的元素
                  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')
                  })
              </script>

一些好用的选择器 ​

  1. :focus-within :自己或者后代元素被聚焦时
  2. ::first-letter :选中第一个字母
  3. ::selection :鼠标选中的文字