CSS 中是否有一种方法可以在不使用 JS 的情况下使标签在聚焦输入时获得不同的 属性?

Is there a way in CSS to make a label get a different property when an input is focused without using JS?

我想做的是在输入字段获得焦点时更改标签字体颜色和边框颜色。有没有办法在不使用 JavaScript 的情况下做到这一点?

.input-label {
    display: flex;
    align-items: center;
    height: 16px;
    font-weight: 700;
    font-size: 11px;
    letter-spacing: .1px;
    color: #989898;
    text-transform: uppercase;
}
.form-control{
    display: inline-block;
    max-width: 100%;
    word-wrap: normal;
    background: transparent;
    border: none;
    border-bottom: 2px solid #cacaca;
    color: #4a4a4a;
    font-size: 1.19em;
    height: 35px;
    letter-spacing: .2px;
    padding: 7px 0;
    width: 100%;
    resize: none;
}
input:focus{
  /* after the input is focused the labele font color and border color change to something else*/
}
<div class="firstname">
<label for="name" class="input-label" id="name-label">First Name</label>
<input type="text" class="form-control" id="name" placeholder="First Name" required>
</div>

CSS 没有选择器爬上 DOM 树,要使用 CSS 从另一个被聚焦的元素修改样式,它必须站在前面作为兄弟姐妹或 parent.

但是它有 flexgridorder 允许在屏幕上重新排列元素,所以你可以重写你的 HTML 并设置 label 就在 input 后面并仍然显示它,在输入之前打印它。

这里是一个例子 grid (如果没有另外设置,构建一个单列的网格)order.

.firstname {
  display: grid;
}

.input-label {
  display: flex;
  align-items: center;
  height: 16px;
  font-weight: 700;
  font-size: 11px;
  letter-spacing: .1px;
  color: #989898;
  text-transform: uppercase;
  order: -1;
}

.form-control {
  display: inline-block;
  max-width: 100%;
  word-wrap: normal;
  background: transparent;
  border: none;
  border-bottom: 2px solid #cacaca;
  color: #4a4a4a;
  font-size: 1.19em;
  height: 35px;
  letter-spacing: .2px;
  padding: 7px 0;
  width: 100%;
  resize: none;
}

input:focus+label {
  color: red;
}
<div class="firstname">
  <input type="text" class="form-control" id="name" placeholder="First Name" required>
  <label for="name" class="input-label" id="name-label">First Name</label>
</div>

https://developer.mozilla.org/en-US/docs/Web/CSS/order

The order CSS property sets the order to lay out an item in a flex or grid container. Items in a container are sorted by ascending order value and then by their source code order.

如果表格中只有一个 input/label,那么 within-focus 是最简单的选择。

你可以使用:focus-within伪class:

matches an element if the element or any of its descendants are focused.

您可能想在 caniuse.com

检查浏览器兼容性是否符合您的要求

并像这样创建一个选择器:

    .firstname:focus-within .input-label {
      color: red;
    }

.input-label {
  display: flex;
  align-items: center;
  height: 16px;
  font-weight: 700;
  font-size: 11px;
  letter-spacing: .1px;
  color: #989898;
  text-transform: uppercase;
}

.form-control {
  display: inline-block;
  max-width: 100%;
  word-wrap: normal;
  background: transparent;
  border: none;
  border-bottom: 2px solid #cacaca;
  color: #4a4a4a;
  font-size: 1.19em;
  height: 35px;
  letter-spacing: .2px;
  padding: 7px 0;
  width: 100%;
  resize: none;
}

.firstname:focus-within .input-label {
  color: red;
}
<div class="firstname">
  <label for="name" class="input-label" id="name-label">First Name</label>
  <input type="text" class="form-control" id="name" placeholder="First Name" required>
</div>

或者,您可以将 label 放在 input 之后,然后使用 CSS.

重新排序

所以在html中,让标签为空,将输入放在第一位,将标签放在第二位。

接下来是CSS。目标是使用 css 选择器 + 将标签放回第一个位置。

然后根据需要更改标签 css :

/* CSS ADDED */
.firstname{
  display:flex;
}
.firstname > *:last-child {
  order:-1;
}

input:focus + label{
  color: red;
  border: 3px solid red;
  padding: 5px;
}

演示:

.input-label {
    display: flex;
    align-items: center;
    height: 16px;
    font-weight: 700;
    font-size: 11px;
    letter-spacing: .1px;
    color: #989898;
    text-transform: uppercase;
}
.form-control{
    display: inline-block;
    max-width: 100%;
    word-wrap: normal;
    background: transparent;
    border: none;
    border-bottom: 2px solid #cacaca;
    color: #4a4a4a;
    font-size: 1.19em;
    height: 35px;
    letter-spacing: .2px;
    padding: 7px 0;
    width: 100%;
    resize: none;
}
/* CSS ADDED */
.firstname{
  display:flex;
  flex-direction: column;
}
.firstname > *:last-child {
  order:-1;
}

input:focus + label{
  color: red;
  border: 3px solid red;
  padding: 5px;
}
<div class="firstname">
  <input type="text" class="form-control" id="name" placeholder="First Name" required>
  <label for="name" class="input-label" id="name-label">First Name</label>
</div>