- 原文地址:Building a Trello Layout with CSS Grid and Flexbox
- 原文做者:Giulio Mainardi
- 译文出自:掘金翻译计划
- 本文永久连接:github.com/xitu/gold-m…
- 译者:sunui
- 校对者:Aladdin-ADD、ahonn
经过本教程,我将带你完成 Trello 看板 (查看示例)的基本布局。这是一个响应式的、纯 CSS 的解决方案,而且咱们将只开发布局的结构特性。css
这是一个 CodePen demo,可预览一下最终结果。html
除了栅格布局和 Flexbox,这个方案还采用了 calc 和视图单位。咱们也将利用 Sass 变量,让代码更可读和高效。前端
不提供向下兼容,因此请确保在支持的浏览器上运行。一切就绪,就让咱们开始一步一步开发看板组件吧。react
一个 Trello 看板由一个 app 栏、一个 board 栏和一个包含卡片列表的部分组成。我使用如下标签骨架搭建出这一结构:android
<div class="ui">
<nav class="navbar app">...</nav>
<nav class="navbar board">...</nav>
<div class="lists">
<div class="list">
<header>...</header>
<ul>
<li>...</li>
...
<li>...</li>
</ul>
<footer>...</footer>
</div>
</div>
</div>复制代码
这个布局将经过 CSS 栅格实现。确切地说是 3×1 栅格(就是指一列三行)。第一行用于 app 栏,第二行用于 board 栏,第三行用于 .lists
元素。ios
前两行各自有一个固定的高度,而第三行将撑起可变窗口高度的其他部分:css3
.ui {
height: 100vh;
display: grid;
grid-template-rows: $appbar-height $navbar-height 1fr;
}复制代码
视图单位能够确保 .ui
容器老是和浏览器的窗口高度一致。git
一个栅格化的上下文被分配给容器,而且指定了上文说的行和列。确切地说,是只指定了行,由于声明单独的列是没有必要的。一对 Sass 变量指定了两个栏目的高度,使用 fr
单位指定 .lists
元素高度使其撑起可变窗口高度的其他部分,这样每行的大小就设定完成了。github
如上所述,屏幕栅格的第三行托管着卡片列表的容器。这是标签的轮廓:后端
<div class="lists">
<div class="list">
...
</div>
...
<div class="list">
...
</div>
</div>复制代码
我用一个满屏宽的 Flexbox 单行行容器来格式化列表:
.lists {
display: flex;
overflow-x: auto;
> * {
flex: 0 0 auto; // 'rigid' lists
margin-left: $gap;
}
&::after {
content: '';
flex: 0 0 $gap;
}
}复制代码
给 overflow-x
指定 auto 值,当列表不适合视口提供的宽度时,浏览器会在屏幕底部显示一个水平滚动条。
flex
简写属性用于 flex item 使列表更严格。flex-basis
(简写的方式使用)的 auto 值指示布局引擎从 .list
元素的宽度属性取值,flex-grow
和 flex-shrink
的 0 值能够防止宽度的改变。
接下来我将在列表之间添加一个水平分隔。若是给列表设置右间距,当水平溢出时看板上最后一个列表以后的间距不会被渲染。为了解决这个问题,列表被一个左间距分隔而且最后一个列表和窗口右边缘的间距经过给每一个 .lists
元素添加一个伪元素 ::after
来实现。默认值 flex-shrink: 1
必定要被重写,不然这个伪元素会”吸取“全部的负空间,而后消失。
注意在 Firefox < 54 的版本上要给 .lists
指定 width: 100%
以确保正确的布局渲染。
每一个卡片列表由一个 header 栏、一个卡片序列和一个 footer 栏目组成。如下 HTML 代码段实现了这一结构:
<div class="list">
<header>List header</header>
<ul>
<li>...</li>
...
<li>...</li>
</ul>
<footer>Add a card...</footer>
</div>复制代码
这里的关键任务是如何管理列表的高度。header 和 footer 有固定的高度(未必相等)。而后有一些不定数量的卡片,每一个卡片都有不定量的内容。所以随着卡片的添加和移除,这个列表也会增大和缩小。
可是高度不能无限增大,它须要有一个取决于 .lists
元素高度的上限。一旦突破上线,我想有一个垂直滚动条出现来容许访问溢出列表的卡片。
这听起来是 max-height
和 overflow
属性能作的。但若是根容器 .list
提供了这些属性,一旦列表达到了它的最大高度,全部的 .list
元素包括 header 和 footer 在内都会出现滚动条。下图左右两边分别显示错误的和正确的侧边条:
所以,让咱们把 max-height
约束给内部的 <ul>
。应该提供什么值呢?header 和 footer 的高度必须从列表父容器(.lists
)的高度之中扣除:
ul {
max-height: calc(100% - #{$list-header-height} - #{$list-footer-height});
}复制代码
但还有一个问题。百分比数值并不参照 .lists
而是参照 <ul>
元素的父元素 .list
,而且这个元素没有定义高度,所以这个百分比不能肯定。这个问题能够经过设置 .list
和 .lists
一样高度来解决:
.list {
height: 100%;
}复制代码
这样,既然 .list
和 .lists
老是同样高,它的 background-color
属性不能用于列表背景色,但可使用它的子元素(header, footer 和卡片)来实现这一目的。
最后一个 list 高度的调整颇有必要,可用来计算列表底部和窗口底部的一点空间($gap
)。
.list {
height: calc(100% - #{$gap} - #{$scrollbar-thickness});
}复制代码
还有一个 $scrollbar-thickness
须要被减去,防止列表触及 .list
元素的水平滚动条。 事实上这个滚动条”增加“在 .lists
盒子内部。也就是说,100% 这个值是指包括滚动条在内的 .lists
的高度。
而在火狐中,这个滚动条被”附加“给 .lists
高度的外部,就是说 .lists
高度的 100% 并不包含滚动条。因此这个减法就没什么必要了。结果是当滚动条可见时,在火狐中已经触及最大高度的底部边框和滚动条的顶部之间的可视空间会稍大一些。
这是这个组件相应的 CSS 规则:
.list {
width: $list-width;
height: calc(100% - #{$gap} - #{$scrollbar-thickness});
> * {
background-color: $list-bg-color;
color: #333;
padding: 0 $gap;
}
header {
line-height: $list-header-height;
font-size: 16px;
font-weight: bold;
border-top-left-radius: $list-border-radius;
border-top-right-radius: $list-border-radius;
}
footer {
line-height: $list-footer-height;
border-bottom-left-radius: $list-border-radius;
border-bottom-right-radius: $list-border-radius;
color: #888;
}
ul {
list-style: none;
margin: 0;
max-height: calc(100% - #{$list-header-height} - #{$list-footer-height});
overflow-y: auto;
}
}复制代码
如上所述,列表背景色经过给每个 .list
元素的子元素的 background-color
属性指定 $list-bg-color
值而被渲染。overflow-y
使得卡片滚动条只有按需显示。最后,给 header 和 footer 添加一些简单的样式。
单个卡片包含的一个列表元素 HTML:
<li>Lorem ipsum dolor sit amet, consectetur adipiscing elit</li>复制代码
卡片也有可能包含一个封面图片:
<li>
<img src="..." alt="...">
Lorem ipsum dolor sit amet
</li>复制代码
这是相应的样式:
li {
background-color: #fff;
padding: $gap;
&:not(:last-child) {
margin-bottom: $gap;
}
border-radius: $card-border-radius;
box-shadow: 0 1px 1px rgba(0,0,0, 0.1);
img {
display: block;
width: calc(100% + 2 * #{$gap});
margin: -$gap 0 $gap (-$gap);
border-top-left-radius: $card-border-radius;
border-top-right-radius: $card-border-radius;
}
}复制代码
设置完一个背景、填充、和底部间距就差背景图片的布局了。这个图片宽度必定是跨越整个卡片的,从左填充的边缘到右填充的边缘:
width: calc(100% + 2 * #{$gap});复制代码
而后,指定负边距以使图片水平和垂直对齐:
margin: -$gap 0 $gap (-$gap);复制代码
第三个正边距的值用于指定封面图片和文字之间的空间。
最后我给占据屏幕布局第一行的两条添加了一个 flex 格式化上下文,但它们只是草图。经过扩展 demo 自由构建你本身的实现吧。
这只是实现这种设计的一种可行方法,若是能看见其余方式那必定颇有趣。此外,若是能完成整个布局那就更好了,好比完成最后的两个栏目。
另外一个潜在的改进是可以为卡片列表实现自定义的滚动条。
因此,fork 这个 demo 尽情发挥吧,记得在下面的讨论区留下你的连接哦。
掘金翻译计划 是一个翻译优质互联网技术文章的社区,文章来源为 掘金 上的英文分享文章。内容覆盖 Android、iOS、React、前端、后端、产品、设计 等领域,想要查看更多优质译文请持续关注 掘金翻译计划、官方微博、知乎专栏。