使用css grid实现github贡献图

原文地址:Recreating the GitHub Contribution Graph with CSS Grid Layout


图表分为四个部分

  1. 整体图形网格
  2. "days"列
  3. “month”行
  4. 图形方格

整体网格

贡献图可以分为三部分 - 星期列,月份行,和独立的方格

在主要的 .grid元素中,有三个元素

<div class="graph">
  <ul class="months"></ul>
  <ul class="days"></ul>
  <ul class="squares"></ul>
</div>

使用grid-template-areas在主图中布置三个区域。这个属性允许我们更明确的定义网格不同区域落在何处。使用前我们先对网格的各个区域命名。

.months { grid-area: months; }
.days { grid-area: days; }
.squares { grid-area: squares; }

然后使用这些名字,写出我们想如何布置区域。grid-template-areas属性接收以空格分割的字符串,每个字符串代表一行,字符串内部表示列。

.graph {
  display: inline-grid;
  grid-template-areas: "empty months" "days squares";
}

你可能会注意到我添加了一个没有命名的区域empty作为grid-template-areas的值。这是因为我希望months区域从第二列开始,days区域也从第二行开始。如果我们使用一个不指向确切的区域的名字,实质上会创建一个“幽灵”元素,我们可以表现的好像这里有一个元素。

要布置这些网格区域,还需要添加两个属性。首先,使用grid-gap属性在元素之间添加间隔。

.graph {
  grad-gap: 10px;
}

最后,我们希望第一列只占用它所需要的空间,第二列填满剩下所有的空间。我们可以使用fr单位来实现,它代表了网格中剩余的可用空间。

.graph {
  grid-template-columns: auto 1fr;
}

以上就是我们需要给容器元素添加的所有样式。

"Days"列

贡献图左侧的星期列是一个简单的7行列。

这个布局可以使用两行样式实现:

:root {
  --square-size: 15px;
}
.days {
  display: grid;
  grid-template-rows: repeat(7, var(--square-size));
}

这里我们使用了repeat()函数,可以传递这些选项:

  1. 我们想要创建这样尺寸(见第二个参数)的行数。这里我们使用7因为一周有7天。
  2. 每一行的尺寸。这里我们用定义的--square-size变量给每个单独的方格同样的大小。

然后,我么想让行与行之间有一些空隙。与.graph中设置区域间隔一样,我们使用grid-gap属性。

:root {
  --square-size: 15px;
  --square-gap: 5px;
}
.days {
  grid-gap: var(--square-gap);
}

"Months"行

贡献图顶部的月份列表是单行网格

和日期列表不同,每项占用的空间并不那么简单。理想情况下,我们希望每个月占用四列代表四个星期。我们使用类似的方法来实现星期的布局。

:root {
  --square-size: 15px;
  --square-gap: 5px;
  --week-width: calc(var(--square-size) + var(--square-gap));
}
.months {
  display: grid;
  grid-template-columns: repeat(12, calc(var(--week-width) * 4));
}

但是,每个月并不都是严格的4个星期,有些月会少,有的会多。因此,我选择手动的设置每月的列宽度。

.months {
  display: grid;
  grid-template-columns: calc(var(--week-width) * 4) /* Jan */
                         calc(var(--week-width) * 4) /* Feb */
                         calc(var(--week-width) * 4) /* Mar */
                         calc(var(--week-width) * 5) /* Apr */
                         calc(var(--week-width) * 4) /* May */
                         calc(var(--week-width) * 4) /* Jun */
                         calc(var(--week-width) * 5) /* Jul */
                         calc(var(--week-width) * 4) /* Aug */
                         calc(var(--week-width) * 4) /* Sep */
                         calc(var(--week-width) * 5) /* Oct */
                         calc(var(--week-width) * 4) /* Nov */
                         calc(var(--week-width) * 5) /* Dec */;
}

因为我并不依赖真实的数据,只是复制了我在自己GitHub上看到的内容。理想情况下,我们应该使用编程方法来计算每列的宽度,这只是我为了做示例而使用的方式。

单独的方格


独立方格的样式大部和.days列共享,因为间隔以及行数相同。

.days,
.squares {
  display: grid;
  grid-gap: var(--square-gap);
  grid-template-rows: repeat(7, var(--square-size));
}

除了这些共享的样式之外,还有很多不同的地方。
首先是它的布局方向。默认的,网格内的项目排列方向和文字相同,从左到右然后从上到下。但是方格在GitHub贡献图中的排列不同,先从上到下然后从左到右。
要实现这样的排列方式,需要使用grid-auto-flow属性。

.squares {
  grid-auto-flow: column;
}

最后,我们希望每一列有同样的宽度(var(--square-size))。但是和行不一样,我们不知道或不想指定列的确切数量。因此我们使用grid-auto-columns属性而不使用grid-template-columns,把列宽设置成我们期望的值,让网格计算最终需要绘制多少列。

.squares {
  grid-auto-columns: var(--square-size);
}

完整的代码可以在CodePen看到

Comments
Write a Comment