使用 CSS Grid 实现表单布局的优势

表单布局和设计一直是网页设计和开发中令人头疼的一部分。 尝试过写 <select> 标签的样式,或者在所有浏览器中都居中一个 label 的人感触肯定更深。

原文链接:https://www.sitepoint.com/css-grid-web-form-layout/

在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 的左边
  • 垂直对齐 labelfiled

还可以使用相邻的同级选择器来根据它们的字段的状态来添加样式,例如,当选中复选框时,将粗体应用到 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;
}

这里定义了四个列。单位可以用任意单位或者是 frfr 在网格布局里剩余的空间内,进行比例分配。 上面的示例中第二和第三列的总共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 提供了一个较老的补充规范。在大多数情况下,兼容设置很简单:

  • 旧版本浏览器可以使用 flexboxfloatsinline-blocks 或者 display: table。所有的网格属性都会被忽略。

  • 当浏览器支持 grid 时,所有的 flexboxfloatsinline-blockstable 布局属性会被禁用。

Grid 工具和资源:

MDN Grid Layout MDN 网格布局
A Complete Guide to Grid 一个完整的网格指南
Grid by Example 网格例子
Grid “fallbacks” and overrides 网格"后退"和重写
CSS Grid Playground 网格背景图
CSS Grid Garden 网格花园
Layoutit! 用它布局

Firefoxchrome 浏览器拥有开发工具和可视化工具,支持网格布局。

表单网格

为了逐步增强现有的表格,网格代码将放置在 @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之间的边际,所以三栏形式布局有四个间隙:

  1. 第一列前的第一条间隙
  2. 第一列和第二列之间的间隙
  3. 第二列和第三列之间的间隙
  4. 第三列和右边的最后一条间隙

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 应该是你的首选。

猜你喜欢

转载自blog.csdn.net/YITA90/article/details/83008464