簡體   English   中英

使用CSS均勻分布元素

[英]Distribute elements evenly using CSS

今天在Smashing雜志出現了一種使用CSS在容器中均勻分配元素的方法。

我最近不得不使用Javascript來實現對可變寬度元素的相同效果,但SM上提供的方法讓我想知道是否可以在沒有Javascript的情況下執行此操作。

這個問題gargantaun說:

恕我直言,你可能不想聽到這個,但設計可能有缺陷。 眾所周知,使用CSS在布局中均勻分布項目是一種痛苦,因此設計人員應該避免使用它。

但我無法告訴設計師改變他的設計,我不同意CSS的缺點應該限制設計師。

無論如何,這是我在HTML中的內容(翻譯和簡化):

<div id="menu">
    <ul>
        <li><a href="/">Home</a></li>
        <li><a href="/news">News</a></li>
        <li><a href="/theme">Theme</a></li>
        <li><a href="/activities">Activities</a></li>
        <li><a href="/contact">Contact</a></li>
    </ul>
</div>

在CSS中(刪除和簡化了不相關的屬性):

#menu li { float: left; margin-right: 20px; }
#menu a  { display: block; padding: 0 1em; }

並在Javascript中:

function justifyMenu() {
    var menuItems  = $$("#menu li");
    var menuWidth  = $("menu").getWidth();
    var totalWidth = 0;

    menuItems.each(function(e) {
        totalWidth += e.getWidth();
    });

    var margin = (menuWidth - 4 - totalWidth) / (menuItems.length - 1);
    margin = parseInt(margin);

    menuItems.each(function(e) {
        e.setStyle({ marginRight: margin + 'px' });
    });

    menuItems[menuItems.length - 1].setStyle({ marginRight: '0' });
}

這是一個縮小的截圖(查看菜單如何與標題圖像對齊):

截圖

知道如何在沒有Javascript的情況下實現這一目標嗎?

當然這正是table元素的用途。 同時看到人們用CSS將自己扭曲成一個gordian結,這是令人傷心和歡鬧的,他們中的大多數甚至都不知道他們為什么要避開桌子。

無論你想要拒絕表格的原因是什么,它都可能比依賴Javascript布局你的頁面更糟糕。

是的,我知道這不是你想要的答案,但很明顯 ,它是如此明顯

一直有人聲稱表格是明顯的解決方案,但是,沒有真正討論如何實現它。 我將向您展示將div作為表格顯示是正確的方法,但它並不像對齊所有單元格和設置自動寬度那么容易。 這個問題是你無法控制最左邊和右邊細胞內容的外邊距。 它們都是從包含盒中插入一個你無法控制的任意數量。 這是一個解決方法:

首先,稍微修改一下Guder的html:

<div id="menu">
    <ul>
        <li class="left"><a href="/">Home</a></li>
        <li><a href="/news">News</a></li>
        <li><a href="/theme">Theme</a></li>
        <li><a href="/activities">Activities</a></li>
        <li><a href="/contact">Contact</a></li>
    </ul>
</div>

現在的CSS:

#menu {display:table; width:// some width in px //}
#menu ul {display:table-row; width: 100%}
#menu li.left {display: table-cell; text-align: left; width: 20px; white-space:nowrap;}
#menu li {display: table-cell; text-align: right; width: auto;}

現在,我們可以完全控制菜單的最外側,它與包含盒的左右兩側對齊,每個元素之間的距離是一致的。 你會注意到我使用了一個技巧讓最左邊的單元格成為它內容的精確寬度。 我將width屬性設置為一個小的大小,明顯低於其通常的內容。 然后我將白色空間設置為無包裹,這將細胞拉伸到最小量以適合細胞的文本。 你可以在這里看到一個顯示其效果的圖像(使用不同的html元素):

在貓身上徘徊

這段代碼的優點在於它可以接受許多單元格和文本寬度,而不了解它們的實際寬度,並在頁面上均勻分布它們。 所有的時間,左右元素到達他們的周邊,當然我們所有的html in divs,沒有瀏覽器或互聯網極客誤導我們相信我們正在呈現表格數據。 這里沒有明確的妥協!

這就是顯示:table-cell應該實現的 - 但是,IE只是不這樣做,而FF <3也存在問題,我相信。

這些樣式適用於FF3,Chrome,Safari和(我認為)Opera 9:

#menu ul {display:table;padding:0;}
#menu li {display:table-cell;text-align:center;}

但是你需要一些公平的技巧才能讓它們在通常的商業瀏覽器中工作。

雖然Colin Brogan的答案為解決問題的“幾乎在那里”解決方案提供了堅實的基礎,但它仍然取決於文本長度。 如果文本太長,“單元格”將更寬,因此左側有更多空間。 我試圖根據他的答案中提供的代碼來解決這個問題,但我得出的結論是,問題並沒有一個真正可能的解決方案,包括表或假表(display:table-cell)。

所以我們必須等待CSS3靈活的盒子模型得到更廣泛的支持(你可以在這里查看更新的支持)。 在此期間,您可以使用Flexie polyfill來修補不支持它的瀏覽器。 如果你想現在檢查它在WebKit上的樣子(不需要polyfill),你可以嘗試以下CSS:

#menu ul {
  display: -webkit-box;
  -webkit-box-orient: horizontal;
  -webkit-box-pack: justify;
  width: 940px;
  list-style: none;
  padding: 0;
  border: 1px solid gray;
}
#menu li {
  border: 1px solid silver;
}

請注意,它只使用WebKit前綴。 如果您決定將其帶到生產網站,您應該為其他瀏覽器添加前綴。

這種方法確實接受未知數量的項目和文本寬度,而不知道它們的實際寬度 ,並將它們均勻地分布在它們的容器中(在這種情況下, #menu ul )。

如果您決定保守,那么Colin Brogan提出的方法是最可接受的,因為您將文本保持在相同的近似長度。 如果沒有,將開始展示更寬的空間。

是的,您可以這樣做,只要預先知道要分發的元素的寬度即可。 但它有點亂。

訣竅是,你想要'(Wp-sum(Wc))/(Nc-1)'的每個元素之間的間距,即父元素的寬度減去所有子元素的總寬度,在元素之間的間隙數。

因為CSS沒有能力做表達式,所以我們不得不破解它。 首先,我們為大小'sum(Wc)'的父元素添加一個邊距,即所有子元素的總寬度。 所以現在父節點有寬度'(Wp-sum(Wc))',我們可以使用%相對於該寬度的填充值。

因此,例如,對於分別為10px,20px,40px和80px的四個圖像,我們的'sum(Wc)'是150px。 將其設置為父邊距,然后子節點可以將寬度的三分之一作為它們之間的填充。

<style type="text/css">
    #nava { width: 10px; height: 20px;}
    #navb { width: 20px; height: 20px;}
    #navc { width: 40px; height: 20px;}
    #navd { width: 80px; height: 20px;}

    #nav { margin-right: 150px; white-space: nowrap; }
    #nava, #navb, #navc { padding-right: 33.3%; }
</style>

<div id="nav"
    ><img id="nava" src="nava.png" alt="a"
    ><img id="navb" src="navb.png" alt="b"
    ><img id="navc" src="navc.png" alt="c"
    ><img id="navd" src="navd.png" alt="d"
></div>

有趣的標簽縮進是為了避免圖像之間有任何空白。 'nowrap'是必要的,因為父寬度設置比頁面寬度窄,否則不可能適合行上的所有元素。 最后,在IE中你可能需要在'lot:100%;周圍添加一個包裝div。 溢出:隱藏'以防止不必要的滾動條,如果你跨越整個頁面。 當然,你會想要處於標准模式。

這也適用於文本元素,如果你使它們成為內聯塊,那么你可以添加填充,並在ems中顯式調整它們的大小。 如果未提前知道子元素的大小(例如,它們包含動態內容),則無法使用,因為您不會知道要使用的'sum(Wc)'值。

說實話,我可能只是使用一張桌子。 表格布局算法可以非常順暢地計算如何分配備用表格寬度。 (使用'table-layout:fixed'以獲得具有已知寬度單元格的最佳結果,或使用'auto'來響應動態內容。)這樣您也不必擔心像素舍入錯誤。

如果你使用基於文本的大小(em,ex),那就容易多了。 然后,您可以處理字母而不是像素。

示例:整個事情是30個大寫字母Ms寬。 然后,您可以使用每個導航元素的寬度(基於其文本內容)並從那里靜態地進行數學運算。

最佳答案對我不起作用,而GarciaWebDev的回答也不會對我有用,因為我需要支持其他一些瀏覽器,包括IE8。

這種方法對我有用。 我們的想法是創建一個包含元素text-align:justify並使元素分布display:inline-block。

HTML:

<div id="menu">
    <ul>
        <li><a href="/">Home</a></li>
        <li><a href="/news">News</a></li>
        <li><a href="/theme">Theme</a></li>
        <li><a href="/activities">Activities</a></li>
        <li><a href="/contact">Contact</a></li>
        <li class="filler"></li>
    </ul>
</div>

CSS:

#menu {
    text-align: justify;
}

ul {
    margin: 0;
    padding: 0;
}

#menu li {
    display: inline-block;
}

.filler {
    width: 100%;
    height: 0;
}

以下是jQuery格式的代碼,適用於任何發現它有用的人

function justifyClients() {
                        var menuItems  = $("#clients-wrapper ul li").get();                         
                        var menuWidth  = $("#clients-wrapper ul").width();                          
                        var totalWidth = 0;

                        $("#clients-wrapper ul li").each(function(i,e)
                                        {
                                            totalWidth += $(e).width();
                                        });

                        var margin = (menuWidth - 4 - totalWidth) / ($("#clients-wrapper ul li").length - 1);
                        margin = parseInt(margin);

                        $("#clients-wrapper ul li").each(function(i,e) {

                            if(i < $("#clients-wrapper ul li").length - 1)
                            {
                                alert(i + " " + $("#clients-wrapper ul li").length);
                                $(e).css('margin-right',  margin);
                            }
                        });
                    }

                    $(document).ready(function() {
                      justifyClients();
                    });

演示 - http://codepen.io/vsync/pen/tFwxu

如果要使列表本身為text-align:justify然后在其末尾添加一些偽項並使其填充所有寬度,以欺騙列表以證明其所有項目的總寬度。

Trevor Dixon的改進型(沒有額外的<li>

HTML

<ul>
    <li><a href="/">Home</a></li>
    <li><a href="/news">News</a></li>
    <li><a href="/theme">Theme</a></li>
    <li><a href="/activities">Activities</a></li>
    <li><a href="/contact">Contact</a></li>
</ul>

CSS

ul {
    margin: 0;
    padding: 0;
}
ul li {
    display: inline-block;
    text-align: justify;
}
ul:after{
    display: inline-block;
    content: '';
    width: 100%;
    height: 0;
}

借助CSS3 Flexbox模塊 ,可以使用兩行CSS。

檢查Flexbox瀏覽器兼容性表

HTML

<div id="menu">
  <ul>
    <li><a href="/">Home</a>
    </li>
    <li><a href="/news">News</a>
    </li>
    <li><a href="/theme">Theme</a>
    </li>
    <li><a href="/activities">Activities</a>
    </li>
    <li><a href="/contact">Contact</a>
    </li>
  </ul>
</div>

CSS

ul {
  display: flex;
}
li {
  flex: 1; /* Short hand for flex-grow: 1 and flex-shrink: 1 */
}

輸出:

 ul, li { margin: 0; padding: 0; } ul { display: flex; list-style: none; } li { flex: 1; text-align: center; } 
 <div id="menu"> <ul> <li><a href="/">Home</a> </li> <li><a href="/news">News</a> </li> <li><a href="/theme">Theme</a> </li> <li><a href="/activities">Activities</a> </li> <li><a href="/contact">Contact</a> </li> </ul> </div> 

AFAIK沒有辦法用CSS實現這一點。 如果這是錯的,任何人都會糾正我,請。

如果您使用Yahoo! 用戶界面庫(YUI) grids.css ,它可能會工作。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM