CSS 流体列,固定边距;圣杯的圣杯

Posted

技术标签:

【中文标题】CSS 流体列,固定边距;圣杯的圣杯【英文标题】:CSS fluid columns, fixed margins; the holy grail of holy grails 【发布时间】:2011-11-03 16:22:05 【问题描述】:

更新与总结

既然附加了赏金,我觉得有义务让这个问题更清楚。

(另外,我敢肯定,当支持calc() CSS3 单位值时,这将是小菜一碟,比如width: calc(25% - 5px);尽管我们可能会在脑海中浏览互联网那一点)

我正在为一些共享设计要求的项目开发 CSS 框架;即流体12列布局。使用百分比宽度为(100% / 12) x col_size 的浮动.column 元素,这相当容易。但是,问题在于在列之间添加了固定边距(或任何形式的间距)。

我最初的尝试使用了所描述的流体列,每个都嵌套了一个.panel 子级。 html/CSS sn-p 如下(为简洁起见):

.column
    float: left;
    display: inline-block;


.width-01 width:  8.3333%; 
.width-02 width: 16.6666%; 
.width-03 width:      25%; 
/* etc */

.panel
    width: 100%;
    padding: 5px;
    box-sizing: border-box; /* so padding doesn't increase width */

<div class="column width-02">
    <div class="panel">Width-02</div>
</div>
<div class="column width-03">
    <div class="panel">Width-03</div>
</div>
<div class="column width-02">
    <div class="panel">Width-02</div>
</div>
<div class="column width-05">
    <div class="panel">Width-05</div>
</div>

这个 sn-p 将产生类似于下图的布局,但是所有 .panel 元素的所有边都有 5px 填充。 我正在尝试使外部列的内容边缘与视口(或相关的父容器)边缘齐平。另一种方法是完全消除 .panel 类,只使用列:

.column
    float: left;
    display: inline-block;
    padding-left: 10px;
    box-sizing: border-box;


.column:first-child padding-left: 0px; 

.width-01 width:  8.3333%; 
.width-02 width: 16.6666%; 
.width-03 width:      25%; 
/* etc */
<div class="column width-02">Width-02</div>
<div class="column width-03">Width-03</div>
<div class="column width-02">Width-02</div>
<div class="column width-05">Width-05</div>

再一次,这很好用,产生的结果更接近下图,但是现在(实际)问题是填充正在占用拧紧的列的宽度上宽度分布。 :first-child 列的内容区域宽度比其兄弟列大 10 像素(或任何边距大小)。

这可能看起来无害,甚至不引人注意;但是在某些情况下,元素之间的宽度分布精确尽可能精确)要么是必要的,要么会使事情变得更容易。

因此,无论是使用填充、边距还是它们的某种组合;对于流体列、固定边距、均匀分布的装订线空间,是否有任何解决方案不会从相邻列中抢走“边际”(***哈哈*)内容区域? **


原始问题

由于我的搜索和尝试都没有结果,我认为这是不可能的。不过,如果任何地方都能给出答案,我敢肯定它就在这里。

有没有什么方法可以使用纯 CSS 来实现具有固定宽度边距的流体宽度列式布局?

重要提示:此图只是一个示例,并不是我想要实现的特定布局。给定的解决方案应允许相邻列的任意组合,总宽度分布总计为 12 或更少。考虑流行的960 grid 以供参考。)

注意:在12列布局中,图片中各列的宽度分布分别为2、3、2、5 .

到目前为止,我使用了一个网格,使用百分比,几乎可以实现这一点。问题是,为了实现边距,每一列都需要一个额外的子项(我称它们为.panel):

width: 100%;
box-sizing: border-box;
padding: 10px;

这也是,几乎,很好;这种方法的问题是第一列和最后一列具有外部“边距”(10px),并且每列之间的“边距”加倍(2 x 10px >)

当然,通过包含新的 CSS3 calc() 值类型,可以更轻松地解决这个问题。方向:

.width-12 > .panel width: 100%; 
.width-09 > .panel
    width: calc(75% - 10px);
    margin: ...;

我已经修复了一些 javascript,我已经破解了一些“有效”的东西,但我正在寻求。希望最神圣的圣杯存在。

不幸的是,以下解决方案以及 @avall 提供的解决方案(虽然在简化方面肯定是一个不错的选择)并不是我想要的。主要问题是,边距在列之间分布不均匀。

我可以看到这个工作的唯一方法是将 .panel 填充减少到 5px 和类似的东西:

.column:first-child > .panel 
    padding-left: 0px;


.column:last-child > .panel 
    padding-right: 0px;


/* not necessary? in any case, haven't tested */
.column:only-child > .panel 
    padding-right: 0px;
    padding-left: 0px;

这种解决方案是不可接受的,只是因为 IE8 无法识别 :last-child以及就此而言 :only-child)伪选择器。

【问题讨论】:

为什么要在纯 css 中使用它?是否有任何理由无法使用表格(或显示:表格)进行布局? @Exelian - 我是 tables != layout 学派的坚定支持者。至于display: table,浏览器支持的不一致(虽然不可怕)让我寻找替代方案。同样,关于display: table,我遇到了一些关于“单元格”不遵守大小调整属性的问题。否则是的,表格显示属性将是一个很可能的解决方案。 为什么不将 last-child 或 only-child 类添加到相应的列,然后针对类而不是伪选择器应用零填充,以便让 @avall 的解决方案在 IE8 上工作和下面?我知道这是额外的标记,但无论如何我们现在不得不经常这样做。 解决这个问题要简单得多:codepen.io/roydukkey/pen/eudsn @roydukkey,codepen 参考非常棒,而且比公认的答案简单得多 - 谢谢! 【参考方案1】:

我终于想通了。在过去十年间断断续续地浪费了数百个小时之后(尽管我依赖的是一些一年前无论如何都不会工作的 CSS)。我没有任何问题就解决了。在 IE8+ 中。

请准备好 2001:太空漫游音乐,因为我要登陆这艘船。

这种方法的天才和技巧在于使用内联块元素,然后使用字间距来平衡使用负右边距。它自己的负右边距会将元素拉在一起,允许您设置 100% 的宽度并仍然适合其间的东西,但让元素重叠。在父级上设置负边距只会撤消子级边距对与总宽度交互的影响(我们试图击中的神奇“100% 宽度”标记“)。填充仅用于增加元素的大小on 并且对于反作用边距是无用的。它通常与 box-sizing 一起使用,在陪审团操纵解决此问题的方法中,以失去使用填充(和边距)的能力为代价,并且可能需要更多包装元素。

word-spacing 提供了神奇的“第三种方式”来添加或删除两个元素之间的水平距离,前提是它们是 inline-block,因为在这种情况下它们将被视为单个“单词”,并且之间的任何空格都会折叠到一个可控制的“字间距”属性。除了这个技巧,我不知道还有其他方法可以得到这个 100% 的结果。

我谦虚地介绍固定排水沟弹性列问题的最终答案。我在此将我的解决方案命名为“欧米茄机动”。它具有处理任意混合宽度列的能力(添加多达 100% 的总宽度以进行四舍五入)、任何装订线大小、任何预定义的宽度列数、使用自动换行处理任意数量的行,以及使用 inline-block 元素,因此提供了 inline-block 附带的垂直对齐选项,并且它不需要任何额外的标记,只需要容器上的单个类声明(不计算定义列宽)。我认为代码不言自明。这是 2-6 列的代码实现,使用 10px 排水沟和用于百分比的奖励辅助类。

编辑:有趣的难题。我设法得到了两个略有不同的版本;一个用于 Mozilla 和 ie8+,另一个用于 webkit。似乎 word-spacing 技巧在 webkit 中不起作用,我不知道为什么其他版本在 webkit 中起作用,但在 ie8+/mozilla 中不起作用。将两者结合起来可以让您覆盖所有内容,我敢打赌,有一种方法可以统一这种策略或非常类似的方法来解决这个问题。

EDIT2:基本上明白了!神奇的text-align: justify 让 WebKit 几乎与字间距一起出现。间距似乎有点偏离,就像右边的像素问题,也许还有一个额外的像素。但它是可用的,而且在保留列方面似乎比我以前使用过的任何东西都更可靠。它永远不会减少到更少的列,它会一直压缩,直到浏览器获得水平滚动条。

Edit3:有点接近完美。将 font-size 设置为 0 可以规范大多数剩余的间距关闭问题。现在只需要修复 IE9,如果它的字体大小为 0,它会折叠它。

EDIT4:从其他一些流体宽度的帖子中得到了 IE 的答案:-ms-text-justify: distribute-all-lines。在 IE8-10 中测试。

/* The Omega Maneuver */
[class*=cols]  text-align: justify; padding-left: 10px; font-size: 0;
             -ms-text-justify: distribute-all-lines;  

 [class*=cols]>*  display: inline-block; text-align: left; font-size: 13px;
                word-spacing: normal; vertical-align: top;
                -webkit-box-sizing: border-box;
                   -moz-box-sizing: border-box;
                        box-sizing: border-box; 

.cols2  word-spacing: 20px; padding-right: 20px; 
.cols3  word-spacing: 30px; padding-right: 30px; 
.cols4  word-spacing: 40px; padding-right: 40px; 
.cols5  word-spacing: 50px; padding-right: 50px; 
.cols6  word-spacing: 60px; padding-right: 60px; 

  .cols2 > *  margin-right: -10px; 
  .cols3 > *  margin-right: -20px; 
  .cols4 > *  margin-right: -30px; 
  .cols5 > *  margin-right: -40px; 
  .cols6 > *  margin-right: -50px; 

一些帮手:

.⅛, .⅛s >*  width: 12.50%; 
.⅙, .⅙s >*  width: 16.66%; 
.⅕, .⅕s >*  width: 20.00%; 
.¼, .¼s >*  width: 25.00%; 
.⅓, .⅓s >*  width: 33.00%; 
.⅜, .⅜s >*  width: 37.50%; 
.⅖, .⅖s >*  width: 40.00%; 
.½, .½s >*  width: 50.00%; 
.⅗, .⅗s >*  width: 60.00%; 
.⅝, .⅝s >*  width: 62.50%; 
.⅔, .⅔s >*  width: 66.00%; 
.¾, .¾s >*  width: 75.00%; 
.⅘, .⅘s >*  width: 80.00%; 
.⅚, .⅚s >*  width: 83.33%; 
.⅞, .⅞s >*  width: 87.50%; 
.blarg-five-twelfs  width: 41.66%; 

您可以在这里见证我的巨作在一片荣耀的领域中发挥作用:http://jsfiddle.net/xg7nB/15/

<div class="cols4">
    <div class="⅙">This is my magnum opus</div>
    <div class="¼">I finally beat css</div>
    <div class="⅙">⚉ ☺ ☻ ♾ ☢</div>
    <div class="blarg-five-twelfs">I BEAT IT FOREVER</div>
</div>

绝对最小的实现,以 4 个等宽 (25%) 宽度的 cols 和 10px 间距为例,如下所示:

.fourEqualCols  word-spacing: 40px; padding: 0 40px 0 10px;
                 text-align: justify; font-size: 0;
                 -ms-text-justify: distribute-all-lines; 

.fourEqualCols>*  margin-right: -30px; width: 25%;
                   display: inline-block; word-spacing: normal;
                   text-align: left; font-size: 13px; 


<div class="fourEqualCols ">
  <div>GLORIOUSLY CLEAN MARKUP</div>
  <div>I hate extra markup and excessive class props</div>
  <div>Naked code</div>
  <div>get intimate</div>
</div>

这个代码基本上取代了几乎所有现有的网格框架,对吧?如果您可以任意设置排水沟,然后只制作达到 100% 宽度的列集,那么这实际上优于大多数/所有网格框架,不是吗?如果您不再像我们中的许多人那样为 IE7 开发,那么结合 box-sizing:border-box 渲染填充和边框也不是问题。

编辑:哦,对了,你想与容器的侧面齐平。没问题,我必须专门添加侧边槽,这样我们就可以将一些值更改 10 并摆脱填充和瞧。 http://jsfiddle.net/bTty3/

[class^=cols]  text-align: justify; font-size: 0;
             -ms-text-justify: distribute-all-lines;  

 [class^=cols] >*  display: inline-block; text-align: left; font-size: 13px;
                word-spacing: normal; vertical-align: top;
                -webkit-box-sizing: border-box;
                   -moz-box-sizing: border-box;
                        box-sizing: border-box; 

.cols2  word-spacing: 20px; padding-right: 10px; 
.cols3  word-spacing: 30px; padding-right: 20px; 
.cols4  word-spacing: 40px; padding-right: 30px; 
.cols5  word-spacing: 50px; padding-right: 40px; 
.cols6  word-spacing: 60px; padding-right: 50px; 
 .cols2 >*  margin-right: 0 
 .cols2 >*  margin-right: -10px; 
 .cols3 >*  margin-right: -20px; 
 .cols4 >*  margin-right: -30px; 
 .cols5 >*  margin-right: -40px; 
 .cols6 >*  margin-right: -50px; 

相同的html

<div class="cols4">
    <div class="⅙">This is my magnum opus</div>
    <div class="¼">I finally beat css</div>
    <div class="⅙">⚉ ☺ ☻ ♾ ☢</div>
    <div class="blarg-five-twelfs">I BEAT IT FOREVER</div>
</div>

【讨论】:

你可能已经解决了这个问题,但在这个过程中你似乎发疯了。干得好! 伙计,我认为这可能会引发更多的兴趣。我就拿我的 Keep of the Columns 头衔自己去开派对吧。 您应该获得额外的9.999999999999847e+2447 声誉。我将在以后和永远正式将其称为“Benvie Omega Layout”;严重地。请注意,我之所以这么长时间没有回应,是因为我的聪明才智让我陷入昏迷。 好。我早上醒来的主要原因是在午餐前发明一些不可能的事情,然后在晚餐时用它不可逆转地伤害某人来结束这一天。 Safari 不喜欢它;进一步的测试是有序的;最终将发布进一步/详细的结果。【参考方案2】:

如果您可以使用每列另一个嵌套 div,您可以为每个列定义所需的边距。要消除左右外边缘的边距,您可以在外部容器上定义负边距。

例如:使用pureCSSpure-g 是外部容器,pure-u-* 是包含嵌套div 的列节点(显示:inline-block)。间距是 pureCSS 网格系统的自定义扩展名,以允许列边距。

.pure-g.spacing 
    margin: 0 -10px;


.pure-g.spacing [class *= "pure-u"] > div 
    margin: 10px;

应该适用于大多数浏览器。如果没有,请告诉我 - 我已经在使用它了。

问候, 最大

【讨论】:

【参考方案3】:

我最近为此开发了一种替代解决方案,它允许在一行中任意组合灵活的列,并且在所有列之间具有固定且一致的边距,而不管父元素的宽度如何。

这不使用任何 JavaScript 并且在 IE8+ 中工作。

在此解决方案中,边距定义在两个类上 - 因此很容易为响应式设计更改它。列宽也代表了它们使用的空间,例如 2 列行的宽度为 50%,4 列行的宽度为 25%。

你可以在http://www.andrewjamestait.co.uk/conflexgrids/看到一个例子

或者它可以在 GitHub 上https://github.com/andrewjtait/conflexgrids 获得

【讨论】:

【参考方案4】:

为什么不使用第一个示例中的填充,然后在所有元素上设置 box-sizing:border-box?

【讨论】:

【参考方案5】:

参考原始问题“有什么方法可以使用纯 CSS 来实现具有固定宽度边距的流体宽度列式布局?”

在处理这类问题时,CSS 变得异常困难,这是非常了不起的。过去一周我一直在研究一个“基本模板”来创建我自己的“圣杯”,包括边框、边距和填充……似乎 CSS 无法解决这类问题。虽然心中的问题很简单,但它变得(几乎?)不可能在 CSS 中实现,尤其是跨浏览器。

有趣的是,这些问题很容易通过使用表格来解决。我不明白为什么我们被网络社会强迫使用 div 来代替诸如“语义”和“简单概述”之类的模糊论点,因为大多数论点都很弱甚至是错误的。说表格更麻烦的人,显然不了解 CSS 的真正困难。

无论如何,如果你想要一个表格结构(因为列是表格的一部分),我建议使用 'display:table'。

要使用纯 CSS 实现原始问题下方的图像,可以使用以下方法:

CSS

html,body
    margin: 0px; 
    padding: 0px; 
    height: 100%; 
    width: 100%;
    overflow: auto;

.table
    background: pink;
    display: table;
    width: 100%;
    height: 100%;

.tableRow
    display: table-row;         

.tableCell
    display: table-cell;
    vertical-align: top;
    height: 100%;  

/*
    Ensures the full size of the table-cell has the behaviour of a block-element. 
    This is needed, because 'table-cell' will behave differently in different browsers.
*/
.tableCell>div
    height: 100%;

/*
    Padding has to be used instead of margin in 'border-box' modus.
*/
.tableCell>div>div
    height: 100%;
    box-sizing:border-box;
    -moz-box-sizing:border-box;

/*
    The final content.
*/
.tableCell>div>div>div
    background: lightblue;
    padding: 5px;
    height: 100%;
    box-sizing:border-box;
    -moz-box-sizing:border-box;



#col1
    width: 16.66%;          

#col1>div>div
    padding-right: 10px;

#col2
    width: 25%;         

#col2>div>div
    padding-right: 10px;

#col3      
    width: 16.66%;

#col3>div>div
    padding-right: 10px;

#col4
    width: 41.66%;

HTML

<div class="table">
    <div class="tableRow">
        <div id='col1' class="tableCell">   
            <div><div><div>16.66%</div></div></div>
        </div>
        <div id='col2' class="tableCell">
            <div><div><div>25%</div></div></div>
        </div>
        <div id='col3' class="tableCell">
            <div><div><div>16.66%</div></div></div>
        </div>
        <div id='col4' class="tableCell">
            <div><div><div>41.66%</div></div></div>
        </div>  
    </div>
</div>

我会说使用额外的 div 来获得边距是有点过头了,但不幸的是 CSS 没有“边距框”模型,它实际上可以解决十亿个问题。

这么多的嵌套代码可能会让您思考“为什么不使用其他技术?”因为这可能会导致更少的代码。对于一个非常具体的愿望,情况就是如此。然而,其他技术通常涉及浮动或绝对定位。这些技术不能达到同样的效果:例如,浮动可以实现长度相等的列,但是当你想要一个边框或边距时,你会发现自己有麻烦了。对于绝对定位,它更像是相反:您可以解决边距问题,但高度只能基于一列。

在我看来,CSS 未能满足要求。虽然要更换表来代替 positiong,但经过这么多年,仍然不可能得到相同的结果。要实现“圣杯中的圣杯”,表格结构不仅是最简单的方法,也是唯一的方法……至少,据我所知,在尝试了数百种可能性之后。

剩下的问题是:如果您将 div 用作表格,为什么还要使用它们?这一点我自己也不是很明白,但人们似乎有他们的理由。

【讨论】:

【参考方案6】:

获得相同效果的更简单方法是让列中的内容创建您的装订线,而不是对列本身应用边距/填充。这可以通过固定、流体、弹性等网格来完成。

例如:

/* Gutters */
h1, h2, h3, h4, h5, h6,
p, ul, ol, blockquote,
hr, address, pre, object, fieldset

    margin-right: .75rem;
    margin-left: .75rem;
    padding-right: .75rem;
    padding-left: .75rem;

这还简化了列大小、嵌套以及将背景应用到乐高积木。

【讨论】:

【参考方案7】:

我为此使用了 OOCSS 的网格

https://github.com/stubbornella/oocss

我最近在自己的网站上放了一个演示,因为网上没有合适的例子:(

http://www.leipeshit.com/awesome_stuff/oocss/core/grid/grids_all.html

【讨论】:

【参考方案8】:

查看此线程中的 tyyddot 的答案以获得纯 CSS/HTML(具有等距“列”且不使用 JavaScript 的流体布局)...

Fluid width with equally spaced DIVs

http://jsfiddle.net/thirtydot/EDp8R/

对 JSFiddle 的修改表明“列”可以设置为不同的固定宽度,并且仍然具有相等且流动的边距。

http://jsfiddle.net/EDp8R/43/

最后,另一个例子使用百分比,同时仍然保持相等和流动的边距。

http://jsfiddle.net/EDp8R/45/

我知道这可能不是一个精确的解决方案,但我认为它可以让你非常接近。

【讨论】:

【参考方案9】:

试试这个纯 CSS2 解决方案:demo fiddle

基础 CSS (fiddle 没有化妆品)

html, body 
    padding: 0;
    margin: 0;

#wrap 
    padding-right: 30px;
    overflow: hidden;

.col 
    float: left;
    margin-left: 40px;
    margin-right: -30px;

.col:first-child 
    margin-left: 0;

.small 
    width: 16.66%;

.medium 
    width: 25%;

.large 
    width: 41.66%;

HTML:

<div id="wrap">
    <div class="col small"></div>
    <div class="col medium"></div>
    <div class="col small"></div>
    <div class="col large"></div>
</div>

在 Win7 的 IE7、IE8、IE9、Opera 11.50、Safari 5.0.5、FF 6.0、Chrome 13.0 中测试。


更新:

现在,如果您希望这样处理任意数量的列,则必须向容器中添加一个额外的类,指定列数:

<div class="cols-12 count-04">
    <div class="col width-02"></div>
    <div class="col width-03"></div>
    <div class="col width-02"></div>
    <div class="col width-05"></div>
</div>

请参阅 this updated fiddle 演示多种不同的列计数。

可能的错误:

理论上,恕我直言,这个解决方案应该适用于任何浏览器窗口宽度中每个可能的最小列宽的任意数量的列。但似乎,所有浏览器都证明无法处理:1. 大量 1 列宽的列,或 2. 浏览器窗口宽度较小。

请注意,所有浏览器的最小宽度为 1440 像素,等于 12 乘以 120 像素(所有 10px 边距所占用的空间),都可以很好地处理该解决方案。而且当您使用 2 个或更多列宽列时,对最小浏览器宽度的要求确实下降到 720 像素(6 * 120 像素)。最后一种情况听起来更现实,但我仍然无法解释这种浏览器行为。

我尝试通过引入额外的 last column 类来解决此问题,如 this fiddle 所示,但它并不能解决浏览器宽度较小的问题。它确实解决了由于宽度百分比损坏而导致的微小舍入误差,但我想这个问题可以忽略。

我想听听其他 css 专家的意见,所以我加了一个赏金。

【讨论】:

我将此解决方案从使用内联块修改为更健壮和简单的整洁浮动。 感谢@NGLN - 很好的解决方案,但是它无法与我发布的列配置以外的任何列配置一起使用(这只是一个示例,可能应该提到这一点)我正在研究一个 12 列的 CSS 网格,因此它的用法应该涵盖使用单个 width-12 列或使用 12 个 width-01 列的两种情况(每个都有10px 之间的间距) 或两者之间的任何组合(如发布的示例 那么,基本上你要我们写一个完整的css框架?见鬼,没问题... ;) 查看答案编辑。 哈哈@NGLN - 不,我自己已经解决了很多其他错综复杂的问题。我不希望任何人为我做任何工作,我的问题比这更具体一点。当我在上网本上测试时,解决方案失败了,最大屏幕宽度为 1024(更像是 1002 左右)但是我确实注意到填充(和要同步的边距)如您的更新所示,当随着更多列的添加而增加时,似乎可以修复它。不幸的是,如果不使用 count 类,填充/边距规则无法知道给定目标元素有多少兄弟姐妹,正如您的解决方案所举例说明的那样。 另外(run outta space)想再次感谢@NGLN,您编辑的动态解决方案非常棒,并且肯定是实用的,因为通常一组给定的水平相邻列是在我的实现中包含在 section 中(class 或 HTML5);虽然有一些边缘情况我必须解决(页面宽度的减小导致页边距开始膨胀)。感谢您为此提供赏金,我自己也准备这样做。【参考方案10】:

你为什么不使用

.column > .panel 
    padding: 10px 0 10px 10px;


.column:first-child > .panel 
    padding-left: 0px;

它只会在盒子之间产生 10px 的空间,并且不使用 last-child。

【讨论】:

True @avall - 很好的解决方案,但是我刚刚意识到,根据我当前的实现,:first-child 将不起作用,而是需要:first-of-type,带回 IE问题。

以上是关于CSS 流体列,固定边距;圣杯的圣杯的主要内容,如果未能解决你的问题,请参考以下文章

负边距三栏布局(圣杯布局双飞翼布局)

CSS布局(圣杯布局双飞翼布局水平垂直居中)

CSS布局(圣杯布局双飞翼布局水平垂直居中)

CSS布局(圣杯布局双飞翼布局水平垂直居中)

圣杯布局

圣杯布局