响应式网格布局
从文章标题中不难发现这篇文章要和大家聊的是两个东东,即响应式和网格。从布局系统来说,响应式布局和网格布局都不是什么新东西了。但是他们结合在一起,可以让响应式布局变得更灵活。正如@Keir Watson所说,只要20行代码就可以实现响应式网格布局。不过,我们今天来看两个比较有意思的布局,看上去并不是很容易实现的布局效果。
案例背景和特征
接下来的案例是来自于CodePen上的。在节前看到两个有关于网格的布局,觉得蛮有意思的,所以想以这两个案例为基础,来和大家聊聊怎么通过CSS Grid来实现看上去较为复杂的响应式布局。
第一个案例是来自于@Andy Barefoot的《Responsive CSS Grid - Books》:
第二个案例是来自于@Andy Barefoot的《Responsive Product Grid with layered background》:
这两个案例都有着一些共同的特征,比如说都是响应式布局(即,随着视窗大小,布局会有所差异),就拿第一个案例来说,你尝试着拖动视窗大小时,能看到类似下图这样的效果:
第二个特征是视觉效果有层的叠加,层级看上去较为复杂:
第三个特征就技术上采用了相似的CSS特性,比如CSS的Grid布局、自定义属性,媒体查询等。
简单分析层级
两个案例都有着相似的层级结构,其中HTML都非常的简单
<!-- HTML -->
<li>
<img />
</li>
但每个卡片有四层:
除了HTML元素之外还借助了CSS的伪元素::before
和::after
。他们的层级关系是:
我们用动画来模拟这几个层合并的过程:
相对而言,第一个案例要比第二个稍向复杂,毕竟第一个示例未采用图片资源,而且采用了一些新的CSS特性。接下来我们将以第一个案例为例。
实现单个图形效果
稍微花一点点时间来看看单个图形的实现过程,以及运用了哪些技术。
其实这个效果有点类似于《CSS如何实现交叉布局》一文中提到的交叉效果。不过相比而言要更简单一点。
我们来看怎么实现的。
前面已经介绍了它的实现原理和层级的关系。有了这个基础之后,我们就可以快速使用CSS来完成。它的HTML结构很简单,就是一个元素标签(比如div
)包裹了一个<img>
标签。
<!-- HTML -->
<div class="box">
<img src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/881020/book34.jpg" alt="">
</div>
从效果上可以得知,容器是一个1:1
的尺寸,在CSS中有多种方式可以实现该效果,大家可能熟悉的就是通过padding-bottom: 100%
来实现1:1
的容器(即根据纵宽比来完成):
.box {
background-color: #eebc1f;
width: 20vw;
padding-bottom: 20%;
transform: rotate(45deg)
}
注意,padding
取值为%
时根据父元素的width
来计算。这个时候你看到的效果如下:
有关于纵宽比方面的内容在社区中讨论比较多了:
但随着aspect-ratio
属性的出现,实现1:1
的效果更为容易:
.box {
aspect-ratio: 1 / 1;
}
在这个基础上,通过::before
和::after
两个伪元素来构建另两个层:
.box::before,
.box::after {
content: "";
display: block;
width: 100%;
height: 100%;
position: absolute;
background-color: #068d7e;
}
在这个示例中有一点不一样,采用了最新的渐变属性conic-gradient()
绘制所需要的形状效果:
.box::before {
background: conic-gradient(#eebc1f 25%, #068d7e 0 50%, #eebc1f 0) 100% 100% /
180% 180%;
}
.box::after {
background: conic-gradient(#eebc1f 75%, #068d7e 0) 0 0 / 180% 180%;
}
离我们的目标越来越近了,为了让<img>
的上下两层不会遮盖整个图像,这里需要再用到clip-path
属性,裁剪出所需要的效果:
.box::before {
clip-path: polygon(0 0, 100% 0, 100% 20%, 20% 20%, 20% 100%, 0 100%);
}
.box::after {
clip-path: polygon(80% 20%, 100% 0, 100% 100%, 0% 100%, 20% 80%, 80% 80%);
}
在clip-path
中每个点的坐标对应如下:
这个时候,将它位合成在一起就得到我们想要的效果:
实现单个效果之后,要实现整个列表效果就要轻易地多了。
网格布局
在上面我们看到的只是一个列表项的效果,如果我们将N
个这样的效果放到一起,就会离我们想要的效果越来越近。虽然列表项目的数量多起来了,但它们的结果是相同的:
<!-- HTML -->
<ul>
<li><img src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/881020/book10.jpg" alt=""></li>
<!-- N个li -->
</ul>
在这里采用的是grid
布局:
ul{
display:grid;
grid-template-columns: repeat(var(--columns),1fr);
}
注意,在上面的示例代码中有--columns
,这个是CSS的自定义属性,在:root
选择器中显式声明了:
:root {
--columns: 3;
}
li:nth-child(2n){
grid-column-start:2;
}
在构建响应式布局时,依旧是以移动端先行,正如上面的代码所示。在类似手机端的设备,你看到的效果类似下图:
响应式布局
在很多开发者的印象中,构建一个响应式布局是离不开CSS媒体查询特性。特别是CSS的Grid布局到来之时,实现一些响应式布局效果可以不需要媒体查询特性:
比如:
.auto-grid {
--auto-grid-min-size: 16rem;
display: grid;
grid-template-columns: repeat(auto-fill, minmax(var(--auto-grid-min-size), 1fr));
grid-gap: 1rem;
}
就可以轻易的实现类似下图的布局效果:
如果你对这方面感兴趣的话,可以阅读《Create a responsive grid layout with no media queries, using CSS Grid》一文。
但是,针对这个案例,要实现响应式布局还是需要依赖媒体查询做相应的处理:
@media (min-width:600px){
:root {
--columns: 5;
}
li:nth-child(2n){
grid-column-start:auto;
}
li:nth-child(4n-1){
grid-column-start:2;
}
}
@media (min-width:900px){
:root {
--columns: 7;
}
li:nth-child(4n-1){
grid-column-start:auto;
}
li:nth-child(6n-2){
grid-column-start:2;
}
}
@media (min-width:1200px){
:root {
--columns: 9;
}
li:nth-child(6n-2){
grid-column-start:auto;
}
li:nth-child(8n-3){
grid-column-start:2;
}
}
@media (min-width:1500px){
:root {
--columns: 11;
}
li:nth-child(8n-3){
grid-column-start:auto;
}
li:nth-child(10n-4){
grid-column-start:2;
}
}
@media (min-width:1800px){
:root {
--columns: 13;
}
li:nth-child(10n-4){
grid-column-start:auto;
}
li:nth-child(12n-5){
grid-column-start:2;
}
}
@media (min-width:2100px){
:root {
--columns: 15;
}
li:nth-child(12n-5){
grid-column-start:auto;
}
li:nth-child(14n-6){
grid-column-start:2;
}
}
在该基础上再针对性的添加一些样式,比如说对不同的列表使用不同的颜色,就能得到我们想要的布局效果。
注意,在这里除了使用了媒体查询之外,还使用了CSS的伪类选择器,按一定的规则对li
设置不同的肤色和控件其在网格空间中的位置。还有就是,CSS的自定义属性和媒体查询结合在一起,可以让响应式布局更容易一点。如果你对这方面感兴趣的话,可以阅读:
- Responsive Designs and CSS Custom Properties: Defining Variables and Breakpoints
- Responsive Designs and CSS Custom Properties: Building a Flexible Grid System
小结
是不是很简单,虽然在该示例中运用到了不少的CSS特性,比如CSS自定义属性、媒体查询、clip-path
、渐变等。但他们都已不是最新的特性了。这也再次证明,将不同的特性结合在一起可以构建出任意你想要的效果。在整个效果中,不管是网格布局还是响应式布局都不是难点,其中最为复杂的是交叉布局效果。但运用好层级关系和裁剪规则,这些都是易事。
如果你感兴趣的话,建议你自己亲手写个Demo。体验一下,也能加深印象。如果你在这方面有更好的建议或经验,欢迎在下面的评论中与我们共享。