本文将介绍一个不太实用的小技巧,使用 tabindex 配合 :focus-within 巧妙实现父选择器。

CSS 中是否存在父选择器?

这是一个非常经典的问题,到目前为止,CSS 没有真正意义上被广泛实现的父选择器,这和浏览器的渲染机制有关。

如果你对 CSS 中是否存在父选择器有疑惑,可以去看看 知乎 -- CSS 中能否选取父元素?

当然,这不代表 CSS 完全无法通过子元素去控制父元素,通过 :focus-within 伪类可以近似的达到类似的目的。

:focus-within 伪类

首先需要复习一下 :focus-within,它是一个伪类。

它表示一个元素获得焦点,或,该元素的后代元素获得焦点。划重点,它或它的后代获得焦点。

关于 :focus-within,不算太了解的可以先看看这篇文章:《神奇的选择器 :focus-within》

利用它,我们可以实现类似这样的功能,通过元素的子元素的获焦(focus事件),触发该伪元素,从而实现一个狭义的父选择器,类似这样:

CodePen -- CSS focus-within INPUT

:focus-within 伪类实现父选择的缺陷

借助 :focus-within 实现父类选择器最大的问题是,元素必须要有 focus 事件,才能触发它或者它的父元素的 :focus-within

所以,这就导致了在之前我认为 :focus-within 只能配合 <button><input > 元素一起使用。

诸如 <button><input><select><a> 这类可交互元素,默认是存在 focus 事件的,而类似 <div><span> 和 <table> 这类非交互元素,默认是不能被聚焦的。

也是因为这个原因,大大限制了它的使用场景。基于此,我们引入本文的另外一个主角 -- tabindex

使用 tabindex 使元素获得 focus 事件

tabindex: HTML 标签的属性,指示其元素是否可以聚焦,以及它是否/在何处参与顺序键盘导航(通常使用Tab键,因此得名)。

也就是说,一个单纯的 div 标签,他是没有 focus 事件的,然而,我们给它加上一个 tabindex 属性,这个时候他就会获得类似 input 框一样的表现,拥有了 focus 事件,再配合 :focus-within,能够使用的场景就大大提升了。

看看伪代码:

<div class="g-father">
<!-- 没有 focus 事件的 .g-children 元素 -->
<div class="g-children">Click</div>
</div>
<div class="g-father">
<!-- 拥有 focus 事件的 .g-children 元素 -->
<div class="g-children" tabindex="-1">Click</div>
</div>

这里为什么是 tabindex="-1" 呢,tabindex 负值表示元素是可聚焦的,但是不能通过键盘导航来访问到该元素。因为我们只需要让元素能够获得 focus 事件,而不需要他真的能够被键盘导航来访问。

这样,配合 :focus-within,就能做到当点击子元素的时候,去改变父元素的样式了。

并且,我们可以在任意元素上搭配 tabindex,脱离了 <input>, <a>, <button> 等元素才有 focus 事件的束缚。

.g-father:focus-within {
background: #fc0;
}

CodePen -- tabindex 配合 focus-within 实现div的父选择器

一个小细节,button 的 focus 事件在 Safari 和 firefox 的上冒泡问题

由于 input 元素(或者任意元素 +tabindex) 配合 :focus-within 的方案依赖 focus 事件的冒泡。

而对于 <button> 元素,稍微有点特殊,存在这样两个问题,即:

  1. 在 MacOS 的 Safari 和 Firefox 中, **点击 <button> 元素,不会触发 <button> 的 focus 事件,也没有 focus 事件冒泡。
  2. 在 Windows 的 Safari 和 Firefox 中, 点击 <button> 元素,会触发 <button> 的 focus 事件,但在被目标元素捕捉到之后,不会继续向上冒泡。

什么意思呢?我们来验证一下,使用类似这样的结构:

<div class="g-father">
<input type="button" value="Button">
</div>
input:focus {
background: #00bcd4;
} body:focus-within {
background: blue;
} .g-father:focus-within {
background: red;
}

看看,在 Chrome 下的表现:

在 Windows 的 Safari,Firefox 下的表现:

在 MacOS 的 Safari,Firefox 下的表现:

在 Chrome 上的表现是正常,而在 Windows 的 Safari、Firefox 上,会触发 button 的 focus 事件,但不会触发父元素的 :focus-within 事件,也就是上面说的,focus 事件,在被目标元素捕捉到之后,不会继续向上冒泡。而在 Mac 上,则连 focus 都不会触发。

这一点,在使用的时候务必需要留意。

CodePen -- button 的 focus 事件冒泡性验证(Chorme / Safari / Firefox)

最后

当然,本文介绍的小技巧,只能算是一个非常简陋,特定条件(点击目标元素改变父元素样式)下的父选择器,真正意义上的父选择器仍需等待未来规范的实现。

好了,本文到此结束,希望对你有帮助 :)

更多精彩 CSS 技术文章汇总在我的 Github -- iCSS ,持续更新,欢迎点个 star 订阅收藏。

如果还有什么疑问或者建议,可以多多交流,原创文章,文笔有限,才疏学浅,文中若有不正之处,万望告知。

使用 tabindex 配合 focus-within 巧妙实现父选择器的更多相关文章

  1. less学习三---父选择器

    引用父选择器需要用到“&”符号 &运算符表示嵌套规则的父选择器,并且在修改类或伪类选择器的应用中非常普遍 ul{ li{ &:nth-child(2) a { color: r ...

  2. Sass - &引用父选择器

    描述: 您可以使用&字符选择父级选择器. 它告诉父选择器应该插入的位置. 例一:&在前 h3 { font-size: 20px margin-bottom: 10px &.s ...

  3. [Unity3D]巧妙利用父级子级实现Camera场景平面漫游

    本文系作者原创,转载请注明出处 入门级的笔者想了一上午才搞懂那个欧拉角的Camera旋转..=.= 在调试场景的时候,每次都本能的按下W想前进,但是这是不可能的(呵呵) 于是便心血来潮想顺便添加个Ke ...

  4. ligerUI 关闭父弹窗JS报错问题 解决方法

    1:调用父窗口某一个文件框,获取焦点, parent.window.document.getElementById("roleName").focus(); 2:关闭父窗口pare ...

  5. CSS中模拟父元素选择器

    很多情况下,我们需要找到父元素,但可惜的是css中并没有这样的一个选择器. 至于原因可以看张鑫旭的如何在CSS中实现父选择器效果这篇文章. 简单来说这个实现并不是真正的父元素选择器,只是利用其它思路来 ...

  6. jquery基础学习之事件篇(三)

    一.鼠标事件 click 单击 与 dbclick 双击 用于监听用户的点击操作,在同一元素上同时绑定 click 和 dblclick 事件是不可取的...根据浏览器支持不同一个点击事件是由mous ...

  7. Vue 入门之组件化开发

    Vue 入门之组件化开发 组件其实就是一个拥有样式.动画.js 逻辑.HTML 结构的综合块.前端组件化确实让大的前端团队更高效的开发前端项目.而作为前端比较流行的框架之一,Vue 的组件和也做的非常 ...

  8. 《零基础学HTML5+CSS3(全彩版)》读书笔记

    2019年1月31日星期四 1点 <零基础学HTML5+CSS3(全彩版)>开始全面学习 前提: 11月20日开始学Python,可能因为太累了,也可能遇到了瓶颈,进入了一个迷茫期,1月6 ...

  9. 2019.4.18 HTML + CSS相关整理

    目录 标签 块标签 行标签 行块转化 嵌套规则 css引入方式 行间样式 内部引入 外部引入 选择器 基础选择器 组合选择器 盒模型 css样式 字体属性 设置字体的大小 设置字体的粗细 设置字体的风 ...

随机推荐

  1. 转载:Win7系统 利用 pycharm导入Tensorflow失败,出现报错——ImportError:DLL load failed with error code -1073741795的解决方式

    转载自:https://blog.csdn.net/shen123me/article/details/80621103 下面的报错信息困扰了一天,网上的各种方法也都试过了,还是失败,最后自己瞎试,把 ...

  2. @ComponentScan比较

    ComponetScan 定义扫描规则 value:指定要扫描的包 excludeFilters=Filter[] 指定扫描的时候按照什么规则排除哪些组件. includeFilters=Filter ...

  3. git的详细使用,项目创建到同步远程仓库,版本回退,忽略文件,分支创建,分支合并,分支名称修改,冲突解决,项目迁移

    注意:此处省略git的安装 1..git的工作流程示意图: 2.本地仓库的初始化: 2.1 创建一个文件夹,如我创建的是:D:\gitdemo\shop 2.2 进入shop目录,鼠标右键,打开git ...

  4. Vue.js 学习笔记之三:与服务器的数据交互

    显而易见的,之前的02_toDoList存在着一个很致命的缺陷.那就是它的数据只存在于浏览器端,一但用户关闭或重新载入页面,他之前加入到程序中的数据就会全部丢失,一切又恢复到程序的初始状态.要想解决这 ...

  5. requests和正则表达式爬取猫眼电影Top100练习

    1 import requests 2 import re 3 from multiprocessing import Pool 4 from requests.exceptions import R ...

  6. xor 和 or 有什么区别

    参考:https://zhidao.baidu.com/question/67532331.html 1.定义区别: ①OR是或运算,A OR B的结果:当A.B中只要有一个或者两个都为1时,结果为1 ...

  7. 14.深入k8s:kube-proxy ipvs及其源码分析

    转载请声明出处哦~,本篇文章发布于luozhiyun的博客:https://www.luozhiyun.com 源码版本是1.19 这一篇是讲service,但是基础使用以及基本概念由于官方实在是写的 ...

  8. Acticiti流程引擎在已知当前流程定义id的情况下获取当前流程的所有信息(包括:节点和连线)

    这里我们已知流程已经部署,我的需求是获取当前流程的所有任务节点,我使用instanceof关键字来进行匹配 private List<UserTask> getProcessUserTas ...

  9. 【C语言/C++程序员编程】一小时做出来的数字雨(一颗开花的树)!

    相信大家看过许许多多的关于计算机黑客.骇客.人工智能.AI方面的电影,每当黑客入侵某个五角大楼,某个网站时,都会出现这样一副画面: 入侵 或者这样的: 数字雨 然后就轻而易举的成功入侵夺取管理员权限了 ...

  10. 【不知道怎么分类】HDU - 5963 朋友

    题目内容 B君在围观一群男生和一群女生玩游戏,具体来说游戏是这样的: 给出一棵n个节点的树,这棵树的每条边有一个权值,这个权值只可能是0或1. 在一局游戏开始时,会确定一个节点作为根.接下来从女生开始 ...