创建自定义下拉列表,为什么子元素的宽度比其父元素宽?

时间:2018-06-15 17:06:32

标签: 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;
}

结果如下:

enter image description here

如何在不手动操作的情况下获得与其父级匹配的宽度(以确保它适用于任何大小的下拉列表?其次,是否有人知道让边框覆盖孩子的好方法?

1 个答案:

答案 0 :(得分:2)

快速说明:这是一个CSS问题,因此您的React逻辑只是任何愿意回答的人的障碍。我已根据您的描述将重要部分提取到下面没有React的工作代码段中。我建议撤销对你的问题背景不重要的任何事情,以鼓励更快速的答案。

  

如何在不手动操作的情况下获得与其父级匹配的宽度(以确保它适用于任何大小的下拉列表?

我认为你要找的主要内容是position: relative。因为绝对定位的元素大小和位置自己对抗第一​​个&#34;定位&#34;祖先。因此,您可以将其与topleftrightbottomwidth和/或height值相结合(以及可能是box-sizing: border-box;

  

...有没有人知道让边界覆盖孩子的好方法?

您可以通过将下拉菜单直接放在底部并在公共父级上切换类来隐藏/显示某些边框来伪造它。

以下是要演示的片段:

&#13;
&#13;
// 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')
  )
}
&#13;
.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;
}
&#13;
<!-- 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>
&#13;
&#13;
&#13;