作者: 晴栀Sunset
- 良辰难再,人生中大好时刻,不要再去旧梦重圆。
公众号链接:神奇的focus-within
神奇的伪类选择器focus-within
:focus-within
是一个CSS 伪类 ,表示一个元素获得焦点,或,该元素的后代元素获得焦点。换句话说,元素自身或者它的某个后代匹配 :focus 伪类。(shadow DOM 树中的后代也包括在内)
该选择器非常实用。举个通俗的例子:表单中的某个
<input>
字段获得焦点时,整个表单的<form>
元素都可被高亮。
:focus-within 的冒泡性
这个属性有点类似 Javascript 的事件冒泡,从可获焦元素开始一直冒泡到根元素 html,都可以接收触发
:focus-within
事件,
举个例子
HTML
<p>试试在这个表单中输入点什么。</p>
<form>
<label for="given_name">Given Name:</label>
<input id="given_name" type="text">
<br>
<label for="family_name">Family Name:</label>
<input id="family_name" type="text">
</form>
CSS
form {
border: 1px solid;
color: gray;
padding: 4px;
}
form:focus-within {
background: #ff8;
color: black;
}
input {
margin: 4px;
}
输入未框聚焦
输入框聚焦
冒泡案例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>focus-within</title>
<style>
html,
body,
.g-father,
.g-children {
padding: 30px;
border: 1px solid #999;
}
input {
display: block;
border: none;
outline: none;
background: none;
border: 1px solid #333;
cursor: pointer;
margin: 0 auto;
}
input:focus {
background: #00bcd4;
}
html:focus-within {
background: #ddd;
}
body:focus-within {
background: #ff5722;
}
.g-father:focus-within {
background: #ffeb3b;
}
.g-children:focus-within {
background: #4caf50;
}
/* 以下是修改文字样式 */
.g-html,
.g-body,
.g-fath,
.g-chil {
position: fixed;
}
.g-html {
left: 30px;
top: 10px;
}
.g-body {
left: 60px;
top: 40px;
}
.g-fath {
top: 70px;
left: 90px;
}
.g-chil {
top: 100px;
left: 120px;
}
</style>
</head>
<body>
<div class="g-father">
<div class="g-children">
<input type="button" value="Button">
</div>
</div>
<!-- 四个角文字 -->
<div class="g-html">HTML</div>
<div class="g-body">BODY</div>
<div class="g-fath">Father</div>
<div class="g-chil">Children</div>
</body>
</html>
感知用户的点击事件
案例一
它或它的后代获得焦点,这一点使得让感知获焦区域变得更大,所以,最常规的用法就是使用
:focus-within
感应用户操作聚焦区域,高亮提醒。
我们无须去给获焦的元素设置 :focus 伪类,而是可以给需要的父元素设置,这样当元素获焦时,我可以一并控制它的父元素的样式
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>focus-within</title>
<style>
* {
font-family: "Work Sans", sans-serif;
box-sizing: border-box;
}
html,
body {
display: flex;
width: 100%;
height: 100%;
align-items: center;
justify-content: center;
flex-direction: column;
}
.g-container {
padding: 10px;
border: 1px solid #eee;
transition: all .3s;
}
.g-username {
padding: 15px;
transition: 0.3s;
}
.g_input {
border: none;
outline: none;
width: 20vw;
padding: 15px;
font-size: 18px;
box-sizing: border-box;
border: 1px solid #ddd;
overflow: hidden;
transition: 0.3s;
}
.g_input:focus {
border-color: hsl(199, 98%, 48%);
}
p {
display: none;
text-indent: 0px;
color: red;
padding: 10px 0;
}
/* 聚焦改变父类元素 */
.g-container:focus-within {
transform: translateY(-4px);
/* background: hsla(199, 98%, 48%, .2); */
box-shadow: 0 0 10px #ddd;
border-color: hsl(199, 98%, 48%);
}
</style>
</head>
<body>
<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>
</body>
</html>
案例二
运用上面思想,我们可以把效果做的更炫一点点,在某些场景制作一些增强用户体验的效果:
边框阴影可以移步:CSS边框动画: https://t.1yb.co/fKm8
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>focus-within</title>
<style>
.g-container {
width: 300px;
margin: 50px auto;
}
p {
line-height: 1.4;
padding-left: 40px;
}
input {
position: absolute;
border: none;
outline: none;
background: none;
width: 20px;
height: 20px;
border-radius: 50%;
border: 1px solid #aaa;
box-sizing: border-box;
top: 50%;
left: 10px;
transform: translate(0, -50%);
cursor: pointer;
}
.g-section {
position: relative;
padding: 10px;
box-sizing: border-box;
border: 1px solid transparent;
}
.g-section:focus-within {
background: linear-gradient(90deg, #03a9f4 50%, transparent 0) repeat-x, linear-gradient(90deg, #03a9f4 50%, transparent 0) repeat-x, linear-gradient(0deg, #03a9f4 50%, transparent 0) repeat-y, linear-gradient(0deg, #03a9f4 50%, transparent 0) repeat-y;
background-size: 8px 1px, 8px 1px, 1px 8px, 1px 8px;
background-position: 0 0, 0 100%, 0 0, 100% 0;
animation: linearGradientMove .5s infinite linear;
}
input:focus-within {
background: #03a9f4;
}
@keyframes linearGradientMove {
100% {
background-position: 6% 0, -6% 100%, 0 -6%, 100% 6%;
}
}
</style>
</head>
<body>
<div class="g-container">
<div class="g-section">
<input type="button">
<p>
:focus-within 是一个CSS 伪类 ,表示一个元素获得焦点,或,该元素的后代元素获得焦点。换句话说,元素自身或者它的某个后代匹配:focus伪类。
</p>
</div>
<div class="g-section">
<input type="button">
<p>
:focus-within 是一个CSS 伪类 ,表示一个元素获得焦点,或,该元素的后代元素获得焦点。换句话说,元素自身或者它的某个后代匹配:focus伪类。
</p>
</div>
<div class="g-section">
<input type="button">
<p>
:focus-within 是一个CSS 伪类 ,表示一个元素获得焦点,或,该元素的后代元素获得焦点。换句话说,元素自身或者它的某个后代匹配:focus伪类。
</p>
</div>
</div>
</body>
</html>
配合 :placeholder-shown 伪类实现表单效果
:placeholder-shown
CSS 伪类 在·<input>
或<textarea>
元素显示 placeholder text 时生效.
超出文本
在分辨率较小的设备上, 输入框或者其他表单控件可能会变的很窄. 这个选择器可以使得占位符文本缩短. 这个选择器经常和·text-overflow
一起使用.
html
<input placeholder="Enter something into this field, if you please!">
css
input:placeholder-shown {
text-overflow: ellipsis;
}
兼容性
案例
简单来说,当
input
类型标签使用了placeholder
属性有了默认占位的文字,会触发此伪类样式。配合:not()伪类
,可以再改变当默认文字消失后的样式,再配合本文的主角,我们可以实现表单的一系列效果。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>placeholder-shown</title>
<style>
.g-container {
position: relative;
margin: 100px auto;
display: flex;
flex-wrap: wrap;
width: 500px;
height: 60px;
overflow: hidden;
transition: 0.3s;
}
.g-container>* {
border: none;
outline: none;
}
.g_input_search {
padding: 0 15px;
height: 100%;
width: 100%;
border: 1px solid #ddd;
font-size: 18px;
box-sizing: border-box;
}
/* 控制按钮显示,失去placeholder-shown */
.g_input_search:not(:placeholder-shown)+.g_button_search {
border: 1px solid #03a9f4;
opacity: 1;
}
/* 控制按钮隐藏 ,placeholder-shown */
.g_input_search:placeholder-shown+.g_button_search {
opacity: 0;
}
.g_button_search {}
.g_button_search {
background: #03a9f4;
color: #feffd4;
font-size: 15px;
cursor: pointer;
width: 100px;
height: calc(100% - 20px);
transition: 0.3s;
position: absolute;
right: 10px;
top: 10px;
}
/* 控制整个盒子阴影 */
.g-container:focus-within {
transform: translateY(-4px);
border-color: #bbb;
box-shadow: 4px 4px 10px 2px #ddd;
}
</style>
</head>
<body>
<div class="g-container">
<input type="text" placeholder="输入你想查询的内容" class="g_input_search">
<button type="button" class="g_button_search">GO</button>
</div>
</body>
</html>
综合案例导航
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
@import url('https://fonts.googleapis.com/css?family=Encode+Sans+Condensed:400,600');
* {
outline: none;
}
strong {
font-weight: 600;
}
.page {
width: 100%;
height: 100vh;
background: #fdfdfd;
font-family: 'Encode Sans Condensed', sans-serif;
font-weight: 600;
letter-spacing: .03em;
color: #212121;
}
header {
display: flex;
position: fixed;
width: 100%;
height: 70px;
background: #212121;
color: #fff;
justify-content: center;
align-items: center;
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
}
main {
padding: 70px 20px 0;
display: flex;
flex-direction: column;
height: 100%;
}
main>div {
margin: auto;
max-width: 600px;
}
main h2 span {
color: #BF7497;
}
main p {
line-height: 1.5;
font-weight: 200;
margin: 20px 0;
}
main small {
font-weight: 300;
color: #888;
}
#nav-container {
position: fixed;
height: 100vh;
width: 100%;
pointer-events: none;
}
#nav-container .bg {
position: absolute;
top: 70px;
left: 0;
width: 100%;
height: calc(100% - 70px);
visibility: hidden;
opacity: 0;
transition: .3s;
background: #000;
}
#nav-container:focus-within .bg {
visibility: visible;
opacity: .6;
}
#nav-container * {
visibility: visible;
}
.button {
position: relative;
display: flex;
flex-direction: column;
justify-content: center;
z-index: 1;
-webkit-appearance: none;
border: 0;
background: transparent;
border-radius: 0;
height: 70px;
width: 30px;
cursor: pointer;
pointer-events: auto;
margin-left: 25px;
touch-action: manipulation;
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
}
.icon-bar {
display: block;
width: 100%;
height: 3px;
background: #aaa;
transition: .3s;
}
.icon-bar+.icon-bar {
margin-top: 5px;
}
#nav-container:focus-within .button {
pointer-events: none;
}
#nav-container:focus-within .icon-bar:nth-of-type(1) {
transform: translate3d(0, 8px, 0) rotate(45deg);
}
#nav-container:focus-within .icon-bar:nth-of-type(2) {
opacity: 0;
}
#nav-container:focus-within .icon-bar:nth-of-type(3) {
transform: translate3d(0, -8px, 0) rotate(-45deg);
}
#nav-content {
margin-top: 70px;
padding: 20px;
width: 90%;
max-width: 300px;
position: absolute;
top: 0;
left: 0;
height: calc(100% - 70px);
background: #ececec;
pointer-events: auto;
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
transform: translateX(-100%);
transition: transform .3s;
will-change: transform;
contain: paint;
}
#nav-content ul {
height: 100%;
display: flex;
flex-direction: column;
}
#nav-content li a {
padding: 10px 5px;
display: block;
text-transform: uppercase;
transition: color .1s;
}
#nav-content li a:hover {
color: #BF7497;
}
#nav-content li:not(.small)+.small {
margin-top: auto;
}
.small {
display: flex;
align-self: center;
}
.small a {
font-size: 12px;
font-weight: 400;
color: #888;
}
.small a+a {
margin-left: 15px;
}
#nav-container:focus-within #nav-content {
transform: none;
}
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
html,
body {
height: 100%;
}
a,
a:visited,
a:focus,
a:active,
a:link {
text-decoration: none;
outline: 0;
}
a {
color: currentColor;
transition: .2s ease-in-out;
}
h1,
h2,
h3,
h4 {
margin: 0;
}
ul {
padding: 0;
list-style: none;
}
img {
vertical-align: middle;
height: auto;
width: 100%;
}
</style>
</head>
<body>
<div class="page">
<!-- 使用tabindex 使div成为可聚焦状态 -->
<header tabindex="0">Header</header>
<div id="nav-container">
<div class="bg"></div>
<div class="button" tabindex="0">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</div>
<div id="nav-content" tabindex="0">
<ul>
<li><a href="#0">Home</a></li>
<li><a href="#0">Services</a></li>
<li><a href="#0">Blog</a></li>
<li><a href="#0">About</a></li>
<li><a href="#0">Contact</a></li>
<li class="small"><a href="#0">Facebook</a><a href="#0">Instagram</a></li>
</ul>
</div>
</div>
<main>
<div class="content">
<h2>Off-screen navigation using <span>:focus-within</span></h2>
<p>Adding yet another pure CSS technique to the list of off-screen navigation by "hacking" the :focus-within pseudo-class. Have a look at the code to see how it works.</p>
<small><strong>NB!</strong> Use a browser that supports :focus-within</small>
</div>
</main>
</div>
</body>
</html>
如何使div聚焦
tabindex
tabindex
全局属性指示其元素是否可以聚焦
,以及它是否/在何处参与顺序键盘导航(通常使用Tab键,因此得名)。
它接受一个整数作为值,具有不同的结果,具体取决于整数的值:
tabindex=负值 (通常是tabindex=“-1”),
表示元素是可聚焦
的,但是不能通过键盘导航来访问到该元素,用JS做页面小组件内部键盘导航的时候非常有用。- tabindex=“0” ,表示元素是可聚焦的,并且可以通过键盘导航来聚焦到该元素,它的相对顺序是当前处于的DOM结构来决定的。
tabindex=正值
,表示元素是可聚焦的
,并且可以通过键盘导航来访问到该元素
;它的相对顺序按照tabindex 的数值递增而滞后获焦。如果多个元素拥有相同的 tabindex,它们的相对顺序按照他们在当前DOM中的先后顺序决定。
根据键盘序列导航的顺序,值为 0 、非法值、或者没有 tabindex 值的元素应该放置在 tabindex 值为正值的元素后面。
- 兼容性
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
.output {
font: .9rem 'Fira Sans', sans-serif;
}
p {
font-style: italic;
}
div,
label {
display: block;
letter-spacing: .5px;
margin-bottom: 1rem;
}
div:focus {
font-weight: bold;
}
</style>
</head>
<body>
<p>Click anywhere in this pane, then try tabbing through the elements.</p>
<label>First in tab order:<input type="text"></label>
<div tabindex="0">Tabbable due to tabindex.</div>
<div tabindex="1">Tabbable due to tabindex.</div>
<div>Not tabbable: no tabindex.</div>
<label>Third in tab order:<input type="text"></label>
</body>
</html>
总结
今天的
focus-within
就到这了,相信大家今天也学到许多focus-within
新知识
欢迎大家访问 我的博客: 晴栀Sunset :https://qingzhisunset.gitee.io/qingzhi/
每日更新新知识 ,Get新技能