秋雨寒雪

在CSS中实现”Wrapper“最好的方式

原文链接: css-tricks.com

通常,在一个新HTML文档中,我们首先要写一个元素,用来包容页面中的所有其他内容。术语“wrapper”常用在此处。我们给这个元素增加一个类,用来封装页面中的其他可视元素。

我一直在努力寻找最好的实现方法。我曾在StackOverflow上发现一个相关的帖子,有超过250,000位观看者。很明显,我并不是唯一对此好奇的人。在本文中,我将对我最近的思考做个总结。

在深入探讨之前,我们首先说说"wrapper"和"container"之间的不同。

"Wrapper" vs "Container"

我相信wrapper元素和container元素之间存在不同。

在编程语言中,container一词通常用来表示包含多个元素的结构,wrapper则表示对某单个对象进行包装,该对象可以提供多个功能,也会向它提供接口。

因为他们代表不同的功能,所以也就拥有了两个不同的名字。

谈到wrapper,通常会想到一个<div>标签,它包含HTML文档的其他所有内容。我相信我们中的很多人都有过将它的宽设置为960px,并将所有主要内容居中显示的经历。 wrapper也会用在其他地方,如设计一个sticky footer

接下来是container,它通常代表另一种类型的包含。有时实现一种行为,有时代表多个组件的样式。它将具有相同视觉和逻辑的元素进行分组。例如, Bootstrap有不同的container,用来包含它的网格系统或其他各式的组件。

术语wrapper和container也可以按照开发者的想法代表同样的东西。可能也有其他的约定俗成,通常最好的建议是(让它们)代表对你来说最合理的东西。但要记住,命名是最基础也是最重要的开发者行为之一。命名规范可以让代码更易读、更具有可预测性。请认真选择!

下面是一个有关普通页面wrapper的例子。

/**
 * 1\. Centers the content. Yes, it's a bit opinionated.
 * 2\. See the "width vs max-width" section
 * 3\. See the "Additional Padding" section
 */
.wrapper {
  margin-right: auto; /* 1 */
  margin-left:  auto; /* 1 */

  max-width: 960px; /* 2 */

  padding-right: 10px; /* 3 */
  padding-left:  10px; /* 3 */
}

width vs max-width

为块元素设定width,可以防止它延伸到容器边缘以外(在很多情况下都有好处,如可读行的宽度)。所以,wrapper元素会拥有指定的宽。但当浏览器窗口比wrapper给的宽度窄时,问题就出现了。它将触发水平滚动条,这是很不受欢迎。

在这种情况下,可以使用 max-width代替,更适用于变窄的浏览器窗口。当想让一个网站可以在小设备上运行时,这个属性就非常重要。这里有个很好的例子来展示这个问题。

代码演示请见原文

根据响应式设计原则,max-width是一个更好的选择。

额外的Padding

我曾看见很多开发者忘记一种特殊的极端情况。我们将wrapper的max-width设为980px。这极端情况就是,用户设备的屏幕正好是980px。那时,内容将紧贴屏幕的边缘,而没有留白空间。

无留白空间的问题

我们通常需要离边界有一定的留白。如果需要实现总宽度为980px的wrapper,我会这样做:

.wrapper {
  max-width: 960px; /* 20px smaller, to fit the paddings on the sides */

  padding-right: 10px;
  padding-left: 10px;

  /* ...  */
}

为wrapper增加padding-leftpadding-right是个好办法,尤其在移动端。

也可以考虑使用box-sizing。使用它,padding不会改变整体的宽度。

选择哪个HTML元素

wrapper并没有任何语义。它只是简单地包含了所有可视元素和页面上的内容。它只是一个普通的容器。从语义学角度来说,<div>是最好的选择,<div>也没有任何语义,也仅仅是一个普通的容器。

有人可能想知道<section>是否适合。那让我们来看看 W3C文档对它的解释:

The element is not a generic container element. When an element is needed only for styling purposes or as a convenience for scripting, authors are encouraged to use the div element instead. A general rule is that the section element is appropriate only if the element's contents would be listed explicitly in the document's outline.

<section>有它自己的语义。它代表着同主题组。每个section的主题都应该是易区分的。包含一个标题元素(h1-h6),作为section子类,是很典型的做法。

Examples of sections would be chapters, the various tabbed pages in a tabbed dialog box, or the numbered sections of a thesis. A Web site's home page could be split into sections for an introduction, news items, and contact information.

第一眼看上去似乎并不是很出奇,但,是的!普通的div最适合wrapper。

<body>标签还是使用额外的<div>

值得一提的是,有一些例子使用<body>标签作为wrapper。下面的例子可以很好的执行:

body {
  margin-right: auto;
  margin-left:  auto;
  max-width: 960px;
  padding-right: 10px;
  padding-left:  10px;
}

你放弃使用非必须的<div>作为wrapper,这样就可以在标记语言中少写一个元素。

鉴于灵活性和适应性,我不想对此做出评论。想象接下来的项目中,遇到下面这些场景:

  • 你需要将footer固定在文档的最底部(当文档很短时,出现在视窗的底部)。即便你使用最现代的方法完成它,如使用flexbox,你还是需要一个额外的<div>作为wrapper。

  • 你需要为整个页面设置背景颜色。因为body标签有max-width属性,很难使用它来实现。那我们可以为<html>标签设置背景颜色,以此来代替<body>。好吧,对此我不太了解。我曾经读过一篇文章 HTML vs Body in CSS,对我来说它只是听起来有点陌生。但我也从没听到过因为为<html>标签设置背景颜色而出现问题、产生困难。不过,这听起来确实有点怪异,不是吗?

我的结论是,为实现CSS wrapper增加额外的<div>是最佳实践。使用这种方法,即使以后文档规范发生了变化,你也不必添加wrapper,将样式进行迁移。毕竟,我们只是讨论一个额外的DOM元素。