【发布时间】:2017-09-06 12:40:41
【问题描述】:
我已经创建了一个 flexbox 容器,它充当具有两个输入字段的表单控件,表示两个日期之间的范围。如果用户在两个字段中的任何一个字段中输入了内容,则该字段旁边会出现一个叉号。用户可以点击这个十字来清除该字段。
十字架是一个:after 伪元素,使用一些漂亮的css 和JavaScript 创建并与之交互,主要基于this answer on Stack Overflow。这是我的实现(有些简化,但不多):
$('.field.clearable').on('change input', 'input', function($e) {
$(this).parent().toggleClass('non-empty', !!this.value);
})
.on('mousemove', 'span.non-empty', function($e) {
var $this = $(this);
$this.toggleClass('onX', $this.width() < $e.clientX - $this.offset().left);
$this.hasClass('onX') ? $this.attr('title', 'Clear field') : $this.removeAttr('title');
})
.on('mouseleave', 'span.non-empty', function($e) {
var $this = $(this);
$this.removeClass('onX')
.removeAttr('title');
})
.on('click', 'span.non-empty.onX', function($e) {
$e.preventDefault();
var $this = $(this);
$this.removeClass('non-empty onX')
.removeAttr('title')
.children('input')
.val('')
.trigger('clear');
});
/* reset and cosmetic css */
* {
margin: 0;
padding: 0;
color: inherit;
font-family: inherit;
font-size: inherit;
}
::-webkit-input-placeholder {
color: #ccc;
font-size: 80%;
opacity: .8;
}
:-moz-placeholder {
color: #ccc;
font-size: 80%;
opacity: .8;
}
::-moz-placeholder {
color: #ccc;
font-size: 80%;
opacity: .8;
}
:-ms-input-placeholder {
color: #ccc;
font-size: 80%;
opacity: .8;
}
:focus::-webkit-input-placeholder {
opacity: .5;
}
:focus:-moz-placeholder {
opacity: .5;
}
:focus::-moz-placeholder {
opacity: .5;
}
:focus:-ms-input-placeholder {
opacity: .5;
}
html {
font-family: Arial;
font-size: 10px;
font-weight: normal;
text-align: left;
height: 100%;
}
body {
margin: 4em auto;
width: 400px;
color: #2c5ba0;
font-size: 1.5rem;
line-height: 1.5em;
background-color: #fff;
}
/* relevant css */
div.field {
display: inline-block;
margin: .4em 0;
}
div.field>label {
display: block;
margin: 0 0 .3em .2em;
font-size: 80%;
line-height: 1em;
}
div.field>span {
position: relative;
display: -webkit-flex;
display: flex;
-webkit-align-items: center;
align-items: center;
-webkit-justify-content: space-between;
justify-content: space-between;
box-sizing: border-box;
height: 2em;
border: .1em solid #ddd;
background-color: #fff;
}
div.field>span>span {
-webkit-flex: 1;
flex: 1;
}
div.field>span>span>input {
width: 100%;
border: none;
}
div.field.range>span input {
text-align: center;
}
div.field.range>span label {
-webkit-flex: 0;
flex: 0;
margin: 0 .2em;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
div.field.clearable span.non-empty {
position: relative;
padding-right: 2em;
}
div.field.clearable span.non-empty:after {
position: absolute;
right: 0;
top: 0;
content: 'x';
display: inline-block;
width: 2em;
height: 2em;
color: #ddd;
vertical-align: middle !important;
text-align: center !important;
font-style: normal !important;
font-weight: normal !important;
text-transform: none !important;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
cursor: pointer;
}
div.field.clearable span.non-empty.onX:after {
color: #f37e31;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="field clearable range">
<label for="start">created</label>
<span>
<span>
<input type="text" id="start" placeholder="from">
</span>
<label for="end">–</label>
<span>
<input type="text" id="end" placeholder="until">
</span>
</span>
</div>
当两个<input> 字段都包含值并因此在它们旁边有一个叉号时,它们的宽度比很好地相互抵消,没有任何问题。但是,当只有一个 <input> 字段包含值并且叉号仅出现在该 <input> 字段旁边时,叉号/<input> 字段会将其他内容推到一边。
这不应该发生。我怀疑<input> 字段是罪魁祸首。即使容器div.field 应该保持其display: block 的灵活性,内部内容的比率也应该保持不变。
以下是我认为可以通过以下方式实现的相关位:
/* the span that acts as the flexbox container */
div.field>span {
position: relative;
display: -webkit-flex;
display: flex;
-webkit-align-items: center;
align-items: center;
-webkit-justify-content: space-between;
justify-content: space-between;
box-sizing: border-box;
height: 2em;
border: .1em solid #ddd;
}
/* let the spans, containing the <input> fields, take available space */
div.field>span>span {
-webkit-flex: 1;
flex: 1;
}
/*
let <input> fields take 100% content space of span
I thought this should take into account any padding on its parent
*/
div.field>span>span>input {
width: 100%;
border: none;
}
/* let center label (the dash) not be flexible */
div.field.range>span label {
-webkit-flex: 0;
flex: 0;
margin: 0 .2em;
}
/* if .non-empty class was set by JavaScript */
/*
make room for :after by setting padding-right accordingly
but this is the issue:
I thought this would also make the <input> shrink accordingly,
but it appears it doesn't shrink the amount I anticipated
*/
div.field.clearable span.non-empty {
position: relative;
padding-right: 2em;
}
/* show :after pseudo-element */
div.field.clearable span.non-empty:after {
position: absolute;
right: 0;
top: 0;
content: 'x';
display: inline-block;
width: 2em;
height: 2em;
/* etc. */
}
你知道我怎样才能让整个控制元素保持其灵活性,包括它的:after 诡计,但在出现其中一个十字时让<input>s 相应地缩小?
或者更简单地说,我想:有没有办法让两个弹性项目,flex: 1,在任何给定时间都占用相等的空间?
我之所以使用 :after 元素而不是 background-image 就像我从中获得灵感的原始答案一样,是因为我使用的是自定义图标字体而不是图标图像。
【问题讨论】:
-
伪类应该去哪里? ...在输入之上?
-
@LGSon 不,伪(包含输入的
<span>的子项)应该放在输入旁边(否则输入文本可能会出现在十字下方,我不想发生这种情况)。伪是2em宽,因此我通过在<span>上设置padding-right: 2em为它腾出空间。我认为输入会相应地缩小,但它似乎没有这样做。 -
@LGSon 你实际上让我重新考虑它。我刚刚意识到无论我当前的问题如何,文本似乎都会随着填充而微移,因为文本是居中对齐的。但是,如果我放弃填充并在伪元素上设置
background-color并将其放在文本字段的顶部,我的问题可能会得到解决。不过,我将不得不调整检测是否点击十字的 JavaScript 来解决这个问题。但谢谢你的问题。这帮助我获得了一个新的视角。干杯!
标签: html css input flexbox width