Consider the following custom input (ignore the 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>
I apologise for the quantity of CSS, I tried to strip out as much as possible but needed the functionality to be there in order to demonstrate the issue...
Forgive me for being somewhat of a perfectionist, but I have noticed a very slight issue that is rather bugging me and I cannot seem to come up with a fix for it.
When the field is focused, and the .options-form-control
element is shown, it needs to be above all other content (aside from the input
and label siblings). I have acheived this by adjusting the z-index
of each of the elements within the .field-container
.
The problem is, when a user focuses the previous input from having focus on the next input (from .bar
to .foo
), as the dropdown transitions in, the input
and label
within the .bar
element, show above the dropdown that is being transitioned in (for .3s
).
I know why it is doing this, but I cannot think of a way to solve it, especially without restructuring the entire markup which isn't really an option because it is used within other components in my app.
Does anyone have any suggestions as to how I can get around this?
The main issue is due to the use of a lot of z-index
on nested elements which will give you headaches dealing with stacking context. In order to avoid this bad effect, I removed a lot of z-index
properties and kept only the needed ones.
You will only find 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>
Related question for more details about z-index
and stacking context:
Why can't an element with a z-index value cover its child?
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With