考虑一个自动提示输入,该输入位于具有一些内容和垂直滚动条的容器中:
当显示自动提示建议时,它们应显示在内容的顶部,而不会影响容器的滚动条。
我希望得到:
请注意,滚动条与上面完全相同。
但是,我得到以下内容:
请注意,滚动条会受到影响,建议会被删除。
为什么绝对定位的建议会影响容器的滚动条?
你会如何解决这个问题?
注意:
.autosuggest
内(将.autosuggest
视为无法更改HTML的第三方组件,但您可以更改其CSS )。
.container {
height: 100px;
width: 300px;
margin-top: 50px;
overflow-y: auto;
border: 1px solid black;
}
.autosuggest {
position: relative;
width: 250px;
}
.input {
font-size: 16px;
width: 230px;
padding: 5px 10px;
border: 0;
background-color: #FFEBBF;
}
.suggestions {
list-style-type: none;
margin: 0;
padding: 5px 10px;
width: 230px;
background-color: #85DDFF;
position: absolute;
}
.content {
width: 120px;
padding: 5px 10px;
}
<div class="container">
<div class="autosuggest">
<input class="input" type="text" value="input">
</div>
<div class="content">
content content content content content content content content content content
</div>
</div>
<div class="container">
<div class="autosuggest">
<input class="input" type="text" value="input">
<ul class="suggestions">
<li>suggestion 1</li>
<li>suggestion 2</li>
<li>suggestion 3</li>
<li>suggestion 4</li>
<li>suggestion 5</li>
<li>suggestion 6</li>
<li>suggestion 7</li>
<li>suggestion 8</li>
<li>suggestion 9</li>
</ul>
</div>
<div class="content">
content content content content content content content content content content
</div>
</div>
答案 0 :(得分:10)
- 当显示自动提示建议时,它们应显示在内容的顶部,而不会影响容器的滚动条。
- 滚动容器时,输入和建议应一起移动。
仅限CSS无法完成。
要让suggestions
的内容container
显示在position: absolute
的内容之上,而非autosuggest
,则必须container
,而不是父母position: relative
和{{suggestions
1}})可以是suggestions
。
缺点是autosuggest
不会在滚动时移动。
要使container
移动滚动条,其父级之一(position: relative
或container
)必须为overflow: visible
。
与此相反,由于input
不是autosuggest
,因此会被裁剪
正如已经建议的那样,假设position: relative
必须在autosuggest
元素中,将position: absolute
上的input
更改为suggestions
,以便z-index
保留container
滚动,可能是最好的,但需要在每个input
上设置autosuggest
以避免奇数重叠。
但是,如果第三方组件的提供者,...... :) ......可以被谈到suggestions
可以放在{{1}之外的版本根据if content
是否具有焦点,我可以使用input
和input
以及它们的布局获得更多控件(仅使用CSS),...
...此示例可能是一个良好的开端(点击suggestions
以显示.container {
background-color: white;
width: 300px;
min-height: 100px;
margin-top: 50px;
border: 1px solid black;
overflow: auto;
position: relative;
}
.autosuggest {
position: relative;
width: 250px;
z-index: 1;
}
.input {
font-size: 16px;
width: 245px;
padding: 5px 10px;
border: 0;
background-color: #FFEBBF;
position: relative;
z-index: 1;
}
.suggestions {
list-style-type: none;
margin: 0;
padding: 5px 10px;
width: 245px;
background-color: #85DDFF;
display: none;
}
.content {
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
padding: 35px 10px 5px 10px;
overflow: auto;
z-index: 0;
}
input:focus ~ .autosuggest .suggestions {
display: block;
}
)。
<div class="container">
<input class="input" type="text" value="input">
<div class="autosuggest">
<ul class="suggestions">
<li>suggestion 1</li>
<li>suggestion 2</li>
<li>suggestion 3</li>
<li>suggestion 4</li>
<li>suggestion 5</li>
<li>suggestion 6</li>
<li>suggestion 7</li>
<li>suggestion 8</li>
<li>suggestion 9</li>
</ul>
</div>
<div class="content">
content content content content content content content content content content
content content content content content content content content content content
content content content content content content content content content content
content content content content content content content content content content
content content content content content content content content content content
content content content content content content content content content content
</div>
</div>
<div class="container">
<input class="input" type="text" value="input">
<div class="autosuggest">
<ul class="suggestions">
<li>suggestion 1</li>
<li>suggestion 2</li>
<li>suggestion 3</li>
<li>suggestion 4</li>
<li>suggestion 5</li>
</ul>
</div>
<div class="content">
content content content content content content content content content content
content content content content content content content content content content
content content content content content content content content content content
</div>
</div>
e.preventDefault()
答案 1 :(得分:7)
这看起来有点像一种笨拙的方法并且有一个小警告,但它是纯CSS /没有HTML结构修改。
基本上,我将.container
作为主要父级,而不是尝试从较低级别(.autosuggest
)开始工作。一步一步:
position: relative
移至.container
.autosuggest
绝对定位(上/左默认为0px)。
.content
绝对位于所有四边0px,因此它的大小与.container
相同.content
div .content
的顶部填充设置为.input
的高度+实际所需的填充。否则.content
位于输入元素后面。你最终得到了这个:
.container {
height: 100px;
width: 300px;
margin-top: 50px;
border: 1px solid black;
position: relative;
}
.autosuggest {
width: 250px;
position: absolute;
z-index: 50;
}
.input {
font-size: 16px;
width: 230px;
padding: 5px 10px;
border: 0;
background-color: #FFEBBF;
}
.autosuggest .input:focus ~ .suggestions{
display: block;
}
.suggestions {
display: none;
list-style-type: none;
margin: 0;
padding: 5px 10px;
width: 230px;
background-color: #85DDFF;
}
.content {
overflow-y: auto;
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
padding: 28px 10px 5px;
}
<div class="container">
<div class="autosuggest">
<input class="input" type="text" value="input">
<ul class="suggestions">
<li>suggestion 1</li>
<li>suggestion 2</li>
<li>suggestion 3</li>
<li>suggestion 4</li>
<li>suggestion 5</li>
<li>suggestion 6</li>
<li>suggestion 7</li>
<li>suggestion 8</li>
<li>suggestion 9</li>
</ul>
</div>
<div class="content">
content content<br >content content content content content<br ><br ><br ><br ><br ><br >content content content
</div>
</div>
我还为autosuggest框添加了一些显示/隐藏,因为它看起来不错。
.autosuggest .input:focus ~ .suggestions{
display: block;
}
.suggestions {
display: none;
}
经过测试的FF 43,Chrome 47
滚动容器时,输入和建议应该一起移动。
这很可能需要JavaScript。根据定义,将建议设置为绝对位置会将其从内容流的其余部分中删除。您可以在.suggestions
div上设置一个高度并单独滚动它,但是如果它位于绝对位置(再次,仅使用CSS),则滚动不能(据我所知)与.content
滚动相关联
类似的东西:
$('.content').on('scroll', function () {
$('.autosuggest .suggestions').scrollTop($(this).scrollTop());
});
为什么绝对定位的建议会影响容器的滚动条?
从技术上讲,绝对定位的元素不会影响父母的身高。但是,它们仍然被视为元素的内容 - 内容溢出(至少在这种情况下)。
overflow属性指定是否剪切内容,渲染滚动条或仅在溢出其块级容器时显示内容。 (from MDN)
由于.container
溢出设置为滚动,因此它显示滚动条,因为其中一个子节点溢出了边界框。如果您将溢出更改为隐藏,则会隐藏所有扩展内容并设置为可见,您会看到.autosuggest
延伸超过.container
,但.content
也是如此(因为它也是内容扩展边界框)。
您会看到一个滚动条,因为.suggest
内容在视觉上超出了.container
块,即使它位于绝对位置。
答案 2 :(得分:4)
你所要做的就是将.zos索引属性添加到.autosuggest和.suggestions这里是codepen的代码示例
http://codepen.io/HTMLNoob/pen/EPEXKN
.autosuggest {
z-index: -10;
width: 250px;
}
.suggestions {
list-style-type: none;
margin: 0;
padding: 5px 10px;
width: 230px;
background-color: #85DDFF;
position: absolute;
z-index: 10;
}
<强> 强>
我相信这就是你要找的东西
http://jsbin.com/fegibaboyo/1/edit?html,css,output
注意:将鼠标悬停在输入上并提供建议。
<强> 强>
http://jsbin.com/mojopuboku/edit?html,css,output
这是新答案。
我已经在大多数浏览器(Firefox,Chrome,Opera)中测试了这个答案,并且所有浏览器都执行相同的结果。(我不确定Safari,因为我无法在Windows XP上安装Safari)
答案 3 :(得分:2)
.autosuggest {
position: fixed; /* add position:fixed */
}
.suggestions {
/* remove position:absolute */
}
答案 4 :(得分:1)
为什么不直接将div和li元素拉出div容器,然后通过设置负顶部位置来移动建议?
http://jsbin.com/ficalu/edit?html,css,output
更新: 将.autosuggest更改为position:absolute
答案 5 :(得分:1)
轻松,删除
position: relative
从类.autosuggest 添加到类.container
答案 6 :(得分:1)
将此添加到您的CSS:
.input:focus + .suggestions {
position: fixed;
display: block;
}
在CSS中将display: none;
添加到.suggestions
。
小提琴here。
答案 7 :(得分:1)
这个怎么样:
我在CSS中的更改旁边有一条评论。请注意,这仅在Chrome中进行了测试。你也可以稍微优化HTML,比如删除示例中的容器,但你可能有多个元素。
HTML:
<div class="autosuggest">
<input class="input" type="text" value="input">
<ul class="suggestions">
<li>suggestion 1</li>
<li>suggestion 2</li>
<li>suggestion 3</li>
<li>suggestion 4</li>
<li>suggestion 5</li>
<li>suggestion 6</li>
<li>suggestion 7</li>
<li>suggestion 8</li>
<li>suggestion 9</li>
</ul>
</div>
<div class="container">
<div class="content">
content content content content content content content content content content
</div>
</div>
CSS:
.container {
height: 100px;
width: 300px;
overflow-y: auto;
border: 1px solid black;
}
.autosuggest {
position: relative;
top:29px; /* height of input */
left:1px; /* width of container border */
width: 250px;
}
.input {
font-size: 16px;
width: 230px;
padding: 5px 10px;
border: 0;
background-color: #FFEBBF;
}
.suggestions {
list-style-type: none;
margin: 0;
padding: 5px 10px;
width: 230px;
background-color: #85DDFF;
position: absolute;
}
.content {
width: 120px;
margin-top: 29px; /* height of input */
padding: 5px 10px;
}
答案 8 :(得分:0)
JavaScript解决方案
我知道有人问过该解决方案不使用Javascript,但是由于所提出的解决方案都无法为我工作,因此我别无选择,只能诉诸于次优的Javascript。尽管如此,该解决方案仍然有效。
为什么上述提议的解决方案都不适合我的原因:
因此,我无法处理输入,建议容器以及前两个容器(相当于Web组件)之外的任何内容的CSS属性或HTML结构 ,以我为例。
我也无法将 position:absolute 应用于容器(由于原因2),如某些解决方案所建议的那样。
这就是说,我只是给那些出于某种原因而不能接受任何其他解决方案的人留在这里,并且别无选择,只能求助于Javascript。我希望这会对他们有所帮助。
const header = document.querySelector('.child-header');
const content = document.querySelector('.child-content');
const open = (el) => {
if (!content.hasAttribute('open')) {
content.toggleAttribute('open');
}
}
const close = (el) => {
if (content.hasAttribute('open')) {
content.toggleAttribute('open');
}
}
window.addEventListener('click', (e) => {
let element = e.target;
let notInsideContent = true;
while (element && notInsideContent) {
notInsideContent = !element.classList.contains('child-content');
element = element.parentElement;
}
if (notInsideContent) {
close(content);
}
});
const repositionContent = () => {
const headerStyle = header.getBoundingClientRect();
content.style.left = `${headerStyle.x}px`;
const contentTop = headerStyle.y + headerStyle.height;
content.style.top = `${contentTop}px`;
content.style.width = `${headerStyle.width}px`;
// Make sure height takes into account bottom of page scroll
const windowBottom = window.innerHeight;
const contentMaxHeight = contentTop + content.scrollHeight;
if (contentMaxHeight > windowBottom) {
content.style.maxHeight = `${
content.scrollHeight -
(contentMaxHeight - windowBottom)
}px`;
} else {
content.style.maxHeight = '';
}
};
header.addEventListener('click', (e) => {
e.stopPropagation();
open(content);
repositionContent();
});
// Listen to ANY scroll event on the document
document.addEventListener('scroll', e => {
if (!content.hasAttribute('open')) {
return;
}
// TODO Check scroll provoked position change for content element
// Check scroll origin element doesn't come from within
const path = e.composedPath();
let element = path.pop();
let notInsideContentElement = true;
while (element && notInsideContentElement) {
notInsideContentElement = (element !== content);
element = path.pop();
}
if (notInsideContentElement) {
repositionContent();
}
}, true);
.scrollable {
overflow: auto;
border: 1px solid black;
}
.child-header {
border: 1px solid red;
box-sizing: border-box;
cursor: pointer;
}
.child-content[open] {
display: block;
}
.child-content {
display: none;
border: 1px solid blue;
box-sizing: border-box;
background: blue;
color: white;
position: fixed;
overflow-y: auto;
}
<div class="scrollable">
<div>Element</div>
<div>Element</div>
<div>Element</div>
<div>Element</div>
<div>Element</div>
<div>Element</div>
<div>Element</div>
<div>Element</div>
<div>Element</div>
<div>Element</div>
<div>Element</div>
<div class="parent">
<div class="child-header">
Click me for suggestions
</div>
<div class="child-content">
<div>Suggestion</div>
<div>Suggestion</div>
<div>Suggestion</div>
<div>Suggestion</div>
<div>Suggestion</div>
<div>Suggestion</div>
<div>Suggestion</div>
<div>Suggestion</div>
<div>Suggestion</div>
<div>Suggestion</div>
<div>Suggestion</div>
<div>Suggestion</div>
<div>Suggestion</div>
<div>Suggestion</div>
<div>Suggestion</div>
<div>Suggestion</div>
<div>Suggestion</div>
<div>Suggestion</div>
</div>
</div>
<div>Element</div>
<div>Element</div>
<div>Element</div>
<div>Element</div>
<div>Element</div>
<div>Element</div>
<div>Element</div>
<div>Element</div>
<div>Element</div>
<div>Element</div>
<div>Element</div>
<div>Element</div>
</div>
答案 9 :(得分:-1)
你只能在&#34; css&#34;风格,如果建议1,2,3元素不是&#34;输入&#34;元件。
例如:
<input>
content
content
</input>
suggestion1
suggestion2
suggestion3
或作为工作示例thar建议htmlnoob url in some upper mess
其他修复,只能在旧浏览器中使用,例如ie5。