制作两栏布局的 6+5 种方法:从相当合理到完全错误

一个挑战

假设您需要创建一个两列布局。是的,最简单的那种:左边一列,右边一列,中间有一些空隙。有一个明显的现代解决方案:

.columns {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 20px;
}

完毕!当然可以,但是如果我们需要支持一些较旧的浏览器怎么办?然后是 Flexbox。好的!那么文本从一栏流到另一栏呢?没问题,多列。旧的电子邮件客户端怎么样?好吧,我们中的一些人仍然记得如何使用表格布局。

你看,这就是 CSS 的美妙之处:几乎每个问题都有多种解决方案,因此,您可以选择适合您的确切需求的解决方案。但不仅仅是 CSS,还有许多 HTML 和 SVG 技巧在某些情况下可以为您提供帮助。它就像一种自然语言:你的词汇量越大,你就越能表达自己。

甚至还有一个基于此的面试策略:你可以要求人才想出多种方法来解决同一个简单的任务。而这正是本文的想法来源。

我的一个朋友曾经用求职面试的任务来挑战我:你知道多少种制作双栏布局的方法?多么愚蠢的问题,对吧?但这让我比我想象的更深入。有一阵子我什么也想不起来,直到我在脑海中仔细考虑了所有可能和不可能的想法。它归结为 11 种制作带有间隙的两列的方法。

但我更愿意称他们为 6+5,将他们分为两组:

  • 六个非常合理的,它们有意义并且可以用于实际的生产项目(或用于)。

  • 五个完全错误的,有一些怪癖,看起来或行为很奇怪,但仍然完成了任务。

顺便说一句,在所有现代浏览器中,结果看起来都一样,即使是五个奇怪的浏览器。

设置和规则

为了让它更接近现实,我决定将整个事情分成两个部分:

列:固定布局,有两列和一个间隙。

新闻:适合专栏的流动卡片。

这个想法是有一个可以填充真实内容的列组件,而不仅仅是绘制两个彼此相邻的彩色框。

制作两栏布局的 6+5 种方法:从相当合理到完全错误_第1张图片

新闻组件将始终保持不变,我们将只使用栏目组件。第一个新闻将有一个浅绿色的背景,第二个 - 著名的桃花心。

合理六

您将如何对合理选项列表进行排序?好吧,可能不是按字母顺序排列的。从最好到最坏?他们都擅长某些情况,并具有一些独特的优势。所以我决定按照历史的顺序:我先从我学过的开始,到现代的结束。

table

演示:两列和一个表格间隙

表格是浏览器中第一个可用的布局工具。早在 2002 年,我就用它们创建了我的第一个网页。要制作表格布局,您需要一个父包装器

、一些 行和用于列的                                      
单元格。


我将对类名使用 BEM 表示法,就像我在真实项目中所做的那样。我们将为所有演示使用几乎相同的列组件结构,但在某些情况下,我们不需要第一/第二修饰符。

值得注意的是,尽管表格被列在“合理”组中,但它们已经过时了,应该只用于……你知道的,表格和表格数据。您可能有理由将它们用于电子邮件布局,但我什至不确定是否还需要它们。从可访问性的角度来看,这是一场噩梦,所以让我们把它当作一堂历史课。

为了使表格消失并表现得像一个中性列组件,我们需要修复一些东西:border-collapse 和 padding 属性以删除额外的填充和 vertical-align: top 以将内容对齐到顶部。是的,表格曾经是垂直对齐事物的最简单方法。

.columns {
    border-collapse: collapse;
}

.columns__item {
    padding: 0;
    width: 50%;
    vertical-align: top;
}

为了在 2002 年留下一个空白,我会在中间使用另一个空单元格和一些额外的元素来固定宽度。疯狂的时代!但今天我更喜欢一些填充:左边 10px,右边 10px,不要太花哨。

.columns__item--first {
    padding-right: 10px;
}

.columns__item--second {
    padding-left: 10px;
}

您可能认为在

上使用 display: table 可以被视为制作两列布局的另一种方式。但我认为表格就是表格,这种行为是来自浏览器还是作者风格并不重要。

news来了:


    Title
    Content

一旦我们在每个表格单元格中都有两个新闻,第一个“合理”的布局就准备好了。还有十个去!

Floats

演示:两列和一个带浮动的间隙

我学到的下一个布局技术是浮动。它们是为类似报纸或杂志的内容布局而发明的,在这些布局中,文本会“漂浮”在图片、引语或类似元素周围。我首先在 Adobe PageMaker 中尝试了这一点,当时我正在布置一份实际的报纸,而且在 Web 上也可以使用浮动效果非常好。

一些聪明的人意识到,如果你去掉文本,将一个框向左浮动,另一个向右浮动,这样就形成了一个布局!尽管确保浮动元素不会争夺空间很重要,否则它们会开始从行中掉落。

在这种情况下,我们不需要任何特殊的 HTML 元素来使其工作,所以让我们坚持使用抽象 div。毕竟,这只是一个布局。


    
        
    
                  

这是浮动的主要问题:它们需要被“清除”。如果您的容器中有浮动元素,它们会掉出容器并且容器会折叠到零高度。

清除浮点数主要有两种方式:

更改容器的某些属性。

在容器的末尾放置一些虚假内容。

让我们选择第一个选项。回到浮动布局时代,我们会使用 overflow: hidden,它有一个明显的缺点:内容被剪裁。但是今天我们可以使用一个特殊的显示值:

.columns {
    display: flow-root;
}

我会称它为 display: clear-floats,但这就是我没有机会进入 CSSWG 的原因。

现在我们需要设置列的宽度,因为它们不像表格单元格那样粘在一起,所以可以将它们分开,宽度的一半减去间隙的一半。那时候 calc 的魔力还没有,就像 border-radius 一样,但现在是 2022 年,所以:

.columns__item {
    width: calc(50% - 10px);
}

最后,让我们将它们浮动到父对象的不同侧面:

.columns__item--first {
    float: left;
}

.columns__item--second {
    float: right;
}

你有它!第二个稍微“合理”的双列选项。让我们试试下一个!

02、内联块

演示:两列和一个内联块的间隙

基于内联块的布局大约与浮动同时流行。但他们对付起来有点挑剔。我们将使用与浮动相同的标记,但我们不需要任何第一/第二修饰符。

首先,我们需要从我们的列中创建内联块以使整个事情正常进行。因为它们是内联的,所以很乐意保持“内联”,但它们也是块,您仍然可以设置它们的宽度(与内联元素不同)。让我们也将它们对齐到顶部,而不是默认基线。

.columns__item {
    display: inline-block;
    width: calc(50% - 10px);
    vertical-align: top;
}

制作两栏布局的 6+5 种方法:从相当合理到完全错误_第2张图片

现在我们的news块在“栏目”中,但它们之间的差距看起来不对。它看起来像一个典型的白色空间。

好吧,因为它是!我们 HTML 中的所有嵌套都被浏览器例行压缩到一个空白区域,因为它是一个内联上下文。

有两种流行的方法可以摆脱它:

  • 将父项的字体大小设置为零。

  • 删除标记中标签之间的所有空格。

第二种方式相当脆弱,所以让我们使用第一种方式。由于 font-size 是一个继承属性,我们不要忘记为内容恢复它。

.columns {
    font-size: 0;
}

.columns__item {
    font-size: 16px;
}

一旦我们的两个列都紧挨着放置,我们就可以在它们之间精确地留出 20px 的间距。由于它是内联上下文,我们可以将我们的父元素视为一个句子,这使得嵌套列成为单词……你看到它的去向了吗?那就对了!word-spacing 属性可以解决问题。

.columns {
    word-spacing: 20px;
    font-size: 0;
}

.columns__item {
    word-spacing: normal;
    font-size: 16px;
}

我们不要忘记将嵌套元素重置为正常,就像我们对字体大小所做的那样。

那是第三种方式,接下来的三种方式终于开始有意义了,我保证。

03、多列

演示:两列和多列的间隙

现在是第一个为布局设计的布局技术的时候了。嗯,差不多。多列可以获取任何内容并使其在列之间流动,并在其间留有一些原生间隙。正如在报纸上看到的那样!

.columns {
    columns: 2 20px;
}

而已!我不是像 flex 这样神奇的速记属性的忠实粉丝,但我就是无法抗拒。在一个属性中设置了两列和一个 20 像素的间距!是不是很优雅?但是有一点不对劲:

由于内容从一栏流向另一栏,因此一些块部分也在流动。它看起来像一个破损的门户或一台旧电视,但有一个简单的解决办法:礼貌地避免对残酷的闯入财产的价值。

.columns__item {
    break-inside: avoid;
}

那很快!第四种双列布局。让我们看看是否有比这更好的东西。

04、弹性盒

演示:两列和一个 Flexbox 间隙

现在最流行的布局技术来了。它已经存在了一段时间,但在过去,浏览器实现存在差异,并且只是明显的错误使得 Flexbox 难以使用。但现在不是了!

现在很简单:

.columns {
    display: flex;
    gap: 20px;
}

.columns__item {
    width: 50%;
}

但是,如果您不能只支持最近的浏览器版本,那么您将不得不告别 gap 属性并使用一些额外的代码在列之间留出一些空间。将列推到两侧并确保它们的宽度像我们之前所做的那样使用 calc 设置。

.columns {
    display: flex;
    justify-content: space-between;
}

.columns__item {
    width: calc(50% - 10px);
}

最后,一些现代且可用的东西,已经是第五个了!与我们讨论过的许多技术不同,Flexbox 在今天很重要。但这些天我经常寻求下一个选择。

05、网格布局

演示:两列和网格布局的间隙

说真的,网格布局在几乎所有布局情况下都非常有意义,即使对于像在单词旁边放置一个图标这样的微布局也是如此。记住?这就是我们的出发点:

.columns {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 20px;
}

它的美妙之处在于整个布局由容器定义。当然,在某些情况下,您需要将一些属性应用于嵌套元素,但可以仅使用容器的属性来实现基本布局。它对于使您的布局响应媒体查询特别有用。

此外,由于 grid-gap 和后来的 gap 属性是初始网格布局实现的一部分,与 Flexbox 中的 gap 相比,您不必担心浏览器兼容性。

制作两列布局的第六种方法太简单了。别担心,我们会遇到一些非常奇怪的事情。

怪五

这里没有历史顺序。我只是试图列出从最不奇怪到完全错误的选项。又是什么问题让我把这些方法分成了一个特殊的组?

首先,他们并不总是能很好地处理内容流。在 Web 上,我们使用的原则是下一个内容块将紧跟在前一个内容块之后,而不是在它上面。一旦前一个块变小或变大,所有后续块都会随之上下移动。

如果您曾经手动编写过 SVG 文件,您可能知道我在说什么。想象一下,如果每个块都绝对定位在文档的左上角。那将使我们的工作更加困难。对于 SVG 作为图像格式来说完全没问题,但对于内容布局来说是不可接受的。

其他方法使用额外的标记使事情变得过于复杂,滥用某些 CSS 属性,使其只能在单个浏览器中工作,或者损害内容的可访问性。不过,让我们一一探索它们以学习新知识,或者至少获得一些乐趣。

定位

 演示:两列和一个带定位的间隙

定位不是最好的布局技术,因为它破坏了内容流,而内容流是 Web 的主要原则之一。但在某些情况下它仍然是一个有用的工具。与 SVG 中的形状不同,我们不必每次都从文档的左上角定位元素:幸运的是,有一种嵌套定位的方法。

让我们通过 position: relative 将父组件保持在流程中。在这种情况下,嵌套列定位将从父组件开始,即使它会像浮动一样折叠到零高度。不幸的是,没有办法“清除”定位元素。

.columns {
    position: relative;
}

.columns__item {
    position: absolute;
    top: 0;
    width: calc(50% - 10px);
}

由于绝对定位元素处于它们的平行世界中,它们往往以一种有趣的方式包含事物,所以让我们用 calc 来限制它们的宽度。就像浮动一样,让我们将列推到两侧,这样它们就不会重叠。

.columns__item--first {
    left: 0;
}

.columns__item--second {
    right: 0;
}

嗯,这个演示有些不同!与之前的紫色演示不同,这个演示的页面背景充满了番茄色。那是因为突出这个群体的性质看起来稍微危险一些。

所以你有它:第一个奇怪的方式。没什么可怕的,对吧?当然,我们只是在热身。

书写方式

 演示:两列和一个带有书写模式的间隙

要了解下一个方法的工作原理,让我们考虑一下这段文字:不是它的含义,而是它的形状。我是用水平线写的,从上到下一条接一条。这种行为在许多语言中都很常见,并由 writing-mode 属性控制。在本例中,它的值为 horizontal-tb,意思是“水平,从上到下”。

但在某些语言中,文本可以垂直列显示,而不是水平行。这为我们提供了另外两个书写模式值:vertical-rl 和 vertical-lr。值的第一部分相当简单,第二部分取决于文本的方向:LTR 或 RTL。无论如何,在这种垂直模式下,新行从前一行向左或向右移动。

知道了让我们尝试一个愚蠢的事情:将父块的书写模式更改为垂直,这样行就会变成列并从右边开始。

.columns {
    writing-mode: vertical-lr;
}

看,这已经看起来像一个布局了!但有些事情需要修复才能使其可用。就像在 font-size: 0 的情况下,我们需要将列的 writing-mode 恢复到以前的状态。当我们这样做的时候,让我们为我们的列添加宽度。

.columns__item {
    width: 390px;
    writing-mode: horizontal-tb;
}

不幸的是,我们无法在 Flexbox 或 Grid 布局之外使用 gap 属性。因此,让我们使用古老的技巧:一列后跟另一列将获得正确的边距。

.columns__item + .columns__item {
    margin-left: 20px;
}

我可能应该改用 .columns__item——第一个选择器,但这太容易了。我在这里尝试使用尽可能多的技巧!

希望你能在 font-size: 0 和 writing-mode: vertical-lr 情况下闻到同样奇怪的东西:它们既脆弱又滥用了不适合布局的属性。

仍然是第二个奇怪的双列布局。准备好再来一个了吗?我们走吧!

SVG

演示:两列和一个 SVG 间隙

我已经提到 SVG 只是一种可以手动编码的图形格式,但不符合我们的布局需求。对不起,我骗了你。你一开始没有准备好接受真相。但是现在你已经经历了很多奇怪的事情并且准备好迎接任何事情。

让我们从 CSS 开始……然后马上结束。这是我们唯一需要的样式。

.columns {
    display: block;
    width: 100%;
    height: 100%;
}

你已经可以看到这种方式对内容流的友好程度不亚于绝对定位(一点也不)。至于 HTML,它看起来不会很漂亮:


    
        
            Title
            Content

             
                          Title             Content

             

好吧,它不完全是 HTML,而是带有一些 HTML 的 SVG。尽管如此,在 HTML 文档中。我不知道它是否合法,但它是完全有效的:

文件检查完成。没有错误或警告显示。

通常,除了类似命名的

你可能感兴趣的:(html,java,css,前端,javascript)