如何防止绝对定位的元素影响滚动条?
How to prevent an absolutely positioned element to affect the scrollbar?
考虑一个位于容器中的自动建议输入,其中包含一些内容和一个垂直滚动条:
当显示自动建议时,它们应该出现在内容的顶部而不影响容器的滚动条。
我希望得到:
注意滚动条和上面完全一样
但是,我得到以下信息:
注意滚动条受到影响,建议被删减。
为什么绝对定位建议会影响容器的滚动条?
你会如何解决这个问题?
备注:
- 滚动容器时,输入和建议应该一起移动。
- 您可以修改 HTML,但输入和建议列表应保留在
.autosuggest
内(将 .autosuggest
视为 HTML 的第三方组件无法更改,但您可以更改其 CSS).
- 如果有帮助,您可以使用 flexbox。
- 我正在寻找 CSS 唯一的解决方案。不请Javascript
.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>
您所要做的就是将 z-index 属性添加到 .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
注意: 将鼠标悬停在输入内容上并提供建议。
更新2:
http://jsbin.com/mojopuboku/edit?html,css,output
这是新答案。
我已经在大多数浏览器(Firefox、Chrome、Opera)中测试了这个答案,所有这些浏览器都执行相同的结果。(我不确定 Safari,因为我无法在上安装 Safari我的 Windows XP)
为什么不直接将 ul 和 li 元素从 div 容器中拉出,然后通过设置负的顶部位置来向上移动建议?
http://jsbin.com/ficalu/edit?html,css,output
更新:
将 .autosuggest 更改为 position: absolute
简单,删除
position: relative
来自 class.autosuggest 并添加到 class.container
.autosuggest {
position: fixed; /* add position:fixed */
}
.suggestions {
/* remove position:absolute */
}
- When autosuggest suggestions are shown, they should appear on top of the content without affecting container's scrollbar.
- When scrolling the container, the input and suggestions should move together.
这不能只用 CSS 来完成。
要让 suggestions
出现在 container
内容的顶部,不被剪裁,它必须有其父项的 position: absolute
和 none(autosuggest
和 container
) 可以是 position: relative
.
缺点是 suggestions
不会在滚动时移动。
要使 suggestions
随滚动一起移动,其父项之一(autosuggest
或 container
)需要 position: relative
。
不利的一面是,由于 container
不是 overflow: visible
,它将被剪裁
如前所述,假设 input
必须在 autosuggest
元素内,将 autosuggest
上的 position: relative
更改为 position: absolute
,所以 input
在滚动时与 suggestions
保持一致,这可能是最好的,尽管需要在每个 container
上设置 z-index
以避免奇怪的重叠。
但是如果 第三方组件的提供者 ,... :) ..., 可以讨论成可以放置 input
的版本在 autosuggest
元素之外,仅使用 CSS 可以获得更多的控制,基于 if input
有无焦点,...
...此示例可能是一个好的开始(单击 input
显示 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>
将此添加到您的 CSS:
.input:focus + .suggestions {
position: fixed;
display: block;
}
并在 CSS 中将 display: none;
添加到 .suggestions
。
Fiddle here.
只有当建议 1、2、3 元素不是 "input" 元素的子元素时,您才能使用 "css only" 样式。
例如:
<input>
content
content
</input>
suggestion1
suggestion2
suggestion3
或者作为工作示例建议 htmlnoob
url in some upper mess
其他修复,只能在旧浏览器中工作,如 ie5。
这个怎么样:
- 将自动建议移到容器外
- 为内容提供与输入高度相同的边距(如果您使用的是 LESS/SASS,您应该能够计算出)
- 降低自动建议以占用边距space
我在 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;
}
这似乎有点笨拙,并且有一个小警告,但它是纯粹的 CSS/ 没有 HTML 结构修改。
本质上,我让 .container
成为主要父级,而不是尝试从较低级别 (.autosuggest
) 开始工作。一步一步:
- 将
position: relative
上移 .container
- 使
.autosuggest
绝对定位(顶部/左侧默认为0px)。
- 为其设置更高的 z-index,使其始终位于顶部
- 使
.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 .input:focus ~ .suggestions{
display: block;
}
.suggestions {
display: none;
}
测试 FF 43,Chrome47
When scrolling the container, the input and suggestions should move together.
这很可能需要 JavaScript。根据定义,将建议设置为绝对位置会将它们从其余内容流中移除。您可以在 .suggestions
div 上设置一个高度并单独滚动它,但是如果绝对定位(再次,单独使用 CSS)。
类似于:
$('.content').on('scroll', function () {
$('.autosuggest .suggestions').scrollTop($(this).scrollTop());
});
Why absolutely positioned suggestions affect container's scrollbar?
从技术上讲,绝对定位元素不会影响父元素的高度。但是,它们仍然被视为元素的内容 - 溢出的内容(至少在这种情况下)。
The overflow property specifies whether to clip content, render scrollbars or just display content when it overflows its block level container. (from MDN)
由于 .container
已将溢出设置为滚动,它会显示一个滚动条,因为它的一个子项溢出了边界框。如果您将溢出更改为隐藏,它将隐藏所有扩展内容并设置为可见,您将看到 .autosuggest
延伸超过 .container
,但 .content
也是如此(因为它也满足于扩展边界框)。
您看到滚动条是因为 .suggest
内容在视觉上超出了 .container
块,即使它是绝对定位的。
Javascript解决方案
我知道有人问没有 Javascript 用于解决方案,但由于 none 提议的解决方案对我有用 ,我有别无选择,只能求助于非常次优的 Javascript 可行的解决方案,nonetheless.
上述解决方案 none 对我有效的原因:
- 我正在开发一个 Web 组件,它基本上只包含原始问题中指定的输入和建议部分。
- 我无法假设 Web 组件的位置
使用(在另一个带有 scroll: auto 的元素内,在带有
或者没有卷轴,...)。
因此,除了输入、建议容器和容器到前 2 个,在我的例子中等同于 Web 组件。
我也无法将 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>
考虑一个位于容器中的自动建议输入,其中包含一些内容和一个垂直滚动条:
当显示自动建议时,它们应该出现在内容的顶部而不影响容器的滚动条。
我希望得到:
注意滚动条和上面完全一样
但是,我得到以下信息:
注意滚动条受到影响,建议被删减。
为什么绝对定位建议会影响容器的滚动条?
你会如何解决这个问题?
备注:
- 滚动容器时,输入和建议应该一起移动。
- 您可以修改 HTML,但输入和建议列表应保留在
.autosuggest
内(将.autosuggest
视为 HTML 的第三方组件无法更改,但您可以更改其 CSS). - 如果有帮助,您可以使用 flexbox。
- 我正在寻找 CSS 唯一的解决方案。不请Javascript
.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>
您所要做的就是将 z-index 属性添加到 .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
注意: 将鼠标悬停在输入内容上并提供建议。
更新2:
http://jsbin.com/mojopuboku/edit?html,css,output
这是新答案。
我已经在大多数浏览器(Firefox、Chrome、Opera)中测试了这个答案,所有这些浏览器都执行相同的结果。(我不确定 Safari,因为我无法在上安装 Safari我的 Windows XP)
为什么不直接将 ul 和 li 元素从 div 容器中拉出,然后通过设置负的顶部位置来向上移动建议?
http://jsbin.com/ficalu/edit?html,css,output
更新: 将 .autosuggest 更改为 position: absolute
简单,删除
position: relative
来自 class.autosuggest 并添加到 class.container
.autosuggest {
position: fixed; /* add position:fixed */
}
.suggestions {
/* remove position:absolute */
}
- When autosuggest suggestions are shown, they should appear on top of the content without affecting container's scrollbar.
- When scrolling the container, the input and suggestions should move together.
这不能只用 CSS 来完成。
要让 suggestions
出现在 container
内容的顶部,不被剪裁,它必须有其父项的 position: absolute
和 none(autosuggest
和 container
) 可以是 position: relative
.
缺点是 suggestions
不会在滚动时移动。
要使 suggestions
随滚动一起移动,其父项之一(autosuggest
或 container
)需要 position: relative
。
不利的一面是,由于 container
不是 overflow: visible
,它将被剪裁
如前所述,假设 input
必须在 autosuggest
元素内,将 autosuggest
上的 position: relative
更改为 position: absolute
,所以 input
在滚动时与 suggestions
保持一致,这可能是最好的,尽管需要在每个 container
上设置 z-index
以避免奇怪的重叠。
但是如果 第三方组件的提供者 ,... :) ..., 可以讨论成可以放置 input
的版本在 autosuggest
元素之外,仅使用 CSS 可以获得更多的控制,基于 if input
有无焦点,...
...此示例可能是一个好的开始(单击 input
显示 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>
将此添加到您的 CSS:
.input:focus + .suggestions {
position: fixed;
display: block;
}
并在 CSS 中将 display: none;
添加到 .suggestions
。
Fiddle here.
只有当建议 1、2、3 元素不是 "input" 元素的子元素时,您才能使用 "css only" 样式。
例如:
<input>
content
content
</input>
suggestion1
suggestion2
suggestion3
或者作为工作示例建议 htmlnoob url in some upper mess
其他修复,只能在旧浏览器中工作,如 ie5。
这个怎么样:
- 将自动建议移到容器外
- 为内容提供与输入高度相同的边距(如果您使用的是 LESS/SASS,您应该能够计算出)
- 降低自动建议以占用边距space
我在 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;
}
这似乎有点笨拙,并且有一个小警告,但它是纯粹的 CSS/ 没有 HTML 结构修改。
本质上,我让 .container
成为主要父级,而不是尝试从较低级别 (.autosuggest
) 开始工作。一步一步:
- 将
position: relative
上移.container
- 使
.autosuggest
绝对定位(顶部/左侧默认为0px)。- 为其设置更高的 z-index,使其始终位于顶部
- 使
.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 .input:focus ~ .suggestions{
display: block;
}
.suggestions {
display: none;
}
测试 FF 43,Chrome47
When scrolling the container, the input and suggestions should move together.
这很可能需要 JavaScript。根据定义,将建议设置为绝对位置会将它们从其余内容流中移除。您可以在 .suggestions
div 上设置一个高度并单独滚动它,但是如果绝对定位(再次,单独使用 CSS)。
类似于:
$('.content').on('scroll', function () {
$('.autosuggest .suggestions').scrollTop($(this).scrollTop());
});
Why absolutely positioned suggestions affect container's scrollbar?
从技术上讲,绝对定位元素不会影响父元素的高度。但是,它们仍然被视为元素的内容 - 溢出的内容(至少在这种情况下)。
The overflow property specifies whether to clip content, render scrollbars or just display content when it overflows its block level container. (from MDN)
由于 .container
已将溢出设置为滚动,它会显示一个滚动条,因为它的一个子项溢出了边界框。如果您将溢出更改为隐藏,它将隐藏所有扩展内容并设置为可见,您将看到 .autosuggest
延伸超过 .container
,但 .content
也是如此(因为它也满足于扩展边界框)。
您看到滚动条是因为 .suggest
内容在视觉上超出了 .container
块,即使它是绝对定位的。
Javascript解决方案
我知道有人问没有 Javascript 用于解决方案,但由于 none 提议的解决方案对我有用 ,我有别无选择,只能求助于非常次优的 Javascript 可行的解决方案,nonetheless.
上述解决方案 none 对我有效的原因:
- 我正在开发一个 Web 组件,它基本上只包含原始问题中指定的输入和建议部分。
- 我无法假设 Web 组件的位置 使用(在另一个带有 scroll: auto 的元素内,在带有 或者没有卷轴,...)。
因此,除了输入、建议容器和容器到前 2 个,在我的例子中等同于 Web 组件。
我也无法将 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>