Comment justifier un menu horizontal en HTML+CSS ?

vous trouverez beaucoup de tutoriels sur les barres de menu en HTML, mais pour ce cas spécifique (bien que Générique IMHO), Je n'ai pas trouvé de solution décente:

#  THE MENU ITEMS    SHOULD BE    JUSTIFIED     JUST AS    PLAIN TEXT     WOULD BE  #
#  ^                                                                             ^  #
  • il y a un nombre variable d'éléments de menu textuels et la mise en page est fluide.
  • le premier élément du menu doit être aligné à gauche, le dernier élément du menu doit être aligné à droite.
  • les autres éléments doivent être répartis de manière optimale sur la barre de menu.
  • le nombre varie,donc il n'y a aucune chance de pré-calculer les largeurs optimales.

notez qu'une TABLE ne fonctionnera pas ici aussi bien:

  • si vous centrez tous les TDs, le premier et le dernier élément ne sont pas alignés correctement.
  • si vous alignez à gauche et à droite la première réponse. le dernier élément, l'espacement entre sous-optimales.

n'est-il pas étrange qu'il n'y a-t-il pas une façon évidente de mettre en œuvre ceci d'une manière propre en utilisant HTML et CSS?

84
demandé sur Paul D. Waite 2008-09-08 15:57:08

13 réponses

Approche Moderne - Flexboxes !

maintenant que CSS3 flexboxes ont meilleure prise en charge du navigateur , certains d'entre nous peuvent enfin commencer à les utiliser. Il suffit d'ajouter des préfixes supplémentaires de fournisseur pour plus de couverture de navigateur .

dans ce cas, vous définissez simplement l'élément parent display à flex et puis vous changez le justify-content biens à space-between ou space-around afin d'ajouter de l'espace entre ou autour des éléments de flexbox enfants.

utilisant justify-content: space-between - ( exemple ici) :

ul {
    list-style: none;
    padding: 0;
    margin: 0;
}
.menu {
    display: flex;
    justify-content: space-between;
}
<ul class="menu">
    <li>Item One</li>
    <li>Item Two</li>
    <li>Item Three Longer</li>
    <li>Item Four</li>
</ul>

à l'Aide de justify-content: space-around - (exemple ici) :

ul {
    list-style: none;
    padding: 0;
    margin: 0;
}
.menu {
    display: flex;
    justify-content: space-around;
}
<ul class="menu">
    <li>Item One</li>
    <li>Item Two</li>
    <li>Item Three Longer</li>
    <li>Item Four</li>
</ul>
41
répondu Josh Crozier 2015-03-26 02:27:24

la chose la plus simple à faire est de forcer la ligne à se casser en insérant un élément à la fin de la ligne qui occupera plus que l'espace disponible gauche et puis le cacher. Je l'ai accompli assez facilement avec un simple span élément comme cela:

#menu {
  text-align: justify;
}

#menu * {
  display: inline;
}

#menu li {
  display: inline-block;
}

#menu span {
  display: inline-block;
  position: relative;
  width: 100%;
  height: 0;
}
<div id="menu">
  <ul>
    <li><a href="#">Menu item 1</a></li>
    <li><a href="#">Menu item 3</a></li>
    <li><a href="#">Menu item 2</a></li>
  </ul>
  <span></span>
</div>

tout le matériel à l'intérieur du sélecteur #menu span est (autant que j'ai trouvé) nécessaire pour plaire à la plupart des navigateurs. Il devrait forcer la largeur de l'élément span à 100%, ce qui devrait causer un bris de ligne puisqu'il est considéré comme un élément en ligne en raison de la règle display: inline-block . inline-block rend également le span possible de bloquer des règles de style comme width qui fait que l'élément ne rentre pas dans la ligne avec le menu et donc le menu à line-break.

vous devez bien sûr ajuster la largeur du span à votre cas d'utilisation et de la conception, mais j'espère que vous avez l'idée générale et peut l'adapter.

83
répondu Asbjørn Ulsberg 2016-12-03 18:47:10

Ok, Cette solution ne fonctionne pas sur IE6 / 7, en raison du manque de soutien de :before / :after , mais:

ul {
  text-align: justify;
  list-style: none;
  list-style-image: none;
  margin: 0;
  padding: 0;
}
ul:after {
  content: "";
  margin-left: 100%;
}
li {
  display: inline;
}
a {
  display: inline-block;
}
<div id="menu">
  <ul>
    <li><a href="#">Menu item 1</a></li>
    <li><a href="#">Menu item 2</a></li>
    <li><a href="#">Menu item 3</a></li>
    <li><a href="#">Menu item 4</a></li>
    <li><a href="#">Menu item 5</a></li>
  </ul>
</div>

la raison pour laquelle j'ai l'étiquette a comme inline-block est parce que je ne veux pas que les mots à l'intérieur soient justifiés aussi bien, et je ne veux pas utiliser des espaces non-cassants non plus.

12
répondu remitbri 2016-12-03 18:48:22

a une solution. Fonctionne en FF, IE6, IE7, Webkit,etc.

assurez-vous de ne pas mettre de blanc avant de fermer le span.inner . IE6 va craquer.

vous pouvez donner optionnellement .outer une largeur

.outer {
  text-align: justify;
}
.outer span.finish {
  display: inline-block;
  width: 100%;
}
.outer span.inner {
  display: inline-block;
  white-space: nowrap;
}
<div class="outer">
  <span class="inner">THE MENU ITEMS</span>
  <span class="inner">SHOULD BE</span>
  <span class="inner">JUSTIFIED</span>
  <span class="inner">JUST AS</span>
  <span class="inner">PLAIN TEXT</span>
  <span class="inner">WOULD BE</span>
  <span class="finish"></span>
</div>
8
répondu mikelikespie 2016-12-03 18:50:25

Fonctionne avec Opera , Firefox, Chrome et IE

ul {
   display: table;
   margin: 1em auto 0;
   padding: 0;
   text-align: center;
   width: 90%;
}

li {
   display: table-cell;
   border: 1px solid black;
   padding: 0 5px;
}
4
répondu Szajba 2012-07-30 15:15:18

encore une autre solution. Je n'avais pas le choix d'aborder le html comme l'ajout de classe distinguée, etc. donc j'ai trouvé un moyen CSS pur.

Fonctionne dans Chrome, Firefox, Safari..ne sais pas sur IE.

essai: http://jsfiddle.net/c2crP/1

ul {
  margin: 0; 
  padding: 0; 
  list-style: none; 
  width: 200px; 
  text-align: justify; 
  list-style-type: none;
}
ul > li {
  display: inline; 
  text-align: justify; 
}

/* declaration below will add a whitespace after every li. This is for one line codes where no whitespace (of breaks) are present and the browser wouldn't know where to make a break. */
ul > li:after {
  content: ' '; 
  display: inline;
}

/* notice the 'inline-block'! Otherwise won't work for webkit which puts after pseudo el inside of it's parent instead of after thus shifting also the parent on next line! */
ul > li:last-child:after {
  display: inline-block;
  margin-left: 100%; 
  content: ' ';
}
<ul>
  <li><a href="#">home</a></li>
  <li><a href="#">exposities</a></li>
  <li><a href="#">werk</a></li>
  <li><a href="#">statement</a></li>
  <li><a href="#">contact</a></li>
</ul>
3
répondu bash2day 2016-12-03 18:52:55

en faire un <p> avec text-align: justify ?

Mise À Jour : Nevermind. Qui ne fonctionne pas du tout comme je l'avais pensé.

mise à jour 2 : ne fonctionne pas dans les navigateurs autres que IE en ce moment, mais CSS3 a le support pour cela sous la forme de text-align-last

2
répondu Jordi Bunster 2008-09-08 12:14:43

pour les navigateurs basés sur Gecko, j'ai trouvé cette solution. Cette solution ne fonctionne pas avec les navigateurs WebKit, cependant (par exemple Chromium, Midori, Epiphany), ils affichent toujours l'espace de fuite après le dernier élément.

j'ai mis la barre de menu dans un paragraphe justifié . Le problème est que la dernière ligne d'un paragraphe justifié ne sera pas rendu justifié, pour des raisons évidentes. Par conséquent, j'ajoute un large élément invisible (par exemple un img) qui justifie que le le paragraphe fait au moins deux lignes.

maintenant la barre de menu est justifiée par le même algorithme que le navigateur utilise pour justifier le texte simple.

Code:

<div style="width:500px; background:#eee;">
 <p style="text-align:justify">
  <a href="#">THE&nbsp;MENU&nbsp;ITEMS</a>
  <a href="#">SHOULD&nbsp;BE</a>
  <a href="#">JUSTIFIED</a>
  <a href="#">JUST&nbsp;AS</a>
  <a href="#">PLAIN&nbsp;TEXT</a>
  <a href="#">WOULD&nbsp;BE</a>
  <img src="/Content/Img/stackoverflow-logo-250.png" width="400" height="0"/>
 </p>
 <p>There's an varying number of text-only menu items and the page layout is fluid.</p>
 <p>The first menu item should be left-aligned, the last menu item should be right-aligned. The remaining items should be spread optimal on the menu bar.</p>
 <p>The number is varying,so there's no chance to pre-calculate the optimal widths.</p>
 <p>Note that a TABLE won't work here as well:</p>
 <ul>
  <li>If you center all TDs, the first and the last item aren't aligned correctly.</li>
  <li>If you left-align and right-align the first resp. the last items, the spacing will be sub-optimal.</li>
 </ul>
</div>

Remarque: avez-vous remarqué que j'ai triché? Pour ajouter l'élément de remplissage d'espace, je dois faire quelques suppositions sur la largeur de la barre de menu. Donc cette solution n'est pas complètement les règles.

1
répondu flight 2010-04-07 11:02:12
Le texte

n'est justifié que si la phrase provoque naturellement un saut de ligne. Donc tout ce que vous devez faire est naturellement forcer une rupture de ligne, et cacher ce qui est sur la deuxième ligne:

CSS:

ul {
  text-align: justify;
  width: 400px;
  margin: 0;
  padding: 0;
  height: 1.2em;
  /* forces the height of the ul to one line */
  overflow: hidden;
  /* enforces the single line height */
  list-style-type: none;
  background-color: yellow;
}

ul li {
  display: inline;
}

ul li.break {
  margin-left: 100%;
  /* use e.g. 1000px if your ul has no width */
}

HTML:

<ul>
  <li><a href="/">The</a></li>
  <li><a href="/">quick</a></li>
  <li><a href="/">brown</a></li>
  <li><a href="/">fox</a></li>
  <li class="break">&nbsp;</li>
</ul>

The li.l'élément break doit être sur la même ligne que le dernier élément du menu et doit contenir du contenu (dans ce cas un espace non-break), sinon dans certains navigateurs, si ce n'est pas sur la même ligne, alors vous verrez un petit espace supplémentaire à la fin de votre ligne, et si elle ne contient pas de contenu, alors elle est ignorée et la ligne n'est pas justifiée.

testé en IE7, IE8, IE9, Chrome, Firefox 4.

1
répondu Diaren W 2016-02-16 00:38:14

pour aller avec le javascript qui est possible (ce script est basé sur mootools)

<script type="text/javascript">//<![CDATA[
    window.addEvent('load', function(){
        var mncontainer = $('main-menu');
        var mncw = mncontainer.getSize().size.x;
        var mnul = mncontainer.getFirst();//UL
        var mnuw = mnul.getSize().size.x;
        var wdif = mncw - mnuw;
        var list = mnul.getChildren(); //get all list items
        //get the remained width (which can be positive or negative)
        //and devided by number of list item and also take out the precision
        var liwd = Math.floor(wdif/list.length);
        var selw, mwd=mncw, tliw=0;
        list.each(function(el){
            var elw = el.getSize().size.x;
            if(elw < mwd){ mwd = elw; selw = el;}
            el.setStyle('width', elw+liwd);
            tliw += el.getSize().size.x;
        });
        var rwidth = mncw-tliw;//get the remain width and set it to item which has smallest width
        if(rwidth>0){
            elw = selw.getSize().size.x;
            selw.setStyle('width', elw+rwidth);
        }
    });
    //]]>
</script>

et le css

<style type="text/css">
    #main-menu{
        padding-top:41px;
        width:100%;
        overflow:hidden;
        position:relative;
    }
    ul.menu_tab{
        padding-top:1px;
        height:38px;
        clear:left;
        float:left;
        list-style:none;
        margin:0;
        padding:0;
        position:relative;
        left:50%;
        text-align:center;
    }
    ul.menu_tab li{
        display:block;
        float:left;
        list-style:none;
        margin:0;
        padding:0;
        position:relative;
        right:50%;
    }
    ul.menu_tab li.item7{
        margin-right:0;
    }
    ul.menu_tab li a, ul.menu_tab li a:visited{
        display:block;
        color:#006A71;
        font-weight:700;
        text-decoration:none;
        padding:0 0 0 10px;
    }
    ul.menu_tab li a span{
        display:block;
        padding:12px 10px 8px 0;
    }
    ul.menu_tab li.active a, ul.menu_tab li a:hover{
        background:url("../images/bg-menutab.gif") repeat-x left top;
        color:#999999;
    }
    ul.menu_tab li.active a span,ul.menu_tab li.active a.visited span, ul.menu_tab li a:hover span{
        background:url("../images/bg-menutab.gif") repeat-x right top;
        color:#999999;
    }
</style>

et le dernier html

<div id="main-menu">
    <ul class="menu_tab">
        <li class="item1"><a href="#"><span>Home</span></a></li>
        <li class="item2"><a href="#"><span>The Project</span></a></li>
        <li class="item3"><a href="#"><span>About Grants</span></a></li>
        <li class="item4"><a href="#"><span>Partners</span></a></li>
        <li class="item5"><a href="#"><span>Resources</span></a></li>
        <li class="item6"><a href="#"><span>News</span></a></li>
        <li class="item7"><a href="#"><span>Contact</span></a></li>
    </ul>
</div>
0
répondu Raksmey 2010-08-27 06:47:33

Simple balisage, testé sous Opera, FF, Chrome, IE7, IE8:

<div class="nav">
  <a href="#" class="nav_item">nav item1</a>
  <a href="#" class="nav_item">nav item2</a>
  <a href="#" class="nav_item">nav item3</a>
  <a href="#" class="nav_item">nav item4</a>
  <a href="#" class="nav_item">nav item5</a>
  <a href="#" class="nav_item">nav item6</a>
  <span class="empty"></span>
</div>

et css:

.nav {
  width: 500px;
  height: 1em;
  line-height: 1em;
  text-align: justify;
  overflow: hidden;
  border: 1px dotted gray;
}
.nav_item {
  display: inline-block;
}
.empty {
  display: inline-block;
  width: 100%;
  height: 0;
}

Live exemple .

0
répondu Litek 2016-02-16 00:35:11

cela peut être parfaitement réalisé par quelques mesures soigneuses et le sélecteur du dernier enfant.

ul li {
margin-right:20px;
}
ul li:last-child {
margin-right:0;
}
-1
répondu Jason Paul 2011-08-19 05:05:20

je sais que la question originale spécifiait HTML + CSS, mais elle ne précisait pas pas de javascript ;)

en essayant de garder le css et le markup aussi propre que possible, et aussi sémantiquement significatif que possible (en utilisant un UL pour le menu) j'ai proposé cette suggestion. Probablement pas idéal, mais il peut être un bon point de départ:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">

<html>

    <head>
        <title>Kind-of-justified horizontal menu</title>

        <style type="text/css">
        ul {
            list-style: none;
            margin: 0;
            padding: 0;
            width: 100%;
        }

        ul li {
            display: block;
            float: left;
            text-align: center;
        }
        </style>

        <script type="text/javascript">
            setMenu = function() {
                var items = document.getElementById("nav").getElementsByTagName("li");
                var newwidth = 100 / items.length;

                for(var i = 0; i < items.length; i++) {
                    items[i].style.width = newwidth + "%";
                }
            }
        </script>

    </head>

    <body>

        <ul id="nav">
            <li><a href="#">first item</a></li>
            <li><a href="#">item</a></li>
            <li><a href="#">item</a></li>
            <li><a href="#">item</a></li>
        <li><a href="#">item</a></li>
            <li><a href="#">last item</a></li>
        </ul>

        <script type="text/javascript">
            setMenu();
        </script>

    </body>

</html>
-2
répondu David Heggie 2008-09-08 13:05:15