CSS——网格布局(display: grid)之下篇

CSS------网格布局(display: grid)之下篇

前面我们介绍了网格布局的基础的创建以及一些比较基础的属性,下面我们将介绍网格布局的剩余部分,还将结合实例来进行细致的讲解(图文并茂,生动形象有内涵)。

显式网格和隐式网格

显式网格 :是指在CSS中明确定义 的网格轨道。包括在 grid-template-rowsgrid-template-columns 属性中指定的行和列。显示网格的大小和位置是固定的,由开发者在CSS中明确指定。

隐式网格 :指在显示网格之外 自动创建的网格轨道。当网格项没有足够的显示网格轨道来容纳时,浏览器会自动创建 额外的轨道来放置这些网格项。隐式网格的大小和位置是自动计算的,基于网格项的需求和网格容器的尺寸。

如果网格元素放在声明的网格轨道之外,就会创建隐式轨道,直到包含该元素(如上图所示),同时在指定网格线的时候,隐式网格轨道不会改变负数的含义 。负的网格线编号仍然是从显式网格的右下开始 的。

隐式网格轨道默认的大小为auto,也就是它们会扩展到能容纳自身的宽度(包含内容、内边距、边框和外边距)。下面介绍三个与之相关的属性。

grid-auto-flow 属性

首先来看取值吧:

css 复制代码
grid-auto-flow: row;
grid-auto-flow: column;
grid-auto-flow: dense;
grid-auto-flow: row dense;
grid-auto-flow: column dense; 

其中:

  • row
    多的格子一行一行陈列。默认值。
  • column
    多的格子一列一列排列。
  • dense
    多的格子空白填充。

row 与 column 之分

如果我们创建一个网格布局,可以看到,网格元素之间是默认占满一行,然后一个挨着一个地向下排列的。

html 复制代码
 <style>
   .container {
     display: grid;
   }

   .item {
     background-color: #ccc;
   }
 </style>

<body>
  <main class="container">
    <div class="item">1号盒子</div>
    <div class="item">2号盒子</div>
    <div class="item">3号盒子</div>
    <div class="item">4号盒子</div>
    <div class="item">5号盒子</div>
  </main>
</body>

如果此时我们为网格容器添加grid-template-columns: 1fr 1fr,使之分为两列,可以看到:这些盒子在填满本行之后,才去换行显示。那你可能会说了:"这不是理所当然的吗?",嘿嘿,这可没有那么简单,这是因为grid-auto-flow属性默认设置为row,即默认先填充横向,再填充纵向

如果我们修改grid-auto-flow: column

html 复制代码
 <style>
   .container {
     display: grid;
     grid-template-columns: 1fr 1fr;
     grid-auto-flow: column;
   }
   .item{
 	 background-color: #ccc;
   }
 </style>


<body>
  <main class="container">
    <div class="item">1号盒子</div>
    <div class="item">2号盒子</div>
    <div class="item">3号盒子</div>
    <div class="item">4号盒子</div>
    <div class="item">5号盒子</div>


  </main>
</body>

那么会产生如下的效果:

原因是 :我们设置了grid-auto-flow: column,故就先纵向填满 ,然而我们没有明确的划分出行数,所以就默认仅有初始元素所在的第一行,这就导致所有的子元素会横向排列成一行,后面的第3、4、5列没有划分大小,所以他们就fit-content,然后剩下的第1、2列平分剩下的空间( fr单位的优先级是最低的,优先级顺序以及fit-content的解释可以看CSS------网格布局(display: grid)之上篇)。

dense 的作用

dense 翻译为稠密的 ,我们打个比方,如果有一片四四方方的农田,每家每户都各自分有一块,一开始大家都在种。如下图:

直到有一天,中间的一块田的主人王老二进城打工了,这片田就荒废了,远远望去,中间秃了一块。如下图:

村里人看到王老二进城打工赚大钱了,也就纷纷效仿,渐渐的,原本整整齐齐的一大块地,变得稀稀拉拉的。如下图:

这时候村长说了,"现在的地太分散了,为了方便管理,我们重新规划一下地块"。经过又一年的种植,如下图:

大家发现,村长让原本分散的地块变得稠密了,于是就给村长起了个外号"dense"。

我们再用代码演示:我们设置第一个元素在第二列的位置

html 复制代码
 <style>
   .container {
     display: grid;
     grid-template-columns: 1fr 1fr;
     grid-template-rows: 1fr 1fr;
   }

   .item{
 	 background-color: #ccc;
   }
   
   .item:nth-child(1) {
     grid-column: 2 / 3;
   }
 </style>
 
<body>
  <main class="container">
    <div class="item">1号盒子</div>
    <div class="item">2号盒子</div>
    <div class="item">3号盒子</div>
    <div class="item">4号盒子</div>
    <div class="item">5号盒子</div>
  </main>
</body>

可以看到,左上角的位置空出来了(变得稀疏了)

这时,我们添加grid-auto-flow: dense(row是默认的),会看到:2号盒子填补了空缺的位置

如果我们设置了 grid-auto-flow: column dense,那么就会是以下的效果:

嗯,dense就是这样的,稍后实例中会用到。

P.S. 貌似有一个bug,如果在明确指定 了某个子元素不在其默认位置时,浏览器渲染时会默认产生dense的效果。何为明确与不明确呢?比如刚才grid-column: 2 / 3仅指定了子元素的列的位置,没指定行的位置,那么这就算不明确指定;如果grid-column: 2 / 3 & grid-row: 1 /2或者 gird-area: A,这个元素的位置是确定的,那么这就算明确指定,在此时,浏览器渲染时会默认产生 dense 的效果。

grid-auto-columns & grid-auto-rows 属性

前面我们看到,在仅规定两列的情况下,隐式网格轨道的大小是 fit-content的,grid-auto-columns & grid-auto-rows 两个属性就是规定了隐式轨道的大小。

实战强化

注意:下面的部分会用到Flexbox(弹性盒子)布局部分的知识,该部分内容可以参考本人的另一篇文章CSS------弹性盒子布局(display: flex)

目标效果

下面我们要实现一个如下图的效果

我们可以看到图片有大有小,但是它们却能够网格对齐,仔细看还会发现,它们的顺序不是按照从左到右排序的,这个可以先联系一下 grid-auto-flow: dense

步骤

创建网格布局
html 复制代码
<style>
	body {
      background-color: rgb(254, 226, 181);
      font-family: Helvetica, Arial, sans-serif;
    }
    
    .portfolio {
      display: grid;
      grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
      grid-gap: 1em;
    }

    .portfolio>figure {
      margin: 0;
    }

    .portfolio img {
      max-width: 100%;
    }

    .portfolio figcaption {
      padding: 0.3em 0.8em;
      background-color: rgba(0, 0, 0, 0.5);
      color: #fff;
      text-align: right;
    }

    .portfolio .featured {
      grid-row: span 2;
      grid-column: span 2;
    }
  </style>

<body>
  <div class="portfolio">
    <figure class="featured">
      <img src="./images/pic1.jpg" alt="">
      <figcaption>1</figcaption>
    </figure>
    <figure>
      <img src="./images/pic2.jpg" alt="" />
      <figcaption>2</figcaption>
    </figure>
    <figure>
      <img src="./images/pic3.jpg" alt="" />
      <figcaption>3</figcaption>
    </figure>
    <figure class="featured">
      <img src="./images/pic4.jpg" alt="" />
      <figcaption>4</figcaption>
    </figure>
    <figure>
      <img src="./images/pic5.jpg" alt="" />
      <figcaption>5</figcaption>
    </figure>
    <figure class="featured">
      <img src="./images/pic6.jpg" alt="" />
      <figcaption>6</figcaption>
    </figure>
    <figure>
      <img src="./images/pic7.jpg" alt="" />
      <figcaption>7</figcaption>
    </figure>
    <figure class="featured">
      <img src="./images/pic8.jpg" alt="" />
      <figcaption>8</figcaption>
    </figure>
  </div>
</body>

我们创建以上的网格布局是这样的:

其中,我们通过grid-template-columns: repeat(auto-fit, minmax(200px, 1fr))创建了自适应布局,会根据视口的大小自动分配列数,但是每列的最小宽度不会低于200px。

这时候我们发现,容器内部比较稀疏,所以我们想到了grid-auto-flow: dense,为网格容器添加了以上属性之后的效果如下:

我们会发现2、3号是对齐的,但是5、7号以及6、8号是没有对齐的,这是因为在默认情况下,网格元素会扩展到网格单元的大小,但是其子元素不会自动扩展,在这里,网格元素是 <figure>元素,它会自动扩展,但是它的子元素<img><figcaption>不会扩展,网格肯定是对齐的,但是由于以上原因,导致网格单元内部出现了空余部分,如下图:

使网格单元内部所有元素拉伸

这时候我们想到了前面的 Flexbox(弹性盒子)布局,它能够实现其直接子元素自动扩展(与网格布局类似)。所以我们添加以下代码:

css 复制代码
.portfolio>figure {
  margin: 0;
  display: flex;
  flex-direction: column;
}

我们首先将<figure>设置成弹性盒子,让其主轴方向为竖直 ,那么其子元素就可以实现在竖直方向上的扩展。效果如下:

我们发现,这里除了<figcaption><img> 元素之间的间距没了,其余的还是没有变化,嘿嘿,这是为什么呢?

当然是我们忘记给子元素设置flex属性了,可以看到,flex-grow默认值是 0即默认不会放大。

所以我们为子元素设置该属性(建议使用简写,原因见本人的 flex文章,链接在本节开始部分):flex: 1,我们不希望<figcaption>也随之放大,所以我们只为<img>添加该属性。

css 复制代码
figure>img{
	flex: 1;
}

效果如下:

以上看起来以上效果很好了(嗯,我也觉得),前面消失的<img>元素与<figcaption>之间间距我就不追加了,不过有时候要考虑<img>图片的缩放问题。

一个被拉伸的<img>元素的小细节

在前面我们将<img>元素拉伸以填充满父元素,但是这样这会改变图片的宽高比,导致图片变形。好在 CSS 为控制这一行为提供了一个特殊属性 object-fit。默认情况下,一个<img>object-fit 属性值为 fill,也就是说整个图片会缩放 ,以填满<img>元素。我们也可以设置其他值改变默认行为。

比如,object-fit 属性的值还可以是 covercontain。这些值告诉浏览器,在渲染盒子里改变图片的大小,但是不要让图片变形。

  • cover:扩展图片,让它填满盒子(导致图片一部分被裁剪)。
  • contain:缩放图片,让它完整地填充盒子(导致盒子里出现空白)。

这里,我为了保持画面的整体性,默认采用了 object-fit: fill。可以根据需求和具体情况,选择适合的值。

这里有两个概念要区分清楚:盒子(由<img>元素的宽和高决定)和渲染的图片。默认情况下,这二者大小相等。object-fit 属性让我们能在盒子内部控制渲染图片的大小,同时保持盒子的大小不变。

完整代码如下:

html 复制代码
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>网格布局的实战</title>
  <style>
    body {
      background-color: rgb(254, 226, 181);
      font-family: Helvetica, Arial, sans-serif;
    }

    .portfolio {
      display: grid;
      grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
      grid-auto-flow: row dense;
      grid-gap: 1em;
    }


    .portfolio>figure {
      margin: 0;
      display: flex;
      flex-direction: column;
    }

    figure>img {
      flex: 1;
      object-fit: fill;
    }

    .portfolio img {
      max-width: 100%;
    }

    .portfolio figcaption {
      padding: 0.3em 0.8em;
      background-color: rgba(0, 0, 0, 0.5);
      color: #fff;
      text-align: right;
    }

    .portfolio .featured {
      grid-row: span 2;
      grid-column: span 2;
    }
  </style>
</head>

<body>
  <div class="portfolio">
    <figure class="featured">
      <img src="./images/pic1.jpg" alt="">
      <figcaption>1</figcaption>
    </figure>
    <figure>
      <img src="./images/pic2.jpg" alt="" />
      <figcaption>2</figcaption>
    </figure>
    <figure>
      <img src="./images/pic3.jpg" alt="" />
      <figcaption>3</figcaption>
    </figure>
    <figure class="featured">
      <img src="./images/pic4.jpg" alt="" />
      <figcaption>4</figcaption>
    </figure>
    <figure>
      <img src="./images/pic5.jpg" alt="" />
      <figcaption>5</figcaption>
    </figure>
    <figure class="featured">
      <img src="./images/pic6.jpg" alt="" />
      <figcaption>6</figcaption>
    </figure>
    <figure>
      <img src="./images/pic7.jpg" alt="" />
      <figcaption>7</figcaption>
    </figure>
    <figure class="featured">
      <img src="./images/pic8.jpg" alt="" />
      <figcaption>8</figcaption>
    </figure>
  </div>
</body>

</html>

结尾

创作不易,感谢喜欢和支持,如有错误,恳请指出,希望与大家共同进步。

相关推荐
哟哟-15 分钟前
python多线程开发
开发语言·前端·python
双桥wow23 分钟前
Android Input系统原理一
android·服务器·前端
Swift社区25 分钟前
SwiftUI 与前端框架(如 React)中的状态管理对比
前端·react.js·ios
CherishTaoTao25 分钟前
nvm以及npm源配置
前端·npm·node.js
family2010201030 分钟前
VUE项目运行npm run dev命令后,自动打开浏览器导航到主页
前端·vue.js·npm
Манго нектар34 分钟前
CSS的多种选择器
css
Манго нектар34 分钟前
CSS的文本属性
css
新智元1 小时前
突破数据墙!27 岁华裔 MIT 辍学创业 8 年,年化收入逼近 10 亿
前端·人工智能
软件测试曦曦1 小时前
WEB性能测试-并发测试
前端·自动化测试·软件测试·功能测试·程序人生·职场和发展
I like Code?1 小时前
SpringBoot3+Swagger3(最新版springdoc-openapi教程)
java·服务器·前端