神奇的选择器 :focus-within

简介: 神奇的选择器 :focus-within

神奇的选择器 :focus-within


CSS 的伪类选择器和伪元素选择器,让 CSS 有了更为强大的功能。


伪类大家听的多了,伪元素可能听到的不是那么频繁,其实 CSS 对这两个是有区分的。


有个错误有必要每次讲到伪类都提一下,有时你会发现伪类元素使用了两个冒号 (::) 而不是一个冒号 (:),这是 CSS3 规范中的一部分要求,目的是为了区分伪类和伪元素,大多数浏览器都支持下面这两种表示方式。

通常而言,

#id:after{
 ...
}
#id::after{
...
}

合标准而言,单冒号(:)用于 CSS3 伪类,双冒号(::)用于 CSS3 伪元素。

当然,也有例外,对于 CSS2 中已经有的伪元素,例如 :before,单冒号和双冒号的写法 ::before 作用是一样的。

所以,如果你的网站只需要兼容 webkit、firefox、opera 等浏览器或者是移动端页面,建议对于伪元素采用双冒号的写法,如果不得不兼容低版本 IE 浏览器,还是用 CSS2 的单冒号写法比较安全。

 

伪类选择器 :focus-within

言归正传,今天要说的就是:focus-within 伪类选择器。

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

这也就意味着,它或它的后代获得焦点,都可以触发 :focus-within。


:focus-within 的冒泡性

这个属性有点类似 Javascript 的事件冒泡,从可获焦元素开始一直冒泡到根元素 html,都可以接收触发 :focus-within 事件,类似下面这个简单的例子这样:

<div class="g-father">
    <div class="g-children">
        <input type="button" value="Button">
    </div>
</div>
html,
body,
.g-father,
.g-children {
    padding: 30px;
    border:1px solid #999;
}
input {
    ...
    &:focus {
        background: #00bcd4;
    }
}
html:focus-within {
    background: #e91e63;
}
body:focus-within {
    background: #ff5722;
}
.g-father:focus-within {
    background: #ffeb3b;
}
.g-children:focus-within {
    background: #4caf50;
}

就是这样:

43559244-e4f738da-963f-11e8-8c0c-10d9d44bdce4.gif

CodePen Demo -- :focus-within 冒泡触发

这个选择器的存在,让 CSS 有了进一步的让元素持久停留在一种新状态的的能力。

下面几个例子,看看 :focus-within 可以提供什么能力,做些什么事情。

 

感应用户聚焦区域

它或它的后代获得焦点,这一点使得让感知获焦区域变得更大,所以,最常规的用法就是使用 :focus-within 感应用户操作聚焦区域,高亮提醒。

下面的效果没有任何 JS 代码:

43518041-4ea2d312-95bd-11e8-9a62-9b21f5e0f528.gif

这里是什么意思呢?:focus-within 做了什么呢?

  • 我们无须去给获焦的元素设置 :focus 伪类,而是可以给需要的父元素设置,这样当元素获焦时,我可以一并控制它的父元素的样式

核心思想用 CSS 代码表达出来大概是这样:

<div class="g-container">
    <div class="g-username">
        <input type="text" placeholder="user name" class="g_input" >
    </div>
    <div class="g-username">
        <input type="text" placeholder="code" class="g_input" >
    </div>
</div>
.g-container:focus-within {
    ...
    input {
        ....
    }
}

image.png

DEMO -- CSS focus-within INPUT

用上面思想,我们可以把效果做的更炫一点点,在某些场景制作一些增强用户体验的效果:

43517551-b6bfed24-95bb-11e8-8cdd-4db11e7b4e6a.gif

image.png

DEMO -- PURE CSS FOCUS By :focus-within

 

TAB导航切换

在之前的一篇文章里,介绍了两种纯 CSS 实现的 TAB 导航栏切换方法:

纯CSS的导航栏Tab切换方案

现在又多了一种方式,利用了 :focus-within 可以在父节点获取元素获得焦点的特性,实现的TAB导航切换:

43519376-c5dcb9e4-95c1-11e8-84ea-f1bfbb69e04e.gif

image.png

DEMO -- focus-within switch tab

主要的思路就是通过获焦态来控制其他选择器,以及最重要的是利用了父级的 :not(:focus-within) 来设置默认样式:

.nav-box:not(:focus-within) {
    // 默认样式
}
.nav-A:focus-within ~ .content-box .content-A {
    display: block;
}
.nav-B:focus-within ~ .content-box .content-B {
    display: block;
}


合 :placeholder-shown 伪类实现表单效果

:focus-within 一个人能力有限,通常也会配合其他伪类实现一些不错的效果。这里要再简单介绍的是另外一个有意思的伪类 :placeholder-shown。

:placeholder-shown:The :placeholder-shown CSS pseudo-class represents any or  element that is currently displaying placeholder text.</div><div><span>另外,划重点,这个伪类是仍处于实验室的方案。也就是未纳入标准,当然我们的目的是探寻有意思的 CSS 。</span></div></blockquote><div style="text-align: left; background-color: #F5F5F5;"><span>意思大概就是,当 <code>input</code> 类型标签使用了 placeholder 属性有了默认占位的文字,会触发此伪类样式。配合<code>:not()</code>伪类,可以再改变当默认文字消失后的样式,再配合本文的主角,我们可以实现表单的一系列效果。</span></div><div style="text-align: left; background-color: #F5F5F5;"><span>CSS 代码大概呈现成这样:</span></div><div data-card-type="block" data-ready-card="codeblock" data-card-value="data:%7B%22mode%22%3A%22plain%22%2C%22code%22%3A%22.g-container%20%7B%5Cn%20%20%20%20width%3A%20500px%3B%5Cn%20%20%20%20height%3A%2060px%3B%5Cn%20%5Cn%20%20%20%20input%20%7B%5Cn%20%20%20%20%20%20%20%20height%3A%20100%25%3B%5Cn%20%20%20%20%20%20%20%20width%3A%20100%25%3B%5Cn%20%5Cn%20%20%20%20%20%20%20%20%26%3Anot(%3Aplaceholder-shown)%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20%20%20...%5Cn%20%20%20%20%20%20%20%20%7D%5Cn%20%5Cn%20%20%20%20%20%20%20%20%26%3Aplaceholder-shown%20%7B%5Cn%20%20%20%20%20%20%20%20%20%20%20%20...%5Cn%20%20%20%20%20%20%20%20%7D%5Cn%20%20%20%20%7D%5Cn%20%5Cn%20%20%20%20%26%3Afocus-within%20%7B%5Cn%20%20%20%20%20%20%20%20...%5Cn%20%20%20%20%7D%5Cn%7D%22%2C%22heightLimit%22%3Atrue%2C%22margin%22%3Atrue%2C%22id%22%3A%22jScAT%22%7D"></div><div><span style="color: #000000; background-color: #F5F5F5;">实际效果如下:</span></div><div><span style="color: #000000; background-color: #F5F5F5;"><span data-card-type="inline" data-ready-card="image" data-card-value="data:%7B%22src%22%3A%22https%3A%2F%2Fucc.alicdn.com%2Fpic%2Fdeveloper-ecology%2Feed4b0c3c51540dcb7fceb9d9d709164.png%22%2C%22originWidth%22%3A741%2C%22originHeight%22%3A106%2C%22name%22%3A%22image.png%22%2C%22size%22%3A41346%2C%22display%22%3A%22inline%22%2C%22align%22%3A%22left%22%2C%22linkTarget%22%3A%22_blank%22%2C%22status%22%3A%22done%22%2C%22style%22%3A%22none%22%2C%22search%22%3A%22%22%2C%22margin%22%3A%7B%22top%22%3Atrue%2C%22bottom%22%3Atrue%7D%2C%22width%22%3A741%2C%22height%22%3A106%7D"></span></span></div><div style="text-align: left; background-color: #F5F5F5;"><span>可以看到,上面的效果没有用到任何 JS,可以实现:</span></div><ol style="text-align: left; background-color: #F5F5F5;"><li><span>整个 input(包括父元素所在区域)获焦与非获焦样式控制</span></li><li><span>placeholder 属性设置的文字出现与消失后样式控制</span></li></ol><div><span><span data-card-type="inline" data-ready-card="image" data-card-value="data:%7B%22src%22%3A%22https%3A%2F%2Fucc.alicdn.com%2Fpic%2Fdeveloper-ecology%2Ff3d1bcf129014baa949b8f2fe3535cf2.png%22%2C%22originWidth%22%3A403%2C%22originHeight%22%3A333%2C%22name%22%3A%22image.png%22%2C%22size%22%3A20457%2C%22display%22%3A%22inline%22%2C%22align%22%3A%22left%22%2C%22linkTarget%22%3A%22_blank%22%2C%22status%22%3A%22done%22%2C%22style%22%3A%22none%22%2C%22search%22%3A%22%22%2C%22margin%22%3A%7B%22top%22%3Atrue%2C%22bottom%22%3Atrue%7D%2C%22width%22%3A403%2C%22height%22%3A333%7D"></span></span></div><div style="text-align: left; background-color: #F5F5F5;"><span><a href="https://codepen.io/Chokcoco/pen/xJWwyB" target="_blank">CodePen Demo -- :placeholder-shown && :focus-within</a></span></div><div style="text-align: left; background-color: #F5F5F5;"><span class="lake-fontsize-9"> </span></div><h2 id="koePo" style="text-align: left; background-color: #F5F5F5;"><span class="lake-fontsize-18">实现离屏导航</span></h2><div style="text-align: left; background-color: #F5F5F5;"><span>这个是其他很多文章都有提到过的一个功能,利用 <code>focus-within</code> 便捷的实现离屏导航,可以说将这个属性的功能发挥的淋漓尽致,这里我直接贴一个 codepen 上 <a href="https://codepen.io/dannievinther/" target="_blank">Dannie Vinther</a> 对这个效果的实现方案:</span></div><div style="text-align: left; background-color: #F5F5F5;"><span><span data-card-type="inline" data-ready-card="image" data-card-value="data:%7B%22src%22%3A%22https%3A%2F%2Fucc.alicdn.com%2Fpic%2Fdeveloper-ecology%2Fa76cb58a97b24ed6a1530d70ff2fce30.png%22%2C%22originWidth%22%3A747%2C%22originHeight%22%3A361%2C%22name%22%3A%22image.png%22%2C%22size%22%3A426102%2C%22display%22%3A%22inline%22%2C%22align%22%3A%22left%22%2C%22linkTarget%22%3A%22_blank%22%2C%22status%22%3A%22done%22%2C%22style%22%3A%22none%22%2C%22search%22%3A%22%22%2C%22margin%22%3A%7B%22top%22%3Atrue%2C%22bottom%22%3Atrue%7D%2C%22width%22%3A747%2C%22height%22%3A361%7D"></span></span></div><div style="text-align: left; background-color: #F5F5F5;"><span><a href="https://codepen.io/dannievinther/pen/NvZjvz" target="_blank">CodePen Demo -- Off-screen nav with :focus-within [PURE CSS]</a></span></div><div style="text-align: left; background-color: #F5F5F5;"><span class="lake-fontsize-9"> </span></div><h2 id="QfMto" style="text-align: left; background-color: #F5F5F5;"><span class="lake-fontsize-18">实现掘金登录动效切换</span></h2><div style="text-align: left; background-color: #F5F5F5;"><span><a href="http://juejin.im/" target="_blank">juejin.im</a>是我很喜欢的一个博客网站,它的登录有一个小彩蛋,最上面的熊猫在你输入帐号密码的时候会有不同的状态,效果如下:</span></div><div style="text-align: left; background-color: #F5F5F5;"><span><span data-card-type="inline" data-ready-card="image" data-card-value="data:%7B%22src%22%3A%22https%3A%2F%2Fucc.alicdn.com%2Fpic%2Fdeveloper-ecology%2F54d9b9e699be48baba7d8309469cf930.png%22%2C%22originWidth%22%3A397%2C%22originHeight%22%3A570%2C%22name%22%3A%22image.png%22%2C%22size%22%3A135317%2C%22display%22%3A%22inline%22%2C%22align%22%3A%22left%22%2C%22linkTarget%22%3A%22_blank%22%2C%22status%22%3A%22done%22%2C%22style%22%3A%22none%22%2C%22search%22%3A%22%22%2C%22margin%22%3A%7B%22top%22%3Atrue%2C%22bottom%22%3Atrue%7D%2C%22width%22%3A397%2C%22height%22%3A570%7D"></span></span></div><div style="text-align: left; background-color: #F5F5F5;"><span style="color: #000000; background-color: #F5F5F5;">利用本文所讲的 </span><code>focus-within</code><span style="color: #000000; background-color: #F5F5F5;"> ,可以不借助任何 Javascript,实现这个动效:</span></div><div style="text-align: left; background-color: #F5F5F5;"><span style="color: #000000; background-color: #F5F5F5;"><span data-card-type="inline" data-ready-card="image" data-card-value="data:%7B%22src%22%3A%22https%3A%2F%2Fucc.alicdn.com%2Fpic%2Fdeveloper-ecology%2Fe038e9f8174e413988169f381c31868d.png%22%2C%22originWidth%22%3A407%2C%22originHeight%22%3A581%2C%22name%22%3A%22image.png%22%2C%22size%22%3A155829%2C%22display%22%3A%22inline%22%2C%22align%22%3A%22left%22%2C%22linkTarget%22%3A%22_blank%22%2C%22status%22%3A%22done%22%2C%22style%22%3A%22none%22%2C%22search%22%3A%22%22%2C%22margin%22%3A%7B%22top%22%3Atrue%2C%22bottom%22%3Atrue%7D%2C%22width%22%3A407%2C%22height%22%3A581%7D"></span></span></div><div style="text-align: left; background-color: #F5F5F5;"><span style="color: #000000; background-color: #F5F5F5;">感兴趣的可以戳这里看看完整的Demo代码:</span></div><div style="text-align: left; background-color: #F5F5F5;"><span style="color: #000000; background-color: #F5F5F5;"><span data-card-type="inline" data-ready-card="image" data-card-value="data:%7B%22src%22%3A%22https%3A%2F%2Fucc.alicdn.com%2Fpic%2Fdeveloper-ecology%2F8385fd322c2e4dd79e7ec862fb5ea39f.png%22%2C%22originWidth%22%3A401%2C%22originHeight%22%3A329%2C%22name%22%3A%22image.png%22%2C%22size%22%3A24399%2C%22display%22%3A%22inline%22%2C%22align%22%3A%22left%22%2C%22linkTarget%22%3A%22_blank%22%2C%22status%22%3A%22done%22%2C%22style%22%3A%22none%22%2C%22search%22%3A%22%22%2C%22margin%22%3A%7B%22top%22%3Atrue%2C%22bottom%22%3Atrue%7D%2C%22width%22%3A401%2C%22height%22%3A329%7D"></span></span></div><div style="text-align: left; background-color: #F5F5F5;"><span><a href="https://codepen.io/Chokcoco/pen/yqKrPR?editors=1100" target="_blank">CodePen Demo -- 掘金登录效果纯CSS实现</a></span></div><div style="text-align: left; background-color: #F5F5F5;"><span class="lake-fontsize-9"> </span></div><h2 id="Wo6AZ" style="text-align: left; background-color: #F5F5F5;"><span class="lake-fontsize-18">兼容性</span></h2><div style="text-align: left; background-color: #F5F5F5;"><span>好了,例子举例的也差不多了,下面到了杀人诛心的兼容性时刻,按照惯例,这种属性大概率是一片红色,看看 CANIUSE,截图日期(2018/08/02),其实也还不算特别惨淡。</span></div><div style="text-align: left; background-color: #F5F5F5;"><span><span data-card-type="inline" data-ready-card="image" data-card-value="data:%7B%22src%22%3A%22https%3A%2F%2Fucc.alicdn.com%2Fpic%2Fdeveloper-ecology%2Fff6c0ebc993e48028780a3dabab9ce4e.png%22%2C%22originWidth%22%3A749%2C%22originHeight%22%3A316%2C%22name%22%3A%22image.png%22%2C%22size%22%3A59214%2C%22display%22%3A%22inline%22%2C%22align%22%3A%22left%22%2C%22linkTarget%22%3A%22_blank%22%2C%22status%22%3A%22done%22%2C%22style%22%3A%22none%22%2C%22search%22%3A%22%22%2C%22margin%22%3A%7B%22top%22%3Atrue%2C%22bottom%22%3Atrue%7D%2C%22width%22%3A749%2C%22height%22%3A316%7D"></span></span></div><h2 id="ng27L" style="text-align: left; background-color: #F5F5F5;"><span class="lake-fontsize-18">最后</span></h2><div style="text-align: left; background-color: #F5F5F5;"><span>感谢耐心读完。本文只是抛砖引玉,期待发掘 <code>focus-within</code> 更多有意义的用法。</span></div><div style="text-align: left; background-color: #F5F5F5;"><span>更多精彩 CSS 技术文章汇总在我的 <a href="https://github.com/chokcoco/iCSS" target="_blank">Github -- iCSS</a> ,持续更新,欢迎点个 star 订阅收藏。</span></div><div style="text-align: left; background-color: #F5F5F5;"><span>好了,本文到此结束,希望对你有帮助 :)</span></div><div style="text-align: left; background-color: #F5F5F5;"><span>如果还有什么疑问或者建议,可以多多交流,原创文章,文笔有限,才疏学浅,文中若有不正之处,万望告知。</span></div><div style="text-align: left; background-color: #F5F5F5;"> </div>

目录
相关文章
|
6月前
|
JavaScript
jQuery :nth-of-type(n)选择器的用法详解
jQuery中,:nth-of-type(n)选择器可以对selector选择器匹配选择到的所有HTML元素进行二次匹配选择,为了更好地阐述:nth-of-type(n)的语法,这里假设selector是一个元素p选择器,如此,:nth-of-type(n)可以用于匹配p元素选择器选择到的p元素指向的父元素中第n个类型为p的子元素,而且与p是否是该父元素的第n个子元素无关,比如
57 5
|
6月前
element-Cascader级联选择器用法?
element-Cascader级联选择器用法?
|
数据格式
Element el-cascader 级联选择器详解
本文目录 1. 概述 2. 数据绑定 2.1 默认数据绑定 2.2 指定绑定数据格式 3. 常用功能 3.1 修改触发方式 3.2 增加清空按钮 3.3 可搜索 3.4 选中项只显示最后一级 3.5 可选中任意一级 3.6 面板样式 3.7 自定义节点内容 4. 动态加载下级 5. 小结
3384 0
|
前端开发
css样式的优先级+ 伪类选择器:hover+选择器
css样式的优先级+ 伪类选择器:hover+选择器
116 0
|
Web App开发 前端开发 JavaScript
神奇的选择器 :focus-within
神奇的选择器 :focus-within
145 0
|
前端开发 JavaScript
【CSS 选择器世界】 :focus-within 实现无障碍访问的输入框
focus-within 实现无障碍访问的输入框
161 0
【CSS 选择器世界】 :focus-within 实现无障碍访问的输入框
|
前端开发 程序员
【CSS 选择器世界】 自定义单选框
【CSS 选择器世界】 自定义单选框
199 0
【CSS 选择器世界】 自定义单选框
|
机器学习/深度学习 前端开发 JavaScript
|
JavaScript
jQuery常用选择器【标签选择器】【id选择器】【class选择器】【集合选择器】
jQuery常用选择器【标签选择器】【id选择器】【class选择器】【集合选择器】
170 0
jQuery常用选择器【标签选择器】【id选择器】【class选择器】【集合选择器】
Stylus - 选择器(Selectors)
Stylus - 选择器(Selectors)
140 0