使用 tabindex 配合 focus-within 巧妙实现父选择器
本文将介绍一个不太实用的小技巧,使用 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>
元素,稍微有点特殊,存在这样两个问题,即:
- 在 MacOS 的 Safari 和 Firefox 中, **点击
<button>
元素,不会触发<button>
的 focus 事件,也没有 focus 事件冒泡。 - 在 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 巧妙实现父选择器的更多相关文章
- less学习三---父选择器
引用父选择器需要用到“&”符号 &运算符表示嵌套规则的父选择器,并且在修改类或伪类选择器的应用中非常普遍 ul{ li{ &:nth-child(2) a { color: r ...
- Sass - &引用父选择器
描述: 您可以使用&字符选择父级选择器. 它告诉父选择器应该插入的位置. 例一:&在前 h3 { font-size: 20px margin-bottom: 10px &.s ...
- [Unity3D]巧妙利用父级子级实现Camera场景平面漫游
本文系作者原创,转载请注明出处 入门级的笔者想了一上午才搞懂那个欧拉角的Camera旋转..=.= 在调试场景的时候,每次都本能的按下W想前进,但是这是不可能的(呵呵) 于是便心血来潮想顺便添加个Ke ...
- ligerUI 关闭父弹窗JS报错问题 解决方法
1:调用父窗口某一个文件框,获取焦点, parent.window.document.getElementById("roleName").focus(); 2:关闭父窗口pare ...
- CSS中模拟父元素选择器
很多情况下,我们需要找到父元素,但可惜的是css中并没有这样的一个选择器. 至于原因可以看张鑫旭的如何在CSS中实现父选择器效果这篇文章. 简单来说这个实现并不是真正的父元素选择器,只是利用其它思路来 ...
- jquery基础学习之事件篇(三)
一.鼠标事件 click 单击 与 dbclick 双击 用于监听用户的点击操作,在同一元素上同时绑定 click 和 dblclick 事件是不可取的...根据浏览器支持不同一个点击事件是由mous ...
- Vue 入门之组件化开发
Vue 入门之组件化开发 组件其实就是一个拥有样式.动画.js 逻辑.HTML 结构的综合块.前端组件化确实让大的前端团队更高效的开发前端项目.而作为前端比较流行的框架之一,Vue 的组件和也做的非常 ...
- 《零基础学HTML5+CSS3(全彩版)》读书笔记
2019年1月31日星期四 1点 <零基础学HTML5+CSS3(全彩版)>开始全面学习 前提: 11月20日开始学Python,可能因为太累了,也可能遇到了瓶颈,进入了一个迷茫期,1月6 ...
- 2019.4.18 HTML + CSS相关整理
目录 标签 块标签 行标签 行块转化 嵌套规则 css引入方式 行间样式 内部引入 外部引入 选择器 基础选择器 组合选择器 盒模型 css样式 字体属性 设置字体的大小 设置字体的粗细 设置字体的风 ...
随机推荐
- Lua设计与实现--读书笔记
目录 lua简介 一种通用的数据类型:lua_TValue 字符串 Table lua实现一个队列 lua简介 C++底层核心模块,暴露核心接口给lua脚本层,网络的收发都在c++层完成,本书简述lu ...
- springmvc 源码分析(二)-- DiapartcherServlet核心调用流程分析
测试环境搭建: 本次搭建是基于springboot来实现的,代码在码云的链接:https://gitee.com/yangxioahui/thymeleaf.git 项目结构代码如下: 一: cont ...
- Python 3 入门,看这篇就够了(超全整理)
史上最全Python资料汇总(长期更新).隔壁小孩都馋哭了 --- 点击领取 今天和大家分享的内容是Python入门干货,文章很长. 简介 Python 是一种高层次的结合了解释性.编译性.互动性和面 ...
- Azure Cosmos DB (二) SQL API 操作
一,引言 还记得国庆期间,我们学习了一下关于Azure Cosmos DB 的一些基础知识以及Azure Cosmos DB 的几种支持数据库类型.今天就开始分享一些实战操作,如何通过Azure Po ...
- PHP的学习(提前学习了,业余爱好) (一)
一个函数一个函数地堆 strstr()函数 在本地测试的时候,代码与显示如下 1.代码: <?php echo strstr("I love Shanghai!123",&q ...
- shell-脚本的执行
1. shell脚本的执行 当shell脚本以非交互的方式运行时,它会先查找环境变量ENV,该变量指定了一个环境文件(通常是.bashrc),然后从该环境变量文件开始执行,当读取了ENV文件后,she ...
- bufferedReader 读取文件第一行第一个字符丢失问题
在做一个解析pacp文件的时候需要读取文件中的每个属性,但是每次读出来的内容的每一行的第一个字符都被吞掉了,找了半天不知道为什么,后来看到在读取的时候用的read()方法,而且返回值是int类型,在变 ...
- 多测师讲解接口测试 _面试题003_高级讲师肖sir
接口测试 一.你对HTTP有没有了解过?具体讲一下对http的了解.(答题思路: 定义.常见请求类型.状态码.请求头请求体.响应头和响应体.三次握手和四次挥手.)答:了解,我们做接口的时候基本上都是基 ...
- 资源管理神器Clover
开开心心地上班,这时你得打开我的电脑,点进D盘,打开某个项目;然后还得打开XX文档,还有.... 最后的最后,你的桌面便成了这个样子 每天你都得天打开多个文件夹,切换时找文件找的晕头转向而烦恼. 每天 ...
- pytest文档49-命令行参数--tb的使用
前言 pytest 使用命令行执行用例的时候,有些用例执行失败的时候,屏幕上会出现一大堆的报错内容,不方便快速查看是哪些用例失败. --tb=style 参数可以设置报错的时候回溯打印内容,可以设置参 ...