使用flexbox的弹出菜单

问题描述 投票:0回答:3

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

红色框是一个弹性框。绿色框是 Flexbox 中的每个

<div>
元素。最右边的元素(标记为 3)有一个与其连接的单击事件。这个想法是,当单击该框时,会在其下方立即弹出一个菜单,但不在其中。

我尝试过使用 div 3 和 4 的绝对和相对定位,但没有任何组合能够实现我想要的效果。我能做的最好的事情就是在 div 4 上使用绝对定位。它按照预期与 div 3 分开弹出,但 div 4 的宽度不会比 div 3 更大,并且内容会换行。

我怎样才能在 div 4 中有一个弹出元素,它从自己的内容中获取宽度,并且不换行?

html css flexbox
3个回答
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>


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

label
checkbox

来完成

已更新

单击页面中的任意位置时

popup
会关闭(感谢我爱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>


3
投票

编辑2:使用此设置,您不需要在下拉菜单中硬编码任何

top
值,因此获得灵活性并保持与导航栏的对齐(即使在不同视口宽度上调整大小时)。

$(".item-red").on("click", function() {
  $(".item-dropdown").toggleClass("display");
});
.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;
}
<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>


2
投票

这是下拉菜单的正常行为,“菜单栏”项目的显示方式(Flex、框或表格)并不重要。条件是:

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

使用负边距,您可以将下拉菜单设置为大于父级。或者您甚至可以将它们设置为全页面大小并像超级菜单一样(记住它们是绝对定位的)。

这是一个例子:

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%;
}
<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>

至于您的要求:

从它自己的内容中获取宽度,并且不换行

通常,您将创建一个具有透明背景的“大型菜单”(全内容宽度)子菜单,并使用

float:right
flex
将内容放置为该大型菜单的子菜单。我假设您希望它最终在达到完整内容宽度时换行。示例:

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');
})
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;
  }
}
<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>

注意我在此代码段中添加了下拉菜单的点击切换功能。

© www.soinside.com 2019 - 2024. All rights reserved.