javascript - 自定义表单字段的 z-index 问题(选择)

标签 javascript html css

背景

考虑以下自定义输入(忽略 JS):

$(document).ready(() => {

  $('input').focus(function() {
    $(this).closest('.field-container').addClass('focused');
  });
  
  $('input').blur(function() {
    $(this).closest('.field-container').removeClass('focused');
  });
  
});
html, body {
  background: #eee;
}

.field-container {
  display: flex;
  padding: 12px 10px 0;
  position: relative;
  transition: z-index 0s cubic-bezier(0.4, 0, 0.2, 1) 0.3s;
  width: 50%;
  z-index: 1;
}

.field-container.focused {
  transition-delay: 0s;
  z-index: 11;
}

.field-container.focused:before {
  opacity: 1;
  transform: scaleX(1);
  transition: 0.3s cubic-bezier(0.4, 0, 0.2, 1);
  transition-property: border, opacity, transform;
}

.field-container.focused label {
  font-size: 15px;
  opacity: 1;
  pointer-events: auto;
  top: 0;
}

.field-container.focused .select-form-control .options-form-control {
  opacity: 1;
  visibility: visible;
}

.field-container:before,
.field-container:after {
  bottom: 0;
  content: "";
  left: 0;
  position: absolute;
  right: 0;
  transition: border 0.3s cubic-bezier(0.4, 0, 0.2, 1), opacity 0.3s cubic-bezier(0.4, 0, 0.2, 1), transform 0s cubic-bezier(0.4, 0, 0.2, 1) 0.3s;
  will-change: border, opacity, transform;
}

.field-container:before {
  background: #000;
  height: 2px;
  opacity: 0;
  transform: scaleX(0.12);
  z-index: 11;
}

.field-container:after {
  background: #ccc;
  height: 1px;
  z-index: 10;
}

.field-container label {
  color: #ccc;
  font-size: 21px;
  font-weight: 500;
  pointer-events: none;
  position: absolute;
  top: 25px;
  transition: 0.4s cubic-bezier(0.25, 0.8, 0.25, 1);
  transition-duration: 0.3s;
  z-index: 10;
}

.field-container .select-form-control {
  display: flex;
  position: relative;
  width: 100%;
  z-index: 9;
}

.field-container input {
  background: none;
  border: none;
  color: #000;
  cursor: text;
  display: block;
  flex: 1;
  font-size: 21px;
  font-weight: 500;
  height: 56px;
  line-height: 56px;
  margin: 0;
  min-width: 100px;
  outline: none;
  padding: 0;
  text-rendering: auto;
  transition: 0.4s cubic-bezier(0.25, 0.8, 0.25, 1);
  transition-property: font-size, padding-top, color;
  word-spacing: normal;
  -webkit-appearance: textfield;
  -webkit-rtl-ordering: logical;
  -webkit-writing-mode: horizontal-tb !important;
}

.field-container .select-form-control .options-form-control {
  background: rgba(255, 255, 255, 0.95);
  box-shadow: 0 23px 71px 0 rgba(204, 204, 204, 0.09);
  left: -20px;
  opacity: 0;
  padding-top: 90px;
  position: absolute;
  right: -20px;
  top: -22px;
  transition: opacity 0.3s cubic-bezier(0.4, 0, 0.2, 1), visibility 0.3s cubic-bezier(0.4, 0, 0.2, 1);
  visibility: hidden;
  z-index: -1;
}

.field-container .select-form-control .options-form-control ul {
  list-style-type: none;
  max-height: 200px;
  overflow: auto;
  padding: 0 0 10px;
  margin: 0;
}

.field-container .select-form-control .options-form-control ul li {
  color: #000;
  cursor: pointer;
  display: block;
  font-size: 21px;
  font-weight: 500;
  line-height: 2.12;
  padding: 0 20px;
  z-index: -1;
  margin: 0;
}

.field-container .select-form-control .options-form-control ul li:hover {
  background: #ccc;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="field-container foo">
  <label>Foo</label>
  <div class="select-form-control">
    <input name="foo" autocomplete="new-password" readonly="readonly">
    <div class="options-form-control">
      <ul>
        <li class="active">Foo</li>
        <li class="">Bar</li>
        <li class="">Foobar</li>
      </ul>
    </div>
  </div>
</div>

<div class="field-container bar">
  <label>Bar</label>
  <div class="select-form-control">
    <input name="bar" autocomplete="new-password" readonly="readonly">
    <div class="options-form-control">
      <ul>
        <li class="active">Foo</li>
        <li class="">Bar</li>
        <li class="">Foobar</li>
      </ul>
    </div>
  </div>
</div>

对于 CSS 的数量,我深表歉意,我尝试尽可能多地删除,但需要提供功能以证明问题...

问题

请原谅我有点完美主义者,但我注意到一个非常小的问题让我很烦恼,我似乎无法想出解决办法。

当字段获得焦点并显示 .options-form-control 元素时,它需要位于所有其他内容之上(除了 input 和 label sibling )。我通过调整 .field-container 中每个元素的 z-index 实现了这一点。

问题是,当用户将焦点从关注下一个输入(从 .bar.foo)时,随着下拉列表的转换, .bar 元素中的 inputlabel,显示在正在转换的下拉列表上方(对于 .3s).

我知道为什么它这样做,但我想不出解决它的方法,尤其是在不重组整个标记的情况下,这不是一个真正的选择,因为它在其他组件中使用我的应用程序。

有人对我如何解决这个问题有什么建议吗?

最佳答案

主要问题是由于在嵌套元素上使用了很多 z-index,这会让您在处理堆栈上下文时感到头疼。为了避免这种不良影响,我删除了很多 z-index 属性,只保留需要的。

你只会找到 4 个 z-index

$(document).ready(() => {

  $('input').focus(function() {
    $(this).closest('.field-container').addClass('focused');
  });
  
  $('input').blur(function() {
    $(this).closest('.field-container').removeClass('focused');
  });
  
});
html, body {
  background: #eee;
}

.field-container {
  display: flex;
  padding: 12px 10px 0;
  position: relative;
  width: 50%;
}


.field-container.focused:before {
  opacity: 1;
  transform: scaleX(1);
  transition: 0.3s cubic-bezier(0.4, 0, 0.2, 1);
  transition-property: border, opacity, transform;
  z-index: 11; /* Here */
}

.field-container.focused label {
  font-size: 15px;
  opacity: 1;
  pointer-events: auto;
  top: 0;
  z-index: 10; /* Here */
}

.field-container.focused .select-form-control .options-form-control {
  opacity: 1;
  visibility: visible;
}

.field-container:before,
.field-container:after {
  bottom: 0;
  content: "";
  left: 0;
  position: absolute;
  right: 0;
  transition: border 0.3s cubic-bezier(0.4, 0, 0.2, 1), opacity 0.3s cubic-bezier(0.4, 0, 0.2, 1), transform 0s cubic-bezier(0.4, 0, 0.2, 1) 0.3s;
  will-change: border, opacity, transform;
}

.field-container:before {
  background: #000;
  height: 2px;
  opacity: 0;
  transform: scaleX(0.12);
}

.field-container:after {
  background: #ccc;
  height: 1px;
}

.field-container label {
  color: #ccc;
  font-size: 21px;
  font-weight: 500;
  pointer-events: none;
  position: absolute;
  top: 25px;
  transition: 0.4s cubic-bezier(0.25, 0.8, 0.25, 1);
  transition-duration: 0.3s;
}

.field-container .select-form-control {
  display: flex;
  position: relative;
  width: 100%;
}

.field-container input {
  background: none;
  border: none;
  color: #000;
  cursor: text;
  display: block;
  flex: 1;
  font-size: 21px;
  font-weight: 500;
  height: 56px;
  line-height: 56px;
  margin: 0;
  min-width: 100px;
  outline: none;
  padding: 0;
  text-rendering: auto;
  transition: 0.4s cubic-bezier(0.25, 0.8, 0.25, 1);
  transition-property: font-size, padding-top, color;
  word-spacing: normal;
  -webkit-appearance: textfield;
  -webkit-rtl-ordering: logical;
  -webkit-writing-mode: horizontal-tb !important;
}

.field-container .select-form-control .options-form-control {
  background: rgba(255, 255, 255, 0.95);
  box-shadow: 0 23px 71px 0 rgba(204, 204, 204, 0.09);
  left: -20px;
  opacity: 0;
  padding-top: 90px;
  position: absolute;
  right: -20px;
  top: -22px;
  transition: opacity 0.3s cubic-bezier(0.4, 0, 0.2, 1), visibility 0.3s cubic-bezier(0.4, 0, 0.2, 1);
  visibility: hidden;
  z-index: 2; /* Here */
}

.field-container .select-form-control .options-form-control ul {
  list-style-type: none;
  max-height: 200px;
  overflow: auto;
  padding: 0 0 10px;
  margin: 0;
}

.field-container .select-form-control .options-form-control ul li {
  color: #000;
  cursor: pointer;
  display: block;
  font-size: 21px;
  font-weight: 500;
  line-height: 2.12;
  padding: 0 20px;
  z-index: -1; /* Here */
  margin: 0;
}

.field-container .select-form-control .options-form-control ul li:hover {
  background: #ccc;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="field-container foo">
  <label>Foo</label>
  <div class="select-form-control">
    <input name="foo" autocomplete="new-password" readonly="readonly">
    <div class="options-form-control">
      <ul>
        <li class="active">Foo</li>
        <li class="">Bar</li>
        <li class="">Foobar</li>
      </ul>
    </div>
  </div>
</div>

<div class="field-container bar">
  <label>Bar</label>
  <div class="select-form-control">
    <input name="bar" autocomplete="new-password" readonly="readonly">
    <div class="options-form-control">
      <ul>
        <li class="active">Foo</li>
        <li class="">Bar</li>
        <li class="">Foobar</li>
      </ul>
    </div>
  </div>
</div>

有关 z-index 和堆叠上下文的更多详细信息的相关问题:

Why can't an element with a z-index value cover its child?

关于javascript - 自定义表单字段的 z-index 问题(选择),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57127030/

相关文章:

javascript - 将字符串转换为时间并添加一些分钟

php - 如何仅向双引号添加斜杠

ios9 移动 safari 景观 css 错误,位置为 :absolute bottom:0

html - 绝对定位的 div float 在主要内容上

html - 根据高度居中动态方形 div

javascript - Angular 在同一工厂内调用工厂函数

javascript - 如何在 d3 VERSION 4 中获取相对于元素原点的 (x, y) 坐标

CSS:我可以选择不属于特定类的每种类型的元素吗?

javascript - 为什么选择 SPA(单页应用程序)?

javascript - 如何限制输入元素中允许的字符集?