使用CSS均匀分布元素

时间:2009-03-23 16:18:43

标签: javascript css

今天使用CSS appeared on Smashing Magazine在容器中均匀分配元素的方法。

我最近不得不使用Javascript来实现对可变宽度元素的相同效果,但SM上提供的方法让我想知道是否可以在没有Javascript的情况下执行此操作。

this question,其中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' });
}

这是一个缩小的截图(看看菜单如何与标题图像对齐):

screenshot

知道如何在没有Javascript的情况下实现这一目标吗?

13 个答案:

答案 0 :(得分:36)

当然这正是 table 元素的用途。同时看到人们用CSS将自己扭曲成一个gordian结,这是令人伤心和欢闹的,他们中的大多数甚至都不知道为什么他们正在避免使用桌子。

无论您想要拒绝表格的原因是什么,它都可能比依赖Javascript来布局您的页面更糟糕。

是的,我知道这不是你想要的答案,但是很明显,很明显

答案 1 :(得分:34)

一直有人声称表格是明显的解决方案,但是,没有真正讨论如何实现它。我将向您展示将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元素):

riffing on cats

这段代码的优点在于它可以接受许多单元格和文本宽度,而不知道它们的实际宽度,并在页面上均匀分布它们。所有的时间,左右元素到达他们的周边,当然我们所有的html in divs,没有浏览器或互联网极客误导我们相信我们正在呈现表格数据。这里没有明确的妥协!

答案 2 :(得分:8)

这就是显示:table-cell应该实现的 - 但是,IE只是不这样做,而FF&lt; 3也有问题,我相信。

这些样式适用于FF3,Chrome,Safari和(我认为)Opera 9:

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

但是你需要一些公平的黑客才能让他们在通常的商业浏览器中工作。

答案 3 :(得分:5)

尽管Colin Brogan的回答为解决问题的“几乎在那里”解决方案提供了坚实的基础,但它仍然取决于文本长度。如果文本太长,“单元格”将更宽,因此左侧有更多空间。我试图根据他的答案中提供的代码来解决这个问题,但我得出结论,问题并没有一个真正可能的解决方案,有桌子或假表(display:table-cell)。

因此,我们必须等待CSS3灵活的盒子模型得到更广泛的支持(您可以检查更新的支持here)。在此期间,您可以使用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建议的方法是最可接受的,因为您保持文本的长度相同。如果没有,将开始展示更宽的空间。

答案 4 :(得分:3)

是的,您可以这样做,只要事先知道要分发的元素的宽度即可。但它有点乱。

诀窍是,你想要'(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'来响应动态内容。)这样您也不必担心像素舍入错误。

答案 5 :(得分:2)

如果你使用的是基于文本的尺寸(em,ex),那就容易多了。然后你可以处理字母而不是像素。

例子:全部是30个大写字母Ms宽。然后,您可以使用每个导航元素的宽度(基于其文本内容)并从那里静态地进行数学运算。

答案 6 :(得分:1)

以下是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();
                    });

答案 7 :(得分:1)

最佳答案对我不起作用,GarciaWebDev的回答不会对我有用,因为我需要支持其他一些浏览器,包括IE8。

This method为我工作。我们的想法是创建一个包含元素text-align:justify并使元素分布显示: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;
}

答案 8 :(得分:0)

AFAIK没有办法用CSS实现这一点。 如果这是错的,任何人都会纠正我,请等。

答案 9 :(得分:0)

如果您使用Yahoo!用户界面库(YUI)grids.css,它可能会起作用。

答案 10 :(得分:0)

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

你需要的只是让列表本身text-align:justify,然后在它的末尾添加一些伪项并使其填满所有宽度,以欺骗列表以证明其所有项目的总宽度。

答案 11 :(得分:0)

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

答案 12 :(得分:0)

感谢CSS3 Flexbox module,这可以通过两行CSS实现。

检查Browser compatibility table for 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>