如何在同一行放置文本框,并实现自适应宽度,使其超过浏览器的默认宽度?
以下片段展示了一个文本输入框的示例,当视口缩小到小于指定的(最大)宽度时不会造成溢出。这是通过让每个<input>占据可用宽度的100%,但不超过一个特定的限制来实现。
.block {
display: block;
}
.w-full {
width: 100%
}
.max-w-80 {
max-width: 20rem;
}
.max-w-20 {
max-width: 5rem;
}
<label for="ex1" class="block">First Name</label>
<input id="ex1" type="text" class="w-full max-w-80"/>
<label for="ex2" class="block">Last Name</label>
<input id="ex2" type="text" class="w-full max-w-20"/>
然而,如果通过flexbox将这些输入放在同一行,则较长的<input>元素会还原为浏览器的默认宽度。
.block {
display: block;
}
.flex {
display: flex;
}
.w-full {
width: 100%
}
.max-w-80 {
max-width: 20rem;
}
.max-w-20 {
max-width: 5rem;
}
<div class="flex">
<div>
<label for="ex1" class="block">First Name</label>
<input id="ex1" type="text" class="w-full max-w-80"/>
</div>
<div>
<label for="ex2" class="block">Last Name</label>
<input id="ex2" type="text" class="w-full max-w-20"/>
</div>
</div>
通过让包裹的<div>自适应增大来缓解这一问题,但如果视口足够宽,输入之间将出现空白区域(也就是说,输入项不会再彼此挨着)。
.block {
display: block;
}
.flex {
display: flex;
}
.w-full {
width: 100%
}
.max-w-80 {
max-width: 20rem;
}
.max-w-20 {
max-width: 5rem;
}
.grow {
flex-grow: 1;
}
<div class="flex">
<div class="grow">
<label for="ex1" class="block">First Name</label>
<input id="ex1" type="text" class="w-full max-w-80"/>
</div>
<div class="grow">
<label for="ex2" class="block">Last Name</label>
<input id="ex2" type="text" class="w-full max-w-20"/>
</div>
</div>
一种解决方案是将<input>的最大宽度也应用到包裹的<div>上,但这也会强制<label>限制为相同的尺寸。如果标签文字比文本框长,这会带来问题。
.block {
display: block;
}
.flex {
display: flex;
}
.w-full {
width: 100%
}
.max-w-80 {
max-width: 20rem;
}
.max-w-20 {
max-width: 5rem;
}
.grow {
flex-grow: 1;
}
<div class="flex">
<div class="grow max-w-80">
<label for="ex1" class="block">First Name</label>
<input id="ex1" type="text" class="w-full max-w-80"/>
</div>
<div class="grow max-w-20">
<label for="ex2" class="block">Phone Number</label>
<input id="ex2" type="text" class="w-full max-w-20"/>
</div>
</div>
有没有办法让flexbox的直接子元素(在此例中为 <divs>)尽可能多地增长以占满宽度,但不会超过其中嵌套的最长元素的最大宽度?
我确信这可以通过JavaScript实现,但我希望存在一个仅用CSS/HTML的解法。
编辑以演示拟议的解决方案:
white-space: pre— 由于标签重叠,不太理想。
.block {
display: block;
}
.flex {
display: flex;
}
.w-full {
width: 100%
}
.max-w-80 {
max-width: 20rem;
}
.max-w-20 {
max-width: 5rem;
}
.grow {
flex-grow: 1;
}
.whitespace-pre {
white-space: pre;
}
<div class="flex">
<div class="grow max-w-20">
<label for="ex2" class="block whitespace-pre">Phone Number</label>
<input id="ex2" type="text" class="w-full max-w-20"/>
</div>
<div class="grow max-w-80">
<label for="ex1" class="block">First Name</label>
<input id="ex1" type="text" class="w-full max-w-80"/>
</div>
</div>
解决方案
对于将来阅读这个问题的任何人来说,这里是我最终采用的解决方案,以及需要注意的其他警告。
.flex-container {
display: flex;
align-items: end;
}
.input-wrapper {
min-width: 0;
}
.input-label {
display: block;
max-width: fit-content;
}
.input-box {
max-width: 100%;
box-sizing: border-box;
}
<div class="flex-container">
<div class="input-wrapper">
<label for="ex1" class="input-label">First Name</label>
<input id="ex1" type="text" class="input-box"/>
</div>
<div class="input-wrapper">
<label for="ex2" class="input-label">Last Name</label>
<input id="ex2" type="text" class="input-box"/>
</div>
</div>
我相信这是在广泛浏览器支持下最简单的方案。
- 包裹的
<div>使用min-width: 0以便按需缩小。 -
标签使用
display: block;来实现“标签覆盖输入”的外观,并对其应用max-width: fit-content;,以防止多余的空间被点击。 -
虽然题目中没有提到,但通常“标签在输入之上”的布局更适用于各种表单;与“标签在输入旁边”相比,后者在标签长度不一时可能看起来很奇怪。
- 不建议完全移除标签或使用 占位符作为标签,因为这会带来无障碍方面的问题(可能会让使用屏幕阅读器的用户感到困惑)。
- 输入框具有
max-width: 100%,目前比max-width: stretch更易获得支持。通过在width:设置一个具体的宽度值,输入框将按该值扩展,或占满视口宽度的100%,以较小者为准。
不幸的是,使用隐式标签(即将外部 <div> 改为 <label>,并将文本放在 <span> 中)并不可取,因为这会导致空白区域也被视为标签的一部分,大多数浏览器在点击空白区域时会把焦点移到输入框。
备注
-
直接照抄以上代码片段会因为标签溢出而出现问题,因为未指定处理标签的方法。
-
我通常将
overflow-wrap: anywhere应用于<body>元素,作为防溢出的后备方案。同样的值也可以附加到标签/包装器上,但在网页根部一次性设置该值可能更方便。 - 也可以在标签上使用
overflow: hidden,并在标签上应用text-overflow: ellipsis以使其在省略号处收缩。然而,我并不推荐这样做,因为标签可能被截断到难以理解的程度。溢出的标签可能看起来丑陋,但至少信息对用户仍然可见。 - 将这些输入包装在
<fieldset>中时,fieldset本身可能会溢出。我认为这是fieldset的一个特定问题。可以通过对其应用min-width: 0;来解决,使其像输入包装那样收缩。 - 以下是上述标签+输入组件在TailwindCSS版本中的实现,请参见:
<div class="min-w-0">
<label for="ex1" class="block max-w-fit">Username</label>
<input id="ex1" type="text" class="box-border max-w-full ..."/>
</div>