css - 创建自定义下拉菜单,为什么子元素的宽度比其父元素宽?
问题描述
我正在尝试为 React 构建一个自定义下拉组件。不幸的是,我设置为 100% 的子列表的宽度显示为比其父元素更宽。
DOM:
<div className="dd-wrapper" id={this.state.wrapperID}>
<div className="dd-header" id={this.state.headerID} onClick={() => this.toggleList()}>
<div className="dd-header-title"></div>
</div>
<ul className="dd-list hidden" id={this.state.listID}>
<li className="dd-list-item">Test</li>
<li className="dd-list-item">Test2</li>
<li className="dd-list-item">Test3</li>
</ul>
</div>
该toggleList
函数从列表中删除hidden
该类,并向包装器添加一个边框属性类dd-border
,该包装器的行为也不正常(边框仅包装标题)。
它在这样的父元素中被调用(我正在使用 Bootstrap 网格):
<div className="col-md-3">
<label> Dropdown
<Dropdown id="test-dd"/>
</label>
</div>
这是相关的CSS:
.dd-wrapper {
width: 100%;
margin-top: 8px;
}
.dd-header {
height: 40px;
background-color: #E2E8F2;
background-image: url("assets/images/down-chevron.png");
background-repeat: no-repeat;
background-position: 95% 50%;
}
.dd-list {
list-style-type: none;
background-color: white;
position: absolute;
}
.dd-list li {
height: 40px;
}
.dd-border {
border: 1px solid #3d70b2;
}
label {
display: inline-block;
width: 100%;
font-size: 14px;
}
.hidden {
display: none;
}
结果如下所示:
如何在不手动执行的情况下获得宽度以匹配其父级(以确保它适用于任何大小的下拉菜单?其次,有没有人知道让边框也覆盖孩子的好技巧?
解决方案
快速说明:这是一个 CSS 问题,因此您的 React 逻辑只是阻碍任何愿意回答的人。我已根据您的描述将重要部分提取到下面没有 React 的工作片段中。我建议删除对您的问题背景不重要的任何内容,以鼓励更及时的回答。
如何在不手动操作的情况下获得与其父级匹配的宽度(以确保它适用于任何大小的下拉菜单?
我认为您要寻找的主要是position: relative
父母。因为绝对定位的元素会根据第一个“定位”的祖先来调整和定位自己。因此,您可以将其与top
, left
, right
, bottom
,width
和/或height
值(并且可能box-sizing: border-box;
)结合起来
...有谁知道让边界也覆盖孩子的好技巧?
您可以通过将下拉列表直接放在底部并切换共同父级上的类来隐藏/显示某些边框来伪造它。
这是要演示的代码段:
// The toggle logic in vanilla JS just to make the example work
// This, instead of toggling "hidden" on the list, toggles a "dd-closed" class on the wrapper
const wrapperEl = document.querySelector('.js-wrapper')
const headerEl = document.querySelector('.js-header')
if (wrapperEl && headerEl) {
const ancestorLabel = headerEl.closest('label')
const targetEl = ancestorLabel ? ancestorLabel : headerEl
targetEl.addEventListener('click',
() => wrapperEl.classList.toggle('dd-closed')
)
}
.dd-wrapper {
position: relative;
width: 100%;
margin-top: 8px;
}
.dd-header {
position: relative;
height: 40px;
background-color: #E2E8F2;
background-repeat: no-repeat;
background-position: 95% 50%;
border: 1px solid #3d70b2;
border-bottom-width: 0;
padding-right: 3em;
}
.dd-header::before {
position: absolute;
content: '\25B4';
right: 0;
text-align: center;
line-height: 40px;
width: 1em;
top: 0;
bottom: 0;
font-size: 2em;
}
.dd-list {
list-style-type: none;
background-color: white;
position: absolute;
border: 1px solid #3d70b2;
margin-top: 0;
left: 0; right: 0;
padding: 0;
}
.dd-list li {
vertical-align: middle;
padding: 1em;
}
.dd-list li:hover {
background-color: #eee;
}
label {
display: inline-block;
width: 100%;
font-size: 14px;
}
.dd-closed > .dd-header::before {
content: '\25BE';
float: right;
}
.dd-closed > .dd-header {
border-bottom-width: 1px;
}
.dd-closed > .dd-list {
display: none;
}
<!-- Basically what React would render as your output HTML...plus any necessary changes -->
<label> Dropdown
<div class="dd-wrapper dd-closed js-wrapper">
<div class="dd-header js-header">
<div class="dd-header-title"></div>
</div>
<ul class="dd-list">
<li class="dd-list-item">Test</li>
<li class="dd-list-item">Test2</li>
<li class="dd-list-item">Test3</li>
</ul>
</div>
</label>
<p>(Some other content for the dropdown to cover)</p>
<button>(I do nothing)</button>
推荐阅读
- multithreading - 大型协程与许多小型协程?
- amazon-web-services - 具有此 ID 的 Terraform 资源不存在
- sql - 用两个查询计算平均值
- image - 包 cached_network_image 是否会减少 Firestore 存储的网络带宽量?
- java - 如何创建两个日志文件
- python - 合并数据框返回熊猫中的 nan 列
- python - 有人可以解释一下这个 django 视图部分吗
- android - 在 Android Studio 上运行 TensorflowLite - tflite.run() 为每个输入提供相同的输出
- r - 在 R 中控制绘图的 DPI
- python - 我正在制作一个函数,它返回 FizzBuzz 列表中所有数字的总和。我认为这会很好,但没有工作。在 Python 中