使用 CSS Grid 实现表单布局的优势
Posted YITA90
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了使用 CSS Grid 实现表单布局的优势相关的知识,希望对你有一定的参考价值。
表单布局和设计一直是网页设计和开发中令人头疼的一部分。 尝试过写 <select>
标签的样式,或者在所有浏览器中都居中一个 label
的人感触肯定更深。
在2016年,我写了一篇文章标题为 "Make Forms Fun with Flexbox"
,文中指出了如何使用 Flexbox
布局解决多种表格布局的困难。为了展示 html
标签顺序的一致性,label
总是跟随在一个关联域标签之后:
<div>
<input id="name" name="name" type="text" />
<label for="name">name</label>
</div>
<div>
<select id="experience" name="experience"><!-- options --></select>
<label for="experience">experience</label>
</div>
<div>
<input id="html" name="html" type="checkbox" />
<label for="html">HTML</label>
</div>
然后,Flexbox
可以这样用:
- 如果需要重新定位
label
顺序,比如,将文本输入(input)、选择框(select) 或者textarea
移动到label
的左边 - 垂直对齐
label
和filed
还可以使用相邻的同级选择器来根据它们的字段的状态来添加样式,例如,当选中复选框时,将粗体应用到 label
上:
input:checked + label
font-weight: bold;
使用 Flexbox
来设计表单的缺点
可是在表单布局中使用 Flexbox
有很多问题。 Flexbox
创建一个一维布局,一项需要折行后跟着一项, Field/label
必须放置在带有 display: flex;
的父级容器元素中,这样才能保证每一行都换行。
必须要给 label
一个固定的宽度,例如 10em
。 因为如果一个label
内文字超长,文本可能会溢出,使得重置元素宽度或者挤出旁边的表单元素,无法与其他行的元素对齐。
最后,表单通常会在网格中设计。 我们为何不试试主流浏览器支持的 CSS Grid
布局呢?
兼容方式
大多数 CSS Grid
文章都介绍了这些概念,而且也为旧版本的浏览器提供了优雅降级。 当布局有很多装饰性布局的时候,这种方法是很理想的——例如,定位页面内容、页眉、页脚和菜单。就算是少量的旧浏览器内展示为线性布局,页面也依然是可用的。
表单布局从功能上来说,会相对重要,因为用户如果在错误的框中输入信息会导致信息错误。所以本教程采用的是一种渐进增强的方法:
- 浮动布局适用于所有的浏览器,包括
IE8 +
(不支持Flexbox
)。 - 在所有现代浏览器中使用
CSS Grid
来实现表单布局
下面的例子因为样式很少,所以直接写在了 HTML
元素上。 这种方式 BEM
不推荐,但也能保持代码可读,整洁。
我们先写一些表单的基础结构。
HTML
一个经典的 HTML
表单结构应该尽量保持简洁,没有必要用 <div>
包裹每一个键值对。
<form action="get">
<fieldset>
<legend>Your web development skillset</legend>
<div class="formgrid">
<input id="name" name="name" type="text" />
<label for="name">name</label>
<select id="experience" name="experience">
<option value="1">1 year or less</option>
<option value="2">2 years</option>
<option value="3">3 - 4 years</option>
<option value="5">5 years or more</option>
</select>
<label for="experience">experience</label>
<input id="html" name="html" type="checkbox" />
<label for="html">HTML</label>
<input id="css" name="css" type="checkbox" />
<label for="css">CSS</label>
<input id="javascript" name="javascript" type="checkbox" />
<label for="javascript">JavaScript</label>
<textarea id="skills" name="skills" rows="5" cols="20"></textarea>
<label for="skills">other skills</label>
<button type="submit">SUBMIT</button>
</div>
</fieldset>
</form>
唯一的附加元素是 <div class="formgrid">
。 fieldset
元素浏览器是无法设置 display: grid
或者 display: flex
的, 所以需要一个外部容器 div
包裹。
表单布局浮动布局
在设置初始字体和颜色样式之后,需要分配浮动布局:
- 70% 宽度向右浮动
- 30% 宽设置给
label
,向左浮动
/* fallback 30%/70% float layout */
input, output, textarea, select, button
clear: both;
float: right;
width: 70%;
label
float: left;
width: 30%;
text-align: right;
padding: 0.25em 1em 0 0;
复选框和单选按钮放置在 label
前,然后向左浮动。 它们的内部宽度可以自适应(width:auto) ,但要设置左边距 30%
进行对齐:
button, input[type="checkbox"], input[type="radio"]
width: auto;
float: left;
margin: 0.5em 0.5em 0 30%;
input[type="checkbox"] + label, input[type="radio"] + label
width: auto;
text-align: left;
这种方式的表单布局适用于所有浏览器,包括 IE8 +
https://codepen.io/SitePoint/pen/bxVaKK
一个不认真的开发人员会认为这样就完事儿了,但是这个表单其实还有几个小问题:
- 填充和边距调整是很不稳定的,在不同浏览器中可能表现不一致
- 如果需要更长的标签文本或不同大小的字体,那么
CSS
间距就会需要调整 - 在小屏幕尺寸下,
label
会溢出
开始使用网格
Grid
模块为了能够创建一个有行和列的布局,新增了 18 个新的 CSS
属性。
模块增加了18个新的 CSS 属性,以便创建一个有行和列的布局。 网格内的元素可以放置在任何行/列,也可以占多行或者多列,重叠其他元素,设置水平或垂直居中。 听起来和 Flexbox
很相似,但是:
Flexbox
是一维的。 元素是一个挨着一个出现的,很有可能不会包裹在一个新的"行"中。 常用的案例是菜单或者图片库
网格是二维的,同时拥有行和列。 如果一个元素对它的单元来说太大,行或列还会相应地变大。布局页面或者表单,网格真是再适合不过了。
CSS
网格相比基于表格的布局, 会更灵活,需要更少的标签。 相比其他的 CSS
属性,网格会更加复杂一些,学起来会稍难一点,但是不需要每个属性和值都记住,可以先了解最基本的网格在元素上的使用:
.container
display: grid;
我们在设计布局的时候,肯定会需要知道列的数量,大小,以及行和列之间的间隔。 像这样:
.container
display: grid;
grid-template-columns: 10% 1fr 2fr 12em;
grid-gap: 0.3em 0.6em;
这里定义了四个列。单位可以用任意单位或者是 fr
。fr
在网格布局里剩余的空间内,进行比例分配。 上面的示例中第二和第三列的总共3fr
。 如果有 600 像素的水平空间可用:
1fr 等于(1fr / 3fr) * 600px = 200px
2fr 等于(2fr / 3fr) * 600px = 400px
在行之间定义 0.3em
的间隙,并在列之间定义 0.6em
。
.container
所有的子元素现在都属于网格的格。 默认情况下,第一个子元素将出现在第 1 行第 1 列。 第二个子元素在第 1 行,第 2 列,第 6 个在第 2 行,第 2 列。 使用 grid-template-rows
属性可以对行进行大小调整,但高度是由内容撑开的。
Grid
的兼容性很好。在 Opera Mini
中不可用, 但 IE11
提供了一个较老的补充规范。在大多数情况下,兼容设置很简单:
-
旧版本浏览器可以使用
flexbox
,floats
,inline-blocks
或者display: table
。所有的网格属性都会被忽略。 -
当浏览器支持
grid
时,所有的flexbox
,floats
,inline-blocks
和table
布局属性会被禁用。
Grid
工具和资源:
MDN Grid Layout
MDN 网格布局
A Complete Guide to Grid
一个完整的网格指南
Grid by Example
网格例子
Grid “fallbacks” and overrides
网格"后退"和重写
CSS Grid Playground
网格背景图
CSS Grid Garden
网格花园
Layoutit!
用它布局
Firefox
和 chrome
浏览器拥有开发工具和可视化工具,支持网格布局。
表单网格
为了逐步增强现有的表格,网格代码将放置在 @supports
声明中:
/* grid layout */
@supports (display: grid)
...
在大多数网格布局中都没必要这样写。 但这个示例需要重置所有的浮动内边距和外边距——需要保证这些规则只有在能使用 CSS Grid
的时候才起作用。
这个表单布局将使用三栏设计:
这个表单的布局:
label
占一列- 复选框或者单选按钮占一列或者两列, 右对齐
- 复选框或者单选名称占三列
- 其他元素,需要二到三列
外层容器和子元素的样式:
.formgrid
display: grid;
grid-template-columns: 1fr 1em 2fr;
grid-gap: 0.3em 0.6em;
grid-auto-flow: dense;
align-items: center;
input, output, textarea, select, button
grid-column: 2 / 4;
width: auto;
margin: 0;
grid-column
定义了起始和结束的网格间隙。 间隙是两个cells
之间的边际,所以三栏形式布局有四个间隙:
- 第一列前的第一条间隙
- 第一列和第二列之间的间隙
- 第二列和第三列之间的间隙
- 第三列和右边的最后一条间隙
grid-column: 2 / 4;
在间隙 2 和 4 之间填充内容,或者说列 2 和列 3 之间。
第一个 HTML
元素是 <input>
。 它占了第二列和第三列,这意味着第一列(间隙1 或者2)是空的。 因此,默认情况下,label
标签将下降到第2行,第1列。 然而,通过设置 grid-auto-flow: dense;
; 在 container
中,浏览器将尝试填补网格中的空单元格,然后再进入一个新的行。
复选框和单选按钮现在可以设置在间隙1到3(1和2列) ,justify-self: end
靠右对齐:
input[type="checkbox"], input[type="radio"]
grid-column: 1 / 3;
justify-self: end;
margin: 0;
网格上的 labels
将自适应于任何一行的单元格。 所以,现在不像是在浮动布局中需要设置默认的宽度和间距:
label, input[type="checkbox"] + label, input[type="radio"] + label
width: auto;
padding: 0;
margin: 0;
最后,<textarea>
还可以在单元格垂直方向的顶部而不是中心:
textarea + label
align-self: start;
下面是最后一个基于网格的表单布局:
https://codepen.io/SitePoint/pen/bxVaKK
与浮动不同,在添加不同的字体、尺寸或 labels
时需要调整设计的情况下,布局不会因为这些小调整而打破。
网格学习
一般新的学习可能需要花几年才能真正实行,但是 CSS Grid
有很好的支持,当你使用浮动布局或者弹性布局布局很困难的时候,提供了另一种布局的可能性。 表单是一个合适的实例,写出来的 CSS
代码会很精炼。
如果你想学习另一种 CSS
技能,Grid
应该是你的首选。
以上是关于使用 CSS Grid 实现表单布局的优势的主要内容,如果未能解决你的问题,请参考以下文章
一行 CSS 代码实现响应式布局 – 使用 Grid 实现的响应式布局