【问题标题】:Distribute elements evenly using CSS使用 CSS 均匀分布元素
【发布时间】:2019-03-08 10:00:12
【问题描述】:

今天使用 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' });
}

这是一个按比例缩小的屏幕截图(查看菜单如何与标题图像对齐):

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

【问题讨论】:

    标签: javascript css


    【解决方案1】:

    当然,这正是 table 元素的用途。看到人们用 CSS 将自己扭成一个死结,这既可悲又好笑,他们中的大多数人甚至不知道为什么他们要避免使用表格。

    无论您出于何种原因拒绝表格,都不会比依靠 Javascript 来布局您的页面更糟糕。

    是的,我知道这不是您要寻找的答案,但天哪,它是如此显而易见

    【讨论】:

    • 这是最好的答案 - 表格将在心跳中解决这个问题
    • 叹息。很明显,我和海报一样因为试图弯曲 CSS 以避免表格而感到内疚。有时它们正确的决定,我们作为设计师/开发人员应该停止反对在适当的时候使用它们。我们只需要记住非常重要的关键字适当...
    • 这绝对是不是表的用途。表是一个二维矩阵,其中每一行和每一列都标识了该行或列中所有其他值之间的关系。单行表没有我能想到的任何语义目的 - 真的没有理由创建一个表来容纳任何东西的一行。
    • 这不是真的拒绝表格,也不是为了美观而牺牲核心文档的语义价值。如果您的 HTML 很糟糕,那么进一步发展的意义何在?在我的书中,使用 javascript 来“润色”一个完美可用的布局是完全可以的。每个人,无论是否使用 javascript,都可以获得漂亮、实用的布局。绝大多数人(使用 JS)会得到一个看起来更精致的布局,间距均匀。谁输了?
    • 虽然我很喜欢“我不认为这意味着你认为它意味着什么......”,但如果你告诉我们 认为这也意味着。
    【解决方案2】:

    有人说表格是显而易见的解决方案,但没有任何关于如何实现它的真正讨论。我将向您展示将 div 显示为表格是正确的方法,但它不像将所有单元格居中并设置自动宽度那么容易。这样做的问题是您无法控制最左边和最右边的单元格内容的外边距。它们都从其包含的盒子中插入了您无法控制的任意数量。这是一个解决方法:

    首先对古德的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 都在 div 中,没有浏览器或互联网极客会误导他们相信我们正在呈现表格数据。这里没有已知的妥协!

    【讨论】:

    • 这应该是 IMO 接受的答案。很好的解释,谢谢!
    • 快速说明:我必须设置width: 1000px 而不是width: auto,因为后者会根据其内容按比例调整单元格的大小。设置一个大的width 会使它们的大小再次相同。仅在 Chrome 中进行了测试,但必须检查它是否可以全面运行。
    • +1,这是一个很好的答案,但它不支持可变文本宽度,文本宽度应该大致相同。此外,要使其正常工作,您必须将 .left 选择器更改为 #menu li.left 以覆盖 #menu li 样式。查看我的答案,了解您将能够使用 CSS3 灵活盒模型的方法。
    • 关于文本宽度的好电话加西亚。当我写这篇文章时,我不知道每个单元格中的左填充量被缩放到每个单元格中文本内容的宽度。这实际上是一种妥协。在下面查看您的解决方案。
    【解决方案3】:

    这是 display:table-cell 应该实现的 - 但是,IE 只是不这样做,我相信 FF

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

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

    但是你需要一些技巧才能让它们在通常的商业浏览器中工作。

    【讨论】:

      【解决方案4】:

      尽管 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 建议的方法是最容易接受的,因为您可以将文本保持在大致相同的长度上。否则,将开始显示更宽的空间。

      【讨论】:

      • Garcia,我更喜欢你在这里提供的解决方案,而不是我自己的解决方案。 +1!
      • 这是一个很好的解决方案,但我认为值得一提的是 CSS3 灵活的盒子模型已经改变。任何浏览器都不再开发“盒子”实现,尽管实现上述代码的浏览器暂时仍会开发。当前规范使用“flex-”约定。 https://developer.mozilla.org/en-US/docs/CSS/Flexbox
      【解决方案5】:

      可以,只要事先知道要分布的元素的宽度即可。但是有点乱。

      诀窍是,你想要'(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 中,您可能需要在地块周围添加一个包装器 div,其宽度为 100%;如果您跨越整个页面,则溢出:隐藏以防止不需要的滚动条。当然,您会希望进入标准模式。

      这也适用于文本元素,如果您将它们设为内联块以便添加填充,并在 ems 中显式调整它们的大小。如果事先不知道子元素的大小(例如,它们包含动态内容),它将不起作用,因为您不知道要使用的“sum(Wc)”值。

      说实话,我可能只会使用一张桌子。表格布局算法非常顺利地计算如何分配备用表格宽度。 (使用“table-layout:fixed”以获得已知宽度单元格的最佳结果,或使用“auto”响应动态内容。)这样您也不必担心像素舍入错误。

      【讨论】:

        【解决方案6】:

        如果您使用基于文本的尺寸(em、ex),它会容易得多。然后您可以处理字母而不是像素。

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

        【讨论】:

        • 我喜欢这个主意,但小型大写字母不会把所有东西都弄乱吗?
        • 不,尺寸偏移量是已知的,所以您仍然可以根据字母进行数学运算。
        【解决方案7】:

        这里是 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();
                            });
        

        【讨论】:

          【解决方案8】:

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

          This method 为我工作。这个想法是使包含元素 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;
          }
          

          【讨论】:

            【解决方案9】:

            AFAIK 没有办法仅使用 CSS 来实现这一点。 如有错误请大家指正。

            【讨论】:

              【解决方案10】:

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

              【讨论】:

                【解决方案11】:

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

                如果您需要创建列表本身text-align:justify,然后在其末尾添加一些伪项目并使其填充所有宽度,以欺骗列表使其在其总宽度上的所有项目合理化。

                p>

                【讨论】:

                  【解决方案12】:

                  Trevor Dixon 的改进变体(没有额外的 &lt;li&gt;

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

                  【讨论】:

                    【解决方案13】:

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

                    【讨论】:

                      猜你喜欢
                      • 2011-07-04
                      • 1970-01-01
                      • 1970-01-01
                      • 2016-03-20
                      • 2020-12-18
                      • 2011-05-05
                      • 2017-04-14
                      • 2020-08-06
                      • 2019-07-21
                      相关资源
                      最近更新 更多