开发者

set all nested li's to be width of widest li

How do I make nested li's the same width?

When I use the below code each nested li is only as wide as it's text + margin.

I'd like all of the li's to be as wide as the widest li under the parent ul.

eg:

<ul id="menu">
    <li <a href="#" title="Menu a">Menu a</a></li>
    <li <a href="#" title="Menu b">Menu b</a></li>
    <li <a href="#" title="Nested Menu">Nested Menu</a>开发者_JS百科;
        <ul>
            <li <a href="#" title="Menu Item">Menu Item</li>
            <li <a href="#" title="Long Menu Item">Long Menu Item</a></li>
            <li <a href="#" title="Longer Menu Item">Longer Menu Item</a></li>
        </ul>
    </li>
    <li <a href="#" title="Menu z">Menu z</a></li>
</ul>

with css:

<style type="text/css" media="all">
* {
    padding:0; 
    margin:0;
}
body, html {
    width: 100%;
    height: 100%;
}
#wrapper {
    width: 800px;
    height: 100%;
    margin: auto;
}
#menu {
    margin: 0 0 0 8px; 
    padding: 0;
    font-size: 14px; 
    font-weight: normal;
}

#menu ul {
    list-style-type:none; 
    list-style-position:outside; 
    position:relative; 
    z-index:300; 
    height: 32px;
    font-weight:bold; 
    white-space: nowrap;
    padding:0;
} 
#menu a {text-decoration:none; 
    line-height: 32px;
} 
#menu a:hover {

} 
#menu li {
    float:left; 
    position:relative; 
    display: inline; 
    height: 100%; 
    list-style-type: none; 
    padding: 0 20px;
    background: #ccc;
} 
#menu ul {
    position:absolute; 
    display:none; 
    left:0px;
    background: #BDCCD4;
    width:100%;
} 
#menu ul a, #menu li a {
    display: block;
}
#menu li ul {
    background: #BDCCD4;
    display:block;
}
#menu li ul a {
    font-weight: normal;
    height:auto; 
    float:left;
} 
#menu ul ul {
    padding: 0 9px;
    display:block;
} 
#menu li ul li {
    padding: 0 9px;
    background: #BDCCD4;
}
#menu li:hover {
    background: #ddd;
    height: 32px;
}
#menu li li:hover, #menu li li li:hover {
    background: #ddd;
    height: 32px;
}
#menu li a:link, #menu li a:visited {
    text-decoration: none;
    color: #003E7E;
    margin: auto;
}


Simply adding width: 100% for #menu li ul li works for me. To make it work for even longer items, use width: auto on #menu li ul. EDIT 2: Added padding workaround.

The new CSS:

<style type="text/css" media="all">
* {
    padding:0;
    margin:0;
}
body, html {
    width: 100%;
    height: 100%;
}
#wrapper {
    width: 800px;
    height: 100%;
    margin: auto;
}
#menu {
    margin: 0 0 0 8px;
    padding: 0;
    font-size: 14px;
    font-weight: normal;
}

#menu ul {
    list-style-type:none;
    list-style-position:outside;
    position:relative;
    z-index:300;
    height: 32px;
    font-weight:bold;
    white-space: nowrap;
    padding:0;
}
#menu a {text-decoration:none;
    line-height: 32px;
}
#menu a:hover {

}
#menu li {
    float:left;
    position:relative;
    display: inline;
    height: 100%;
    list-style-type: none;
    padding: 0 20px;
    background: #ccc;
}
#menu ul {
    position:absolute;
    display:none;
    left:0px;
    background: #BDCCD4;
    width:100%;
}
#menu ul a, #menu li a {
    display: block;
}
#menu li ul {
    background: #BDCCD4;
    display:block;
    width: auto;
}
#menu li ul a {
    font-weight: normal;
    height:auto;
    float:left;
}
#menu ul ul {
    padding: 0 0 0 9px;
    display:block;
}
#menu li ul li {
    padding: 0 9px;
    background: #BDCCD4;
    width: 100%;
}
#menu li:hover {
    background: #ddd;
    height: 32px;
}
#menu li li:hover, #menu li li li:hover {
    background: #ddd;
    height: 32px;
}
#menu li a:link, #menu li a:visited {
    text-decoration: none;
    color: #003E7E;
    margin: auto;
}

The result is here: http://jsfiddle.net/y83zm/2/ EDIT 2 Added fix to solve a weird padding issue, see http://jsfiddle.net/y83zm/5/


You'll need to use JavaScript to set all LIs the same width as the widest LI. Here's the code if you want to use the jQuery library:

$(document).ready(function(){
  $("#menu > li > ul").each(function() { // Loop through all the menu items that got submenu items
    var Widest=0; // We want to find the widest LI... start at zero
    var ThisWidth=0; // Initiate the temporary width variable (it will hold the width as an integer)

    $($(this).children()).each(function() { // Loop through all the children LIs in order to find the widest
      ThisWidth=parseInt($(this).css('width')); // Grab the width of the current LI

      if (ThisWidth>Widest) { // Is this LI the widest?
        Widest=ThisWidth; // We got a new widest value
      }
    });

    Widest+='px'; // Add the unit

    $(this).parent().css('width',Widest);
    $(this).children().css('width',Widest);
  });
});

CSS change:

#menu li ul li {
  padding: 0 9px;
  background: #BDCCD4;
  padding: 0 20px;
}

Check it out at JSFiddle.

Edit: Fixed my misunderstanding. :)


There would be a very simple dynamic solution. To your CSS, as you posted it in the Question, just add

#menu ul {
    display: inline-block;
    min-width: 100px;
}

#menu ul li, #menu ul li a{
    width: 100%;
    display:block;
}

and then it will be exactly as you want it to be.

You can see how it looks here:

<style type="text/css" media="all">
* {
    padding:0; 
    margin:0;
}
body, html {
    width: 100%;
    height: 100%;
}
#wrapper {
    width: 800px;
    height: 100%;
    margin: auto;
}
#menu {
    margin: 0 0 0 8px; 
    padding: 0;
    font-size: 14px; 
    font-weight: normal;
}

#menu ul {
    list-style-type:none; 
    list-style-position:outside; 
    position:relative; 
    z-index:300; 
    height: 32px;
    font-weight:bold; 
    white-space: nowrap;
    padding:0;
} 
#menu a {text-decoration:none; 
    line-height: 32px;
} 
#menu a:hover {

} 
#menu li {
    float:left; 
    position:relative; 
    display: inline; 
    height: 100%; 
    list-style-type: none; 
    padding: 0 20px;
    background: #ccc;
} 
#menu ul {
    position:absolute; 
    display:none; 
    left:0px;
    background: #BDCCD4;
    width:100%;
} 
#menu ul a, #menu li a {
    display: block;
}
#menu li ul {
    background: #BDCCD4;
    display:block;
}
#menu li ul a {
    font-weight: normal;
    height:auto; 
    float:left;
} 
#menu ul ul {
    padding: 0 9px;
    display:block;
} 
#menu li ul li {
    padding: 0 9px;
    background: #BDCCD4;
}
#menu li:hover {
    background: #ddd;
    height: 32px;
}
#menu li li:hover, #menu li li li:hover {
    background: #ddd;
    height: 32px;
}
#menu li a:link, #menu li a:visited {
    text-decoration: none;
    color: #003E7E;
    margin: auto;
}

#menu ul {
    display: inline-block;
    min-width: 100px;
}

#menu ul li, #menu ul li a{
    width: 100%;
    display:block;
}
<ul id="menu">
    <li <a href="#" title="Menu a">Menu a</a></li>
    <li <a href="#" title="Menu b">Menu b</a></li>
    <li <a href="#" title="Nested Menu">Nested Menu</a>
        <ul>
            <li <a href="#" title="Menu Item">Menu Item</li>
            <li <a href="#" title="Long Menu Item">Long Menu Item</a></li>
            <li <a href="#" title="Longer Menu Item">Longer Menu Item</a></li>
        </ul>
    </li>
    <li <a href="#" title="Menu z">Menu z</a></li>
</ul>


To make all of the list items the same length as the longest, you will need to manually set the widths. There is no pure CSS method of achieving this automatically as far as I know.

li{width:100%} Will make the list items fill the width of their container. If that is not set, then it will be the width of the user's browser window.


A simple jQuery solution worked for me:

$(document).ready(function(){
    $('.sub-menu').each(function(){
        $(this).width(2000);
        var width = 0;
        $(this).children('li').each(function(){
            if ($(this).children('a').width() > width)
                width = $(this).children('a').width();
        });
        $(this).width(width);
    });
});


I used following CoffeeScript to achieve described behavior:

$ ->
    menu_toggle = (e, show) ->
        ul = $(e).find('ul')
        ul.toggle()

        computed = ul.hasClass 'computed_width'
        if show && !computed
            ul.width 2000 # enormous with to be sure that li’s’ texts are not wrapped
            max_width = 0
            ul.find('li').each ->
                li = $(this)
                width = li.width()
                max_width = width if width > max_width
            ul.width max_width + 30 if max_width # 20 is 2 * padding + some reserve
            ul.toggleClass 'computed_width' # no need to compute every time

    $('li').has('ul').hover ->
        menu_toggle this, true
    , ->
        menu_toggle this, false
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜