【问题标题】:Why can't an <ul> (with absolute position) inside a <li> (with relative position) auto size?为什么 <li> (具有相对位置)内的 <ul> (具有绝对位置)不能自动调整大小?
【发布时间】:2016-06-28 22:44:49
【问题描述】:

编辑:另见下面我自己的答案(2016 年)


例如:

<ul>
    <li class="first"><a href="#" title="">Home</a></li>
    <li><a href="#" title="">Chi siamo</a>
       <ul><li><a href="#" title="">item1</a></li><li><a href="#" title="">item2</a></li></ul>
    </li>
    <li><a href="#" title="">Novità</a></li>
    <li><a href="#" title="">Promozioni</a></li>
</ul>

然后样式化:

/* level 1 Main menu ----------------------------------------- */

#main-menu > ul{ list-style:none; }

#main-menu > ul > li{
    float:left;
    display:block;
    position:relative;
    margin-left:1em;
}

#main-menu > ul > li.first{
    margin-left:0;
}


/* sub Main menu ----------------------------------------- */

#main-menu > ul > li ul {
    position: absolute;
    z-index:1000;
    display:none;
    left:0;
    top:28px;
}

#main-menu > ul > li:hover ul {
    display:inline-block;
}

#main-menu > ul > li ul li{
    float:left;
    display:block;
    list-style:none;
}

好的。所以,我有水平显示的主菜单。我还希望子菜单显示水平。但是由于某种原因,ul 框没有调整大小以达到 li 标签的总宽度,因此它保持垂直。父 ul 不会遇到这个问题。 我可以通过简单地为子 ul 添加适当的宽度来使其工作,但这不是我想要使用的方式。

有什么想法吗?

【问题讨论】:

  • 我建议使用 id 和 class 选择器而不是 'ul > li ul' 或 '#main-menu > ul > li ul li'

标签: css html-lists


【解决方案1】:

如果您使用绝对位置,请务必使用两次:hover;第一个在li 上触发display: block,然后在ul 上显示在触发器上。
然后将定位和样式分开:我设置了a 而不是li

请看这里: http://jsfiddle.net/HerrSerker/T8x2r/2/

#main-menu > ul > li > ul:hover,
#main-menu > ul > li:hover > ul {
    display: block;
}

也应该使用float:left http://jsfiddle.net/T8x2r/3/

【讨论】:

  • 我很难理解这是如何工作的,但在进一步调查中,不提供顶部/左侧似乎是关键?
  • 了解定位的关键:如果省略垂直(top/bottom)或水平(left/right)定位值并使用position: absolute,则元素将显示在没有绝对位置的位置,同时仍然不影响外部元素的布局。
  • 啊,所以默认为“自动”。在我 11 年的网络开发生涯中,我真的从来不知道这一点 - 谢谢!
【解决方案2】:

带有position: absolute 的元素占据其子元素的大小。

您可以在 ul 上设置width: 100%;,或者设置left: 0; right: 0;,这也会将其拉伸到正确的大小。

您可能还想在嵌套的 UL 以及顶部设置 list-style:none;

【讨论】:

  • 嗨。对不起,但这对我不起作用。关键问题是我希望嵌套的 LI 向左浮动。它们不会浮动,因为 UL 不够大。它确实占用了较大 LI 的空间,但不是所有 LI 占用的总空间。 :(
  • 这时需要一个测试页
【解决方案3】:

对于建议您使用 ids 和 classes 的人,除了可能第一个 ul 被 id'ed 为“菜单”之外,没有必要。我这样说是因为您要寻找的是非常严格和结构化的。

据我了解,您正在尝试完成以下操作:获取一个水平主菜单,当将鼠标悬停在主菜单“链接”上时,该菜单在下方显示另一个水平子菜单

如下图:

----------------------------------------------------------------------
Menu-Item 1    |    Menu Item 2 (hovered over)    |    Menu Item 3    
----------------------------------------------------------------------
               |    Sub Menu 1    |    Sub Menu 2    |    Sub Menu 3
               -------------------------------------------------------

现在我没有人告诉你如何设计你的菜单。但正如你现在所看到的,我什至不确定它应该如何工作。第二个菜单是否应该左对齐到它悬停的主菜单项的最左边?或者第二个菜单是否应该与整个菜单左对齐,一直到左边?

如果是第一个,最后一个菜单项的空间太小,无法在下面有链接(最多一个或两个),如果是第二个版本,那么人们会因为他们不断“丢失”子菜单而感到沮丧当将鼠标悬停在最后一个菜单项上时(在我们的示例中:菜单项 3)试图访问一直到左侧的链接时。相信我,大多数用户都不太擅长鼠标,相信我,第一个版本看起来很糟糕。

因此,当主菜单是水平的时,人们会使用垂直的子菜单,但同样,我不会质疑你的动机。我会尽量以最好的方式回答你的问题,这将是第二种方式,设置如下:

----------------------------------------------------------------------
Menu-Item 1    |    Menu Item 2 (hovered over)    |    Menu Item 3    
----------------------------------------------------------------------
Sub Menu 1    |    Sub Menu 2    |    Sub Menu 3    |      (blank)    
----------------------------------------------------------------------

首先,您的代码甚至没有设置成这样。您的代码当前的编写方式最终会像我向您展示的第一个示例一样(正如我所解释的,如果您的菜单占据了页面的宽度,那么最后一个菜单项将只有很少的水平空间来显示内容当然)

所以要实现这个目标,你必须摆脱你的 li 的相对定位。如果出于某种原因必须将其设置为相对的另一个想法是将主菜单的每个 li 设置为不同的 z-index 并将它们设置为左边距/填充以及右边距/填充以“适合”整个菜单。我发现这是一个“黑客”,宁愿省略你的 li 的相对定位。

绝对 ul 嵌套在你的相对对象下面(不管是什么,在这种情况下它是菜单

  • ) 只能占用您指定的空间。在这种情况下,100% 只是它嵌套在下面的 li 的大小。您可以将其设置为大于 100% 的值,例如 500 像素,但这会导致问题有两个原因:1) 您将无法将所有子菜单设置为您可能希望的左侧绝对菜单,因为嵌套元素的绝对左侧只会是它嵌套在下面的 li 的最左边。 2) 这不好,因为最右边的菜单的子项会漂移到整个菜单的右侧。

    如果您必须保持主菜单的相对位置,则必须手动单独设置每个嵌套 ul 的左侧位置。对于除第一个之外的所有浏览器,这将是一个负数,并且不是一门精确的科学,因为所有浏览器都不显示相同的字体(因此会导致菜单项的宽度略有变化,为了解决这个问题,你会需要在所有年龄段的所有浏览器中使用完美宽度的图像)。但这分散了 CSS 的美感,即使用几行代码来设计多个元素。

    从主菜单 li (#main-menu > ul > li) 中删除“相对”定位并为其添加一些底部填充会容易得多,否则您将永远无法将鼠标悬停在子菜单,每次它都会消失。如果我不得不猜测你在做什么并且我正在编写 CSS/HTML,我会这样做:

    HTML:

      <li>A
        <ul>
          <li>A1<li>
          <li>A2<li>
          <li>A3<li>
        </ul>
      </li>
    
      <li>B
        <ul>
          <li>B1<li>
          <li>B2<li>
          <li>B3<li>
        </ul>
      </li>
    
      <li>C
        <ul>
          <li>C1<li>
          <li>C2<li>
          <li>C3<li>
        </ul>
      </li>
    
    </ul>
    

    CSS:

    ul#main-menu{ list-style:none;}
    
    ul#main-menu > li {
      float: left;
      margin-left: 1em;
      padding-bottom: 3em; /*make this the line-height space underneat the main menu, plus the heigh of the secondary menu, plus the extra space you wanna give the user to not lose focus on the second menu*/
    } 
    ul#main-menu > li:first-child {margin-left: 0;}
    
    ul#main-menu > li > ul {
      display: none;
    }
    ul#main-menu > li:hover > ul {
      position: absolute;
      display: block;
      left: 0;
      list-style: none;
    }
    
    ul#main-menu > li:hover > ul > li,
    ul#main-menu > li > ul:hover > li {
      position: relative;
      float: left;
      margin-left: 1em;
    } 
    ul#main-menu > li:hover > ul > li:first-child,
    ul#main-menu > li > ul:hover > li:first-child {margin-left: 0px}
    

    我已经在自己的浏览器上对此进行了测试,它似乎可以按照您的意愿工作。到现在为止,您应该知道其他两种方法来实现这一点,但结果各不相同,工作量也比这个版本多。

  • 【讨论】:

    • 另外,bazmegakapa 也不正确。将嵌套在相对 li 下的绝对 ul 的宽度设置为 100% 只会占用它上面的父元素加上它下面的 li 元素的空间。然后 li 也将被抵消。您可以通过将主菜单 li 下的 ul 下的嵌套 li 的背景设置为 #eee 或其他内容来轻松测试这一点。在页面上测试它
    • 另外,我不太确定您要构建什么。如果您打算将主菜单
    • 设置得如此宽,以便在其下方容纳多个
    • ,那么您已经走在正确的轨道上。您所要做的就是手动设置该 li 下面的 ul 的宽度(以像素为单位)(出于某种原因,您说过您不想这样做)
  • Alexei Ivanov 似乎也已经为您解决了这个问题。当你有一个可行的解决方案时,我为什么要写这一切? FML。
  • 【解决方案4】:

    好吧,如果您确定项目总是在一行中,您可以移动“位置:相对;”到父 ul,并删除 "left: 0;"从第二个 ul 开始,它会做你想做的事,但如果行尾有很多项目,它们将被裁剪。

    示例:http://jsfiddle.net/ed9Wx/

    【讨论】:

      【解决方案5】:

      既然您在代码中说明了这一点 #main-menu > ul > li:hover ul { display:inline-block; } 最好是display: block; margin: auto; 这样它就可以完全覆盖 li 标签

      #main-menu > ul > li:hover ul {
      display:block; }
      
      #main-menu > ul > li ul li{
      float:left;
      margin: auto; 
      list-style:none;}
      

      这应该可以解决问题。

      【讨论】:

        【解决方案6】:

        有一件愚蠢的事情:在子菜单上,您可以通过简单地强制空格来强制 sumbenus 到内部项目宽度:内部项目上的 no-wrap。尽管您使用了任何技术或布局,它仍然有效 -- 带有显示的主要 LI 项目:inline-block 或现代 flex 布局 // 对于 subs,常规显示无/块或现代 css3 fx 解决方案 - 没关系。一个原始的例子可能就是这样,在这种情况下使用 flexbox 和淡入/淡出 fx 用于 subs(但可以是更简单的 no-flexbox 或更旧的,这真的没关系):

        .main-menu{ // ul
          display: flex;
          flex-wrap: nowrap;
        
          > li{
            display: inline-block;
            flex: 1;
            position: relative;
        
            &:hover{
              .sub-menu{
                visibility: visible;
                opacity: 1;
                transition: opacity 200ms linear;
              }
            }
        
            .sub-menu{
              display: inline-block;
              position: absolute;
              top: 50px;
              left:0;
        
              visibility: hidden;
              opacity: 0;
              transition: visibility 0s 200ms, opacity 200ms linear;
        
              li{
                a{
                  white-space: nowrap; // <<< THIS IS THE KEY!
                }
              }
            } // sub-menu
        
          } // > li
        }
        

        【讨论】:

          猜你喜欢
          相关资源
          最近更新 更多
          热门标签