Làm cách nào để * thực sự * điều chỉnh menu ngang trong HTML + CSS?


86

Bạn tìm thấy rất nhiều hướng dẫn về thanh menu trong HTML, nhưng đối với trường hợp cụ thể này (mặc dù là chung cho IMHO), tôi không tìm thấy giải pháp nào phù hợp:

#  THE MENU ITEMS    SHOULD BE    JUSTIFIED     JUST AS    PLAIN TEXT     WOULD BE  #
#  ^                                                                             ^  #
  • Có nhiều mục menu chỉ văn bản khác nhau và bố cục trang rất linh hoạt.
  • Mục menu đầu tiên phải được căn trái, mục menu cuối cùng phải được căn phải.
  • Các mục còn lại nên được trải rộng tối ưu trên thanh menu.
  • Số lượng đang thay đổi, vì vậy không có cơ hội để tính trước chiều rộng tối ưu.

Lưu ý rằng TABLE cũng sẽ không hoạt động ở đây:

  • Nếu bạn căn giữa tất cả TD, mục đầu tiên và mục cuối cùng không được căn chỉnh chính xác.
  • Nếu bạn căn trái và căn phải lần lượt đầu tiên. các mục cuối cùng, khoảng cách sẽ là tối ưu.

Không có gì lạ khi không có cách rõ ràng nào để thực hiện điều này một cách rõ ràng bằng cách sử dụng HTML và CSS?

Câu trả lời:


43

Phương pháp tiếp cận hiện đại - Flexboxes !

Giờ đây, các flexbox CSS3 đã hỗ trợ trình duyệt tốt hơn , một số người trong chúng ta cuối cùng cũng có thể bắt đầu sử dụng chúng. Chỉ cần thêm tiền tố nhà cung cấp bổ sung để có nhiều trình duyệt hơn .

Trong trường hợp này, bạn chỉ cần đặt phần tử cha displaythành flexvà sau đó thay đổi thuộc justify-contenttính thành một trong hai space-betweenhoặc space-aroundđể thêm khoảng cách giữa hoặc xung quanh các mục flexbox con.

Sử dụngjustify-content: space-between - ( ví dụ ở đây) :

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>


Sử dụngjustify-content: space-around - (ví dụ ở đây) :

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>


83

Điều đơn giản nhất cần làm là buộc dòng bị ngắt bằng cách chèn một phần tử vào cuối dòng sẽ chiếm nhiều hơn không gian trống còn lại và sau đó ẩn nó đi. Tôi đã hoàn thành điều này khá dễ dàng với một spanphần tử đơn giản như sau:

#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>

Tất cả rác bên trong #menu spanbộ chọn (theo như tôi đã tìm thấy) cần thiết để làm hài lòng hầu hết các trình duyệt. Nó phải buộc chiều rộng của spanphần tử là 100%, điều này sẽ gây ra ngắt dòng vì nó được coi là một phần tử nội tuyến do display: inline-blockquy tắc. inline-blockcũng cho phép spancó thể chặn các quy tắc kiểu cấp độ widthkhiến phần tử không phù hợp với menu và do đó menu bị ngắt dòng.

Tất nhiên, bạn cần phải điều chỉnh chiều rộng của nó cho spanphù hợp với trường hợp sử dụng và thiết kế của mình, nhưng tôi hy vọng bạn có được ý tưởng chung và có thể điều chỉnh nó.


1
Nó có vẻ hoạt động nếu bạn sử dụng một spanthay vì một hr! Nó không thực sự hoạt động, nhân sự đang chiếm không gian có thể nhìn thấy - hãy sử dụng #menu { border: solid 1px green; }để xác nhận. Ngoài ra, display: inline-block;không hoạt động trên IE (... 7? CompatibilityView?) Cho các phần tử không phải là phần tử nội tuyến tự nhiên. HR là một phần tử khối, vì vậy tôi đoán khối nội tuyến không hoạt động với HR trên IE. Dù sao, khoảng thời gian.
ANeves cho rằng SE là xấu xa

9
hoạt động tốt, nhưng kết quả sẽ đẹp hơn nếu bạn thay thế từng khoảng trắng bằng & ensp; (n dấu cách), để Menu & mục & 1 ở gần nhau. & nbsp; không hoạt động trong safari.
yitwail

15
Tôi chỉ dành hơn một giờ để đập đầu vào tường, cố gắng tìm ra lý do tại sao điều này không hiệu quả với tôi. Câu trả lời là tôi cần khoảng trắng giữa các thẻ. Tôi đang làm việc trong WordPress và wp_page_menu không bao gồm ngắt dòng sau mỗi <li> </li>. Đã thêm chúng bằng cách sử dụng preg_replace và nó hoạt động ngay bây giờ. Fwewww
Greg Perham

1
Để làm được điều này trong những ngày này, bạn phải sử dụng display: inline-block trên LI trong các trình duyệt hỗ trợ nó và sử dụng display: inline với dấu cách được thay thế bằng & nbsp; trên các trình duyệt không hỗ trợ nó. Ngoài ra, vì ie7 không hỗ trợ khối nội tuyến, bạn phải sử dụng nội tuyến trên thẻ force-wrap của mình và chỉ cần nhét đủ & nbsp; s vào đó để buộc bọc.
Joren

1
Để làm rõ nhận xét của Joren, UL vẫn cần được nội tuyến và khối nội tuyến của LI.
Moss

12

Ok, giải pháp này không hoạt động trên IE6 / 7, do thiếu sự hỗ trợ của :before/ :after, nhưng:

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>

Lý do tại sao tôi có thẻ là an inline-blocklà vì tôi không muốn các từ bên trong cũng được căn chỉnh và tôi cũng không muốn sử dụng dấu cách không ngắt.


Cảm ơn! Tâm hồn của bạn đang đi xuống điểm. Nếu tôi bắt đầu câu hỏi, tôi sẽ đánh dấu nó như một câu trả lời.
Andrevinsky

Tôi gặp sự cố khi làm việc này trong IE. Sau một số giờ dành cho Google, cuối cùng tôi đã tìm thấy bài đăng trên blog này: kristinlbradley.wordpress.com/2011/09/15/… Cuối cùng, mẹo đã làm là thêm text-justify: distribute-all-lines;vào ulbộ chọn. Có vẻ là công cụ IE độc quyền.
maryisdead

Không chắc chắn nếu những vấn đề này, nhưng tôi sử dụng width: 100%thay vì margin-left: 100%: ul:after{content:""; margin-left:100%;}
Eugene Sông

8

Có một giải pháp. Hoạt động trong FF, IE6, IE7, Webkit, v.v.

Đảm bảo rằng bạn không đặt bất kỳ khoảng trắng nào trước khi đóng span.inner. IE6 sẽ bị hỏng.

Bạn có thể tùy chọn cung cấp .outerchiều rộng

.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>


Đối với tôi, giải pháp này hoạt động tốt với Gecko, nhưng không hoạt động tốt với các trình duyệt WebKit (được thử nghiệm với Chromium, Midori, Epiphany): Với WebKit, có dấu cách sau mục cuối cùng.
chuyến bay

Đảm bảo chỉ có một ký tự khoảng trắng giữa mỗi khoảng và hai ký tự giữa phần trong cùng và phần cuối. Nếu điều đó không hiệu quả, hãy tìm khoảng trắng. Có một lỗi trong webkit.
mikelikespie

1
.outer {text-align: justify} .outer span.finish {display: inline-block; width: 100%} .outer span.inner {display: inline-block; white-space: nowrap} Không hoạt động trên IE6 và IE7.
Binyamin

Cung cấp cho các .outer line-height: 0lực lượng chiều cao của danh sách được hiển thị như thể nó bao gồm một dòng.
kontur

4

Hoạt động với Opera, Firefox, Chrome và 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;
}

1
Đáng tiếc là điều này không làm việc trong IE 7 vì sự thiếu hỗ trợ table-cell
Philipp Michael

3

một giải pháp khác. Tôi không có tùy chọn nào để giải quyết html như thêm lớp phân biệt, v.v., vì vậy tôi đã tìm thấy một cách thuần túy css.

Hoạt động trên Chrome, Firefox, Safari..không biết về IE.

Kiểm tra: 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>


2

Làm cho nó một <p>với text-align: justify?

Cập nhật : Nevermind. Điều đó hoàn toàn không hoạt động như tôi nghĩ.

Cập nhật 2 : Hiện không hoạt động trong bất kỳ trình duyệt nào khác ngoài IE, nhưng CSS3 có hỗ trợ cho việc này dưới dạngtext-align-last


Đó là nhanh chóng! Tôi nghĩ rằng giải pháp của riêng tôi là duy nhất, nhưng bạn đã nghĩ ra một thứ tương tự để bắt đầu chỉ trong chốc lát.
chuyến bay

Bây giờ vào năm 2016 text-align-last hoạt động trên bất kỳ trình duyệt nào khác ngoài Safari . Đây có thể là đối thủ của cách tiếp cận flexbox hoặc hack span .
hakatashi

1

Đối với các trình duyệt dựa trên Gecko, tôi đã đưa ra giải pháp này. Tuy nhiên, giải pháp này không hoạt động với các trình duyệt WebKit (ví dụ: Chromium, Midori, Epiphany), chúng vẫn hiển thị khoảng trắng sau mục cuối cùng.

Tôi đặt thanh menu trong một đoạn văn vừa phải . Vấn đề là dòng cuối cùng của một đoạn văn đã căn cứ sẽ không được hiển thị đúng, vì những lý do rõ ràng. Do đó, tôi thêm một phần tử vô hình rộng (ví dụ: một img) đảm bảo rằng đoạn văn dài ít nhất hai dòng.

Bây giờ thanh menu được căn chỉnh bởi cùng một thuật toán mà trình duyệt sử dụng để căn chỉnh văn bản thuần túy.

Mã:

<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>

Nhận xét: Bạn có nhận thấy tôi đã lừa dối? Để thêm phần tử lấp đầy khoảng trắng, tôi phải phỏng đoán về chiều rộng của thanh menu. Vì vậy, giải pháp này không hoàn toàn tuân theo các quy tắc.


Lưu ý rằng bạn cũng có thể sử dụng danh sách ở đây, nếu bạn đặt hiển thị: nội dòng trên danh sách-mục ... danh sách thông thường hơn cho menu.
Andrew Vit

@Andrew Vit: Bạn nói đúng. Đó hầu hết là những gì giải pháp của asbjornu đề xuất.
chuyến bay

@flight, nếu bạn nghĩ câu trả lời của tôi là một giải pháp, bạn có thể vui lòng đánh dấu nó là một không? Hiện tại, có vẻ như vấn đề của bạn chưa được giải quyết. Nếu không, sẽ thật tuyệt nếu bạn cung cấp cho chúng tôi giải pháp mà bạn đã tìm thấy hoặc đánh dấu bất kỳ câu trả lời nào được cung cấp là giải pháp cho vấn đề của bạn. :-)
Asbjørn Ulsberg,

1

Văn bản chỉ được điều chỉnh nếu câu tự nhiên gây ra ngắt dòng. Vì vậy, tất cả những gì bạn cần làm là tự nhiên buộc ngắt dòng và ẩn những gì ở dòng thứ hai:

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>

Phần tử li.break phải nằm trên cùng một dòng với mục menu cuối cùng và phải chứa một số nội dung (trong trường hợp này là khoảng trắng không ngắt), nếu không trong một số trình duyệt, nếu nó không nằm trên cùng một dòng thì bạn sẽ thấy một số nội dung nhỏ khoảng trống thừa ở cuối dòng của bạn và nếu nó không chứa nội dung thì nó bị bỏ qua và dòng không được căn chỉnh.

Đã thử nghiệm trên IE7, IE8, IE9, Chrome, Firefox 4.


0

nếu có thể sử dụng javascript (script này dựa trên 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>

và 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>

và html cuối cùng

<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

Đánh dấu đơn giản hơn, được thử nghiệm trong 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>

và 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;
}

Ví dụ trực tiếp .


-1

Điều này có thể đạt được một cách hoàn hảo bằng một số phép đo cẩn thận và bộ chọn con cuối cùng.

ul li {
margin-right:20px;
}
ul li:last-child {
margin-right:0;
}

4
Hãy nhớ rằng văn bản không hiển thị giống nhau ở mọi nơi, một pixel bị tắt và bạn sẽ thấy một menu bị hỏng. Điều này sẽ chỉ hoạt động với phần tử có chiều rộng cố định như hình ảnh.
fregante

-2

Tôi biết câu hỏi ban đầu chỉ định HTML + CSS, nhưng nó không nói cụ thể là không có javascript ;)

Cố gắng giữ css và đánh dấu càng sạch càng tốt, và có ý nghĩa nhất có thể về mặt ngữ nghĩa (sử dụng UL cho menu), tôi đã đưa ra đề xuất này. Có lẽ không lý tưởng, nhưng nó có thể là một điểm khởi đầu tốt:

<!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>
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.