Susy 是一款用来为网站创建栅格布局的工具,它所带来的灵活和洒脱超乎想象。无论是 5
列,14
列,还是 48
列,一切都不是问题。不等宽列?So easy。
我们为什么要在浩如烟海的互联网框架库中选择 Susy?它的魅力是否就是肤浅的表面呢?
在过去几个月,使用 Susy 可以说是我前端开发流程中最美好的事情。它让我们摆脱了诸多的麻烦,而且我决定要写本书分享使用经验,告诉全世界它的美丽。本文将会深入的介绍使用 Susy 创建布局的方式——任何天马行空的布局都不在话下。
没有说服力?好吧,那我请求给我一个机会,向您介绍一种全新的布局方式。我们将会见识 Susy 的超凡力量。
用一个成语说的话,单刀直入高下立判,所以直接用 Susy 来布局吧。当然,你可以同时使用传统的布局方式来比较比较,计算像素、百分比……
总体会由浅入深,尤其是你了解的足够多时,我会想你展示更加非凡的布局。
朋友们,在开始之前,有些事情你必须了解以下。你必须使用 Sass 预处理器来解析它,所以必须了解一些 Sass 转换为 CSS 的知识。当然,你不能太调皮使用 Less 解析 Susy。
CSS-Tricks 的布局就很漂亮(译者注:该网站是即为原文发表的站点),那我们就用它做示范吧。
仔细观察一下,你会发现 CSS-Tricks 的布局包含了两部分:主内容区和侧边栏。
我们就假设 CSS-Tricks 使用了 12
列栅格布局,其中主内容区占 8
列,侧边栏占 4
列。
如果你之前使用过 Bootsrap 或 Foundation,那么这个网站的布局标签应该就会像是这样:
<div class="wrap">
<div class="content col-md-8"></div>
<div class="content col-md-4"></div>
</div>
很简单对不对。但是 Bootstrap 和 Foundation 也带来了诸多冗余的样式。
一个坚韧的开发者从无到有的开发网站,在没有使用任何框架和样式前,文档标记就像下面这样:
<div class="wrap">
<div class="content">Content</div>
<div class="sidebar">Sidebar</div>
</div>
为了创建一个 8
列宽的主内容区和 4
列宽的侧边栏,你需要计算相应的宽度和艰巨。响应式网页设计的一个大规则就是用百分比输出这些宽度值,所以你又需要再次转换。
接下来,相应的 CSS 代码如下所示:
/* I tend to use border-box sizing for all my web layouts. */
*, *:before, *:after {
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
box-sizing: border-box;
}
.wrap {
max-width: 1120px;
}
/* Clearfix for floated children */
.wrap:after {
content: " ";
clear: both;
display: block;
}
.content {
float: left;
width: 66.071429%; /* 740px / 1120px */
margin-right: 1.6964286%; /* 19px/1120px */
}
.sidebar {
float: right;
width: 32.2321429%; /* 361px / 1120px */
}
在继续下一步工作前,这里有一个小提示:我喜欢将网站所有元素的 box-sizing
选项设置为 border-box
,也非常建议你这么做。更多信息请参阅 Chris 的文章 box-sizing。
有关于
box-sizing
中文介绍可以点击这里。
总之,手工处理这些数据是及其单调乏味的事情,尤其是面临众多的布局设计。想象一下每次计算百分比的痛苦吧!
这正是 Susy 发挥作用的地方,她为你写诗为你计算所有的数学题,绝对的真爱。
使用 Susy 创建布局的第一件事就是,告诉她你想使用的布局类型。Susy 中有一系列的默认参数,用来初始化项目。
现在,假设大家都是第一次接触 Susy,所以我们直接使用默认参数。其中,我们只修改三个参数就足够了,修改时需要声明在 $susy
中。
同时,让我们添加喜爱的 border-box
属性。
@import "susy"
/* Changing Susy default global settings */
$susy: (
/* Tells Susy to use 12 columns */
columns: 12,
/* Tells Susy that the container has a max-width of 1120px */
container: 1120px,
/* Tells Susy to use border-box */
global-box-sizing: border-box
);
/* Makes border-box properties */
@include border-box-sizing;
使用 Susy,需要为网站的最外部容器添加 container
混合宏。在这个示例中,容器就是 .wrap
。
.wrap {
@include container;
}
时光流转,又到了计算百分比的时候,不过,这次只需要告诉 Susy 轮廓就可以了:主内容区占 8
列,侧边栏占 4
列。
接下来,需要让 Susy 知道 sidebar
是横向的最后一个元素,就大功告成了,快来看神奇的代码:
/* Tells Susy there's 8 columns in the content */
.content {
@include span(8);
}
/* Tells Susy there's 4 columns in the sidebar, and its the last item on the row. */
.sidebar {
@include span(4 last);
}
编译结果:
*, *:before, *:after {
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
box-sizing: border-box;
}
.wrap {
max-width: 1120px;
margin-left: auto;
margin-right: auto;
}
.wrap:after {
content: " ";
display: block;
clear: both;
}
.content {
width: 66.10169%;
float: left;
margin-right: 1.69492%;
}
.sidebar {
width: 32.20339%;
float: right;
margin-right: 0;
}
你发现了吗,CSS 输出结果就是我们所想要的样式! Susy 真的节省了我们很多时间。
到现在,我们还没有完成 CSS-Tricks 的布局。如果你继续向下滚动页面,就会发现页面底部有一些社交分享图标。最重要的是,这里有 10 个社交分享图标(而之前我们使用了 12 列的布局):
如果是使用传统的栅格框架进行布局,那你可就摊上大事了。据我所知,还没有什么简单方法,在不影响剩余部分布局的同时,可以迅速将 12
列布局转换为 10
列。
Susy 并不对你做任何限制,可以随意创建自己的规则,事后,这就是你的专属栅格了。
在继续 CSS 的工作前,让我们先来调整一下布局标签,如下所示:
<div class="wrap">
<div class="content"></div>
<div class="sidebar"></div>
<div class="social">
<ul>
<li class="social__list-item"></li> <!-- repeat 10x -->
</ul>
</div>
</div>
好了,开始 CSS 方面的工作吧。如果是使用手工的方法,你就会意识到,自己需要反复计算每个元素的宽度和间距。
.social {
padding: 1.6964286% /* 19px / 1120px */
}
/* Adds clearfix to social to prevent the float collapse */
.social:after {
content: " ";
clear: both;
display: block;
}
.social__list-item {
float: left;
width: 9.1497227; /* 99px / 1082px */
margin-right: 1.0166359; /* 11px / 1082px */
}
/* And the last item cannot have any right margins */
/* It is also good to float it right to mitigate subpixel rounding errors */
.social__list-item:last-child {
float: right;
margin-right: 0;
}
It feels like quite a tedious job, if you ask me.
It's so much simpler if we get Susy to do it for us. You'll just have to tell Susy that there are 10 columns in all (instead of 12), and each social item takes up one column.
.social {
/* Adds a padding of 19px to each side of the .social container */
padding: gutter();
/* Adding a clearfix because all children elements are floated */
@include clearfix;
.social__list-item {
/* Telling Susy that there are 10 items, and each takes up 1 row */
@include span(1 of 10);
/* Another way to tell Susy that this is the last item in the row */
&:last-child {
@include last;
}
}
}
Susy 可以为我们的栅格,恰到好处地生成正确的 CSS 属性。
.social {
padding: 1.69492%;
}
.social:after {
content: "";
display: table;
clear: both;
}
.social .social__list-item {
width: 8.16327%;
float: left;
margin-right: 2.04082%;
}
.social .social__list-item:last-child {
float: right;
margin-right: 0;
}
多么简洁优雅!完全不需要数学技巧。如果你知道使用 CSS 创建栅格布局,那么使用 Susy 就是一件水到渠成的事。
使用百分比布局有一个肯定发生的问题:生成的结果中会出现子像素,比如 10.4px
。很长一段时间以来,这都困扰着布局效果,归根结底还是因为各种浏览器处理子像素的方式不同。
举例来说,使用 webkit
内核的浏览器会向下约取这些像素,10.4px
会被约取为 10 px
。布局中的数字越大,约取错误就会越大。所以我们 10
列宽度的布局所产生的错误,在 webkit
内核的浏览器中会非常明显。
像这样的错误是非常不合适的,使用普通的方法也无法纠正过来。
一种方式是确保百分比不会是生成子像素。但这并不是一个好主意,因为这样你就必须使用非相应布局,或者设置不同的栅格宽度。
这里还有另一种可行的方法,我们称之为 Isolate 技巧。
这种方法略微有些高级,需要你了解一些 Jamie Hill 发明的 isolate 技巧。该技巧已经在 Zen 栅格中久经考验。如果你熟悉 Zen 栅格,那么就一定会理解我在这里的描述。
如果对此比较陌生,也无需担心,下面就详细介绍这种方法。
使用 isolate 技巧的核心就是降低约取效果来避免约取错误,具体做法是为布局元素设置明确的边距。
使用该技巧的前提条件是:
margin-left
属性,以确保元素被安放到了正确的位置。margin-right
属性,且被复制为 -100%
,用来将下一个元素拉到容器的左边缘。如果你对负边距不熟悉,那么就不容易理解这个技巧。那么就让我们一步一步地解析其中的实现原理。
接下来,你需要创建一个包含三个元素的布局:
我们将会一个接一个的固定每个元素的位置。元素 1
的位置非常简单,它的 margin-left
值为 0
,所以整体位于起始的地方。然后给它设置一个值为 -100%
的 margin-right
,用来将下一个元素(元素 2
)拉到开始的位置。
现在,元素 2
已经由于元素 1
的样式而回到了开始的地方。
接下来,用 margin-left
属性固定元素 2
的位置,该属性的值为 2
个列宽和两个间距宽度的总和,以百分比表示。完成后就会发现,元素 2
已经被放到了第三列的位置。
元素 2
也要设置一个 margin-right
属性,值为 -100%
,用来将下一个元素(元素 3
)拉到开始的地方。
现在,item 3
已经被 item 2
拉到了开始的地方。
然后,就可以使用 margin-left
属性将元素 3
固定到第五列的位置,该属性的值为 4
个纵列和 4
个间距的宽度之和,使用百分比表示。
继续将下一个元素拉到开始的位置,并重复上述的模式,最终使所有的元素应用到这个技巧。
如果有元素需要放置到新行,那么就使用 clear:left
属性清楚浮动。
同时,为了让该元素处于首列位置,需要将 margin-left
属性改为 0
。
这就是 Isolate 技巧的原理。现在你已经理解它了,快让我们使用起来解决子像素约取错误吧。
如果要使用 isolate 技巧,我们需要手动摆放每个元素的位置。不过,Susy 可以帮助我们解决这个问题。
Susy 有一个非常方便的功能,帮助我们跳过所有的手工工作。这就是 gallery
混合宏。
.social__list-item {
@include gallery(1 of 10);
}
生成的 CSS 就会使用 isolate 技巧:
.social__list-item:nth-child(10n + 1) {
margin-left: 0;
margin-right: -100%;
clear: both;
margin-left: 0;
}
.social__list-item:nth-child(10n + 2) {
margin-left: 10.20408%;
margin-right: -100%;
clear: none;
}
.social__list-item:nth-child(10n + 3) {
margin-left: 20.40816%;
margin-right: -100%;
clear: none;
}
.social__list-item:nth-child(10n + 4) {
margin-left: 30.61224%;
margin-right: -100%;
clear: none;
}
.social__list-item:nth-child(10n + 5) {
margin-left: 40.81633%;
margin-right: -100%;
clear: none;
}
.social__list-item:nth-child(10n + 6) {
margin-left: 51.02041%;
margin-right: -100%;
clear: none;
}
.social__list-item:nth-child(10n + 7) {
margin-left: 61.22449%;
margin-right: -100%;
clear: none;
}
.social__list-item:nth-child(10n + 8) {
margin-left: 71.42857%;
margin-right: -100%;
clear: none;
}
.social__list-item:nth-child(10n + 9) {
margin-left: 81.63265%;
margin-right: -100%;
clear: none;
}
.social__list-item:nth-child(10n + 10) {
margin-left: 91.83673%;
margin-right: -100%;
clear: none;
}
看,社交分享图标安放到了正确的位置!
现在,我们建立一定的基础,让我们快马一鞭,将其改造成响应式布局。
响应式设计越来越重要了,如果我不讲点 Susy 实现响应式设计的话题,你一定会小看它的力量的。
创建响应式布局最重要的一步就是,确定你熟悉媒体查询的使用方式。要特别注意移动优先的媒体查询原则,在示例中我们就会使用这个原则。
为了简化过程,我们只创建拥有两个断电的布局吧。一个为移动视图设计,宽度范围在 0~700px
之间;另一个为桌面视图设计,宽度大于 700px
;
在移动视图中,.content
和 .sidebar
都会拥有 100%
的宽度。在桌面视图中,.content
和 .sidebar
会被设计为 8
列和 4
列。
如果你尝试编写代码,结果差不多就像下面这样(Sass):
.content {
/* Styles for mobile view go here */
/* Styles for desktop view go here */
@media (min-width: 700px) {
width: 66.10169%;
float: left;
margin-right: 1.69492%;
}
}
.sidebar {
/* Styles for mobile view go here */
/* Styles for desktop view go here */
@media (min-width: 700px) {
width: 32.20339%;
float: right;
margin-right: 0;
}
}
由于 <div>
默认占用 100%
的宽度,所以无需为移动视图创建任何样式。你所需要做的,就是确保宽度大于 700px
时,桌面布局可以正常工作。
手工编写一个响应式布局和使用 Susy 编写相差无几,唯一的区别在于 Susy 更快更好用。
.content {
/* Styles for mobile view go here */
/* Styles for desktop view go here */
@media (min-width: 700px) {
@include span(8);
}
}
.sidebar {
/* Styles for mobile view go here */
/* Styles for desktop view go here */
@media (min-width: 700px) {
@include span(4 last);
}
}
接下里是社交分享部分。在移动视图中看起来就像这样:
在移动视图中,每个元素现在并不是占用 10
列中的 1
列了,而是占用 2
列,这个效果可以由 span(2 of 10)
实现。
注意:你可能会疑问,为什么不用 5 列布局并将社交图标放到其中的一列中去?span(1 of 5)
和 span(2 of 10)
是有些微的差异的,下面的图片就可以解释:
基本的区别就在于是否包含了间距。当然可以使用 5
列布局,但我坚持 10
列,因为这样 gutter
的数量会更接近 12
。
接下来需要再次调用 gallery
混合宏,并为每个元素添加间隔。
.social {
/* ... Same styles as above */
.social__list-item {
@include gallery(2 of 10);
margin-bottom: gutter(10);
}
@media (min-width: 700px) {
@include gallery(1 of 10);
margin-bottom: 0;
}
}
下面是完整的代码示例:
<div class="wrap">
<div class="content">Content</div>
<div class="sidebar">Sidebar</div>
</div>
<div class="wrap">
<div class="social">
<ul>
<li class="social__list-item"><img src="http://placehold.it/100x100&text=Image" alt="" /></li>
<li class="social__list-item"><img src="http://placehold.it/100x100&text=Image" alt="" /></li>
<li class="social__list-item"><img src="http://placehold.it/100x100&text=Image" alt="" /></li>
<li class="social__list-item"><img src="http://placehold.it/100x100&text=Image" alt="" /></li>
<li class="social__list-item"><img src="http://placehold.it/100x100&text=Image" alt="" /></li>
<li class="social__list-item"><img src="http://placehold.it/100x100&text=Image" alt="" /></li>
<li class="social__list-item"><img src="http://placehold.it/100x100&text=Image" alt="" /></li>
<li class="social__list-item"><img src="http://placehold.it/100x100&text=Image" alt="" /></li>
<li class="social__list-item"><img src="http://placehold.it/100x100&text=Image" alt="" /></li>
<li class="social__list-item"><img src="http://placehold.it/100x100&text=Image" alt="" /></li>
</ul>
</div>
</div>
SCSS:
@mixin clearfix {
&:after {
content: "";
display: table;
clear: both;
}
}
ul {
padding: 0;
margin: 0;
}
img {
max-width: 100%;
}
@import "susy";
$susy: (
columns: 12,
);
.wrap {
@include container(1140px);
}
.content {
@media (min-width: 700px) {
@include span(8);
}
}
.sidebar {
@media (min-width: 700px) {
@include span(4 last);
}
}
.social {
padding: gutter();
@include clearfix;
.social__list-item {
@include gallery(2 of 10);
margin-bottom: gutter(10);
@media (min-width: 700px) {
@include gallery(1 of 10);
margin-bottom: 0;
}
}
}
.content,
.sidebar {
background: aquamarine;
text-align: center;
font-size: 28px;
line-height: 10em;
height: 10em;
}
.social {
background: black;
}
效果如下:
使用 Susy 和使用普通的 CSS 别无二致。其中的关键差异在于 Susy 是一位数学高手。
Susy 非常善于数学计算,它允许你创建古怪甚至是不对称宽度的栅格布局。
让我们尝试一下,为 CSS-Tricks 创建一个不对称宽度的栅格布局。
创建不对称的栅格时,声明方式有一点不同。你需要使用 Sass 列表来明确纵列的数量和尺寸的比例。因为 CSS-Tricks 的主内容区比侧边栏宽两部,那么可以设置 Sass 列表为 2 1
。这意味着一共有两列,其中一列为另一列的二倍。
同时还要在 Susy 的全局配置中设置输出模式为 isolate
。
$susy : (
columns: 2 1,
output: isolate,
)
现在我们不说主内容区有 8
列宽了,而是说只有 1
列。Susy 非常智能,只要你告诉它具体的位置,它就知道相应列的宽度。在本文示例中,主内容区为第一个元素。
.content {
@include span(1 first);
}
和上述相似的是,你需要告诉 Susy 侧边栏占用了几列。在本文示例中,侧边栏占用了第二列,恰巧这也是该行的最后一列。
.sidebar {
@include span(1 last);
}
最终的效果就像是这样:
关于不对称栅格的内容还有很多,絮絮叨叨地讲起来那就需要另起一篇文章了。我在我的博客上创建了一个简单的设计,介绍了非对称网格的概念。如下面的示例:
另外,我写了一个不对称布局的示例用来学习Susy,这个设计是基于Nathan Ford的设计。如果你想了解更多相关的东西,你得找本书全面了解一下。
我们已经完成了有关 Susy 的详细介绍,附带讲了些子像素约取的问题。非常希望你能够尝试一下 Susy,棒极了!
本文根据@Zell的《Build Web Layouts Easily with Susy》所译,整个译文带有我们自己的理解与思想,如果译得不好或有不对之处还请同行朋友指点。如需转载此译文,需注明英文出处:https://css-tricks.com/build-web-layouts-easily-susy/。
出处:http://www.w3cplus.com/preprocessor/build-web-layouts-easily-susy.html