使用flexbox的弹出菜单

时间:2017-01-02 18:15:21

标签: html css flexbox

我正在尝试使用FlexBox构建标头组件。这是我想要实现的目标:

enter image description here

红色框是一个弹性框。绿色框是flexbox中的每个元素。最右边的元素(标记为3)有一个连接到它的点击事件。想法是当点击该框时,会在其下方弹出一个菜单,但不在其中。

我尝试过使用div 3和4的绝对和相对定位,但没有任何组合可以实现我正在寻找的东西。我能做的最好的就是在div 4上使用绝对定位。它会按照预期从div 3中弹出seperarte,但div 4的宽度不会比div 3大,而且内容会包含。

我怎样才能在div 4中有一个popup元素,它从自己的内容中获取宽度,并且不会包装?

3 个答案:

答案 0 :(得分:3)

假设您有一个如下所示的简单标记结构,那么使用绝对定位div

最有可能实现这一目标

这会在popup之外显示您的parent,同样的宽度/高度没有限制

我选择将popup放在3:rd div之外,因为它会为您提供更大的灵活性,根据响应性(不同的屏幕尺寸等)定位它。

基于脚本的版本

document.querySelector('.click').addEventListener('click', function(e){
  e.target.nextElementSibling.classList.toggle('clicked');
})
.parent {
  position: relative;
  display: flex;
  border: 1px solid red;
}
.parent div {
  flex: 2;
  border: 1px solid lime;
  margin: 1px;
}
.parent div:nth-child(2) {
  flex: 3;
}
.parent div:nth-child(3) {
  flex: 2;
}
.parent .popup {
  display: none;
  position: absolute;
  right: -2px;
  top: calc(100% + 3px);
  border: 1px solid blue;
}
.parent .popup.clicked {
  display: block;
}
<div class="parent">
  <div> 1 </div>
  <div> 2 </div>
  <div class="click"> 3 <br> (click to toggle) </div>
  <div class="popup"> This one can have text <br>
        that does pretty much what you want    
  </div>
</div>

这也可以在没有任何脚本的情况下完成,使用labelcheckbox

更新

点击页面中的任意位置时popup关闭(感谢I Love CSS

.parent {
  position: relative;
  display: flex;
  border: 1px solid red;
}
.parent div {
  flex: 2;
  border: 1px solid lime;
  margin: 1px;
}
.parent div:nth-child(2) {
  flex: 3;
}
.parent div:nth-child(3) {
  flex: 2;
}
.parent .popup {
  display: none;
  position: absolute;
  right: -2px;
  top: calc(100% + 3px);
  border: 1px solid blue;
}
.parent .modal {
  display: none;
  position: fixed;
  left: 0;
  top: 0;
  right: 0;
  bottom: 0;
  background: white;
  opacity: 0.3;
}
.parent .click label[for=chkbox] {
  display: block;  
}
#chkbox {
  display: none;
}
#chkbox:checked ~ .modal,
#chkbox:checked ~ .popup {
  display: block;
}
<div class="parent">
  <div> 1 </div>
  <div> 2 </div>
  <div class="click"><label for="chkbox"> 3 <br> (click to toggle) </label></div>
  <input type="checkbox" id="chkbox">
  <label class="modal" for="chkbox"></label>
  <div class="popup"> This one can have text <br>
        that does pretty much what you want    
  </div>
</div>

使用:focus

的另一个没有任何脚本的版本

更新

使用popup保持:hover持久,因此链接工作(感谢Andrei Gheorghiu

.parent {
  position: relative;
  display: flex;
  border: 1px solid red;
}
.parent div {
  flex: 2;
  border: 1px solid lime;
  margin: 1px;
}
.parent div:nth-child(2) {
  flex: 3;
}
.parent div:nth-child(3) {
  flex: 2;
}
.parent .popup {
  display: none;
  position: absolute;
  right: -2px;
  top: calc(100% + 3px);
  border: 1px solid blue;
}
.click:focus + .popup {
  display: block;
}
.click + .popup:hover {
  display: block;
}
<div class="parent">
  <div> 1 </div>
  <div> 2 </div>
  <div class="click" tabindex="-1"> 3 <br> (click to toggle) </div>
  <div class="popup"> This one can have text <br>
        that does pretty much what you want <br><br>
        <a href="#" onclick="alert('hey');">links included</a>
  </div>
</div>

答案 1 :(得分:2)

编辑2 :使用此设置,您无需在下拉列表中对任何top值进行硬编码,从而获得灵活性并保持与导航栏的对齐(即使在不同视口宽度上调整大小时也是如此) )。

&#13;
&#13;
$(".item-red").on("click", function() {
  $(".item-dropdown").toggleClass("display");
});
&#13;
.container {
    display: flex;
    flex-flow: row wrap;
    text-align: center;
}
.item {
    flex: 2;
    padding: 5px;
    margin: 0;
}
.item-blue {
    background: lightblue;
}

.item-green {
    background: lightgreen;
    flex: 3;
}
.item-red {
    background: lightgray;
    flex: 1;
}
.item-red:hover {
    cursor: pointer;
}
.container-dropdown {
    display: flex;
    flex-flow: row wrap;
    position: relative;
    text-align: center;
}
.item-dropdown {
    width: 240px;
    display: none;
    background: gold;
    position: absolute;
    right: 0;
    z-index: 1;
    padding: 5px;
}
.display {
    display: flex;
}
.content {
    text-align: center;
}
&#13;
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="container">
    <div class="item item-blue">Lorem</div>
    <div class="item item-green">Lorem ipsum dolor kjghj</div>
    <div class="item item-red">Lorem ipsum dolor
    </div>
</div>
<div class="container-dropdown">
    <div class="item-dropdown">Lorem ipsum dolor sit amet, consectetur adipisicing elit. Fuga voluptate, ipsum consequuntur maiores unde laboriosam suscipit velit corporis.</div>
</div>
<div class="content">Content - lorem ipsum dolor sit amet, consectetur adipisicing elit. Quibusdam delen iti soluta qui, incidunt, neque est doloribus esse deserunt modi, mollitia delectus illum! Ullam nihil reiciendis animi eligendi nemo non. Incidunt.</div>
&#13;
&#13;
&#13;

答案 2 :(得分:2)

这是下拉列表的正常行为,&#34;菜单栏&#34;&#34;显示项目(弹性,框或表格)。条件是:

  • 父级已position:relative;
  • 孩子有position:absolute; top: 100%;
  • 您是否希望孩子在hover上可见,或者父母是否已应用某个类,这是UI / UX和个人选择的问题。

使用负边距可以将下拉菜单设置为大于父级。或者你甚至可以使它们成为整页大小并且像大型菜单一样(记住它们绝对定位)。

以下是一个例子:

&#13;
&#13;
body {
  margin: 0;
  padding: 0;
  background-color: #f5f5f5;
}

.flex-menu {
  display: flex;
  background-color: white;
}
.flex-menu > * {
  position: relative;
  flex: 1 0 auto;
  padding: 10px;
  border-right: 1px solid #eee;
  cursor: pointer;
}
.flex-menu > *:last-child {
  border-right: none;
}
.flex-menu > * .submenu {
  position: absolute;
  top: 100%;
  left: 0;
  display: none;
  background-color: white;
  border-top: 1px solid #eee;
  padding: 10px;
  box-shadow: 0 1px 3px 0 rgba(0,0,0,.2), 0 1px 1px 0 rgba(0,0,0,.14), 0 2px 1px -1px rgba(0,0,0,.12)
}
.flex-menu .has-megamenu {
  position: static
}
.flex-menu > * .submenu.megamenu {
  width: 100vw;
  left: 0;
  top: 39px;
  box-sizing: border-box;
}
.flex-menu > *:hover .submenu {
  display: block;
}

.flex-menu > *:last-child .submenu {
  right: 0;
  margin-left: -100%;
}
&#13;
<div class="flex-menu">
  <div>first item</div>
  <div>second item
    <div class="submenu">
      This is a dropdopwn content.
    </div>
  </div>
  <div class="has-megamenu">third item
    <div class="submenu megamenu">
      This is a mega menu dropdopwn content. You can put anything here. A full page, of content, if you want
    </div>
  </div>
  <div>fourth item
    <div class="submenu">
      This is a dropdopwn content.
    </div>
  </div>
</div>
&#13;
&#13;
&#13;

至于你的要求:

  

从自己的内容中获取宽度,并且不包装

通常,您会创建一个&#34; mega-menu&#34; (全内容宽度)具有透明背景的孩子,您可以使用float:rightflex将内容作为此大型菜单的子项。我假设如果它达到全内容宽度,你希望它最终包装。例如:

&#13;
&#13;
var closeDrops = function(e) {
  $('.flex-menu div').removeClass('active');
}
$('body').on('click', closeDrops);

$('.flex-menu div').on('click', function(e){
  if (!$(this).hasClass('active')) {
    closeDrops();
  }
  e.stopPropagation();
  $(this).toggleClass('active');
})
&#13;
body {
  margin: 0;
  padding: 0;
  background-color: #f5f5f5;
  min-height: 100vh;
  font-family: sans-serif;
}

.flex-menu {
  display: flex;
  position: relative;
}
.flex-menu > * {
  position: relative;
  flex: 1 0 auto;
  padding: 10px;
  border: solid white;
  border-width: 0 1px 1px 0;  
  cursor: pointer;
  transition: background-color .3s ease-in-out;
}
.flex-menu > *:last-child {
  border-right: none;
}
.flex-menu > * .submenu {
  position: absolute;
  top: 100%;
  left: 0;
  display: none;
  background-color: white;
  border-top: 1px solid #eee;
  padding: 10px;
  box-shadow: 0 1px 3px 0 rgba(0,0,0,.2), 0 1px 1px 0 rgba(0,0,0,.14), 0 2px 1px -1px rgba(0,0,0,.12)
}
.flex-menu .has-megamenu {
  position: static
}
.flex-menu > * .submenu.megamenu {
  width: 100vw;
  left: 0;
  box-sizing: border-box;
}
.flex-menu > *:hover .submenu,.flex-menu > *.active .submenu  {
  display: block;
}
.flex-menu > *.active, .flex-menu > *:hover {
  box-shadow: 0 1px 3px 0 rgba(0,0,0,.2), 0 1px 1px 0 rgba(0,0,0,.14), 0 2px 1px -1px rgba(0,0,0,.12);
  background-color: white;
}
.flex-menu > *.active{
  z-index: 1;
  
}
.flex-menu > *:hover {
  z-index: 2;
}
.has-megamenu:last-child .megamenu{
  background-color: transparent; padding: 0;
  box-shadow: none;
}
.has-megamenu:last-child .megamenu > * {
  box-shadow: 0 1px 3px 0 rgba(0,0,0,.2), 0 1px 1px 0 rgba(0,0,0,.14), 0 2px 1px -1px rgba(0,0,0,.12);
}
.placed-right {
  background-color: white;
  padding:10px;
  float: right;
}
@media (max-width: 500px) {
  .flex-menu {
    flex-direction: column;
  }
  .flex-menu > * .submenu {
    width: 100vw;
    box-sizing: border-box;
  }
  .placed-right { 
    float: none;
    width: 100%;
    display: block;
    box-sizing: border-box;
  }
  .flex-menu .has-megamenu {
    position: relative;
  }
}
&#13;
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="flex-menu">
  <div>first item</div>
  <div>second item
    <div class="submenu">
      This is a dropdopwn content.
    </div>
  </div>
  <div class="has-megamenu">third item
    <div class="submenu megamenu">
      This is a mega menu dropdopwn content. You can put anything here. A full page, of content, if you want
    </div>
  </div>
  <div class="has-megamenu">fourth item
    <div class="submenu megamenu">
      <span class="placed-right">
        I am right-aligned and I don't care about my parent's width, ok? <hr />I'll only wrap when I don't fit in page.
      </span>
    </div>
  </div>
</div>
&#13;
&#13;
&#13;

注意我在此代码段中为下拉列表添加了点击切换。