css 网格布局_用CSS网格解决棘手的布局问题

去年,在Mud工作时,我在Warner Brothers Leavesden Park工作室的网站上使用CSS。 我的大部分贡献涉及使用CSS Grid来构建各种组件布局,而我为该站点构建的布局已成为我的一些演讲和文章的主题。

本文是对具有独特布局和一组约束的特定组件的案例研究。 建立一个适合大量需求以及未知内容的布局,需要运用横向思维和大量问题解决方案来找到正确的解决方案。

其中一个组件如下所示:

A component with a large, centred heading, a block of text on the top right and a large image on the left

它由图像或视频,水平和垂直居中的大标题以及一段文本组成。 在这种情况下,文本块与图像的顶部对齐,但是如果由内容作者选择,则文本块也可以与图像的底部对齐。

您可能会觉得不太麻烦,并且使用现代布局方法应该足够简单。 但是此组件带有一系列约束:

  • 标题必须在组件内水平居中,在图像上方垂直居中。
  • 文本块必须与图像的顶部或底部对齐, 除非文本长于可用空间,在这种情况下,文本块应向上延伸(如果与底​​部对齐则向下延伸)。
  • 图像尺寸是未知的,不受宽高比的限制–换句话说,内容作者可以上传任何尺寸的图像,而不会导致图像被裁剪。
  • 标题和文本块的长度也是未知的。

设计本身由一个24列的网格以及该组件的多个变体组成,其中图像和文本块可以与各种不同的网格列对齐。 出于本文的目的,我们暂不关注列轴,因为这里的主要重点是网格项目在行轴上的对齐。

我创建了相同组件的简化视图,这使我们可以更轻松地查看每个元素的边界框。 (想象一下,粉红色的轮廓是组件的边界框。)

Simplified illustration of the component layout

假设对网格容器和直接子项(我们的网格项)进行了以下标记-出于本文的目的,我们将忽略这些元素内的所有内容,以便我们仅关注布局:

< articleclass=" grid ">
	< divclass=" grid__heading "> Heading </ div>
	< figureclass=" grid__image "></ figure>
	< divclass=" grid__text "></ div>
</ article>

我们使用以下CSS定义网格并将项目放置在列轴上:

.grid{
	display: grid ;
	grid-template-columns:minmax( 0 , 1fr )repeat( 24 ,minmax( 0 , 60px ))minmax( 0 , 1fr );
	column-gap: 20px ;
}

.grid__heading{
	/* Using a negative line for the grid-column-end value allows us to easily center the position of the heading when we have a large grid */
	grid-column: 5 / -5 ;
}

.grid__image{
	grid-column: 2 / 16 ;
}

.grid__text{
	grid-column: span 5 / -1 ;
}

如果您对我们用于grid-template-columns属性的值感到好奇,请在此处进行解释

现在我们需要定义网格行。 我最初的想法是我们可以如下定义grid-template-rows属性:

.grid{
	grid-template-rows: 1fr auto 1fr ;
}

这为我们提供了一个中心行,该行的标题值为auto (因为我们不知道这将持续多久,并且我们希望轨道增长以适合内容),以及周围的两行1fr 。 这两个外部行将占据可用空间的相等比例。 如果我们设置row-gap: 40px (在这里将速记gap用于grid-row-gapgrid-column-gap ),那么我们将在标题的上方和下方获得40px的装订线,以保持其与文本块之间的空间。

Component with row tracks highlighted

我们还可以将弹性对齐属性与Grid一起使用,这在这里将非常有用。 我正在使用align-items: center以水平居中我们的网格项目。 目前尚不清楚为什么需要这样做,但是我们很快就会发现,如果我们的文本内容长于可用空间,它会变得更加有用。

.grid{
	/* ...Other grid code */
	grid-template-rows: 1fr auto 1fr ;
	gap: 40px 20px ;
	align-items: center ;
}

现在我们可以将网格项放置在行轴上:

.grid__heading{
	grid-row: 2 ;
}

.grid__image{
	/* From the start of the grid to the end */
	grid-row: 1 / -1 ;
}

.grid__text{
	grid-row: 1 ;
}

我们所有的项目当前都在其网格框中居中对齐,但是如果我在文本块上使用align-self: flex-start ,则该项目将与组件顶部对齐,而标题和图像居中对齐(由于到align-items: center ,这是我们在网格本身上指定的)。

.grid__text{
	grid-row: 1 ;
	align-self: flex-start ;
}

到目前为止,一切都很好。 看来我们已经确定了这种布局。 仅有一个问题:当文本块的长度大于图像标题和图像顶部之间的距离时,组件将扩展以容纳它,将图像推向下方(这是我们想要的)–但不幸的是,网格也会扩展,从而在图像下方提供了额外的空间:

Showing extra space created at the bottom of the grid

如果我们将几个组件堆叠在一起,那么它们之间的垂直空间将是不均匀的。 这不是理想的。 我们想要的是组件在顶部(文本块的侧面)垂直而不在底部垂直增长。

The same grid with the height of the top row only increased
解决方法:顶部的轨道尺寸增加,但底部的轨道尺寸不增加

为了解决这个问题,我必须创造性地思考! 让我们逐步介绍解决方案。

首先,我们将三行轨道的大小更改为auto

.grid{
	grid-template-rows: auto auto auto ;
	gap: 40px 20px ;
	align-items: center ;
}

然后,我们可以在现有行上方添加一个额外的行,高度为1fr 。 在行轴上使用fr单位可能发生的情况可能不太明显。 在列轴上,我们知道网格的宽度(默认情况下为100%),因此很容易想象1fr的列轨迹填充了该空间的一部分。 当涉及行轴时,在这种情况下,网格的高度将取决于当前从第一行到最后一条网格线放置的最高网格项目(图像)的高度。

.grid{
	grid-template-rows: 1fr auto auto auto ;
	gap: 40px 20px ;
	align-items: center ;
}

我们添加的行实际上是一个隐藏行–除非我们在其中放置内容,否则它将折叠为0

Hidden row at the top of the grid

在查看项目放置之前,我们还需要对网格容器做几件事。 我们将row-gap设置为0,并在标题行及其相邻行之间添加40px的轨道。 我们也可以删除align-items: center ,因为我们将不再需要它。

.grid{
	grid-template-rows: 1fr auto 40px auto 40px auto ;
	gap: 0 20px ;
}

现在,我们的网格已经有六行了,要直观地看到在行轴上放置网格项的位置并不容易。 还有更多的网格线可以跟踪! 在这里命名网格线将非常有帮助。 然后,我们可以引用这些行名称来放置网格项。

.grid{
	grid-template-rows:
		[text-start] 1fr [image-start] auto [text-end]
		40px [heading-start] auto [heading-end] 40px
		auto [image-end] ;
	gap: 0 20px ;
}

.grid__heading{
	grid-row: heading ;
}

.grid__image{
	grid-row: image ;
}

.grid__text{
	grid-row: text ;
	align-self: flex-start ;
}

眼神敏锐的读者可能会注意到,我们的文本块现在跨越了两条轨道(从网格线1开始),并且我们的图像不再从网格线1开始,而是从网格线2开始。 但是,视觉上没有任何变化。

当我们在文本块中添加更长的文本段落时,便可以看到这些更改的好处。 在网格的底部添加关键的是, 没有多余的空间-隐藏的行,我们添加的膨胀,同时图像和标题仍然是集中相互对齐!

Hidden row expanding when text block is longer
网格的第一行随着文本内容的增长而扩展

希望现在更加明显了,为什么我们需要将row-gap设置为0并使用多余的轨道作为装订线:如果我们有40px row-gap ,即使文本内容较短,也可以在网格顶部看到因此,第一首曲目已完全崩溃。 不幸的是,我们不能在单个轴上为gap属性设置不同的值,否则我们将不需要这些额外的行。

对于不同的组件变体(文本块位于标题下方而不是上方),我们可以更改grid-template-rows属性以包括隐藏行和结尾而不是开头。

.grid--text-bottom{
	grid-template-rows:
		[media-start] auto 40px
		[heading-start] auto [heading-end]
		40px [text-start] auto [media-end]
		1fr [text-end] ;
	gap: 0 20px ;
}

这是完整的演示:

演示地址

该解决方案实际上并未在生产中实施,直到很久以后我才意识到这一点! 尽管这不是一个常见的布局问题,但我希望这能演示一些可用于Grid生成异常布局的技巧和方法。

翻译自: https://css-irl.info/solving-a-tricky-layout-problem/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值