前端开发者学堂 - fedev.cn

使用Sass制作菱形网格布局

发布于 南北

自从我从事 WEB 开发以来,一直都在规规矩矩地使用标准的栅格布局。直到有一次在公司跟实习生交流时,我意识到开发者的思维已经被条条框框固定住了。这里并不是想说栅格布局这种规规矩矩的布局有什么不好,实际上这些布局就像是沃尔沃汽车一样,让人感到安稳和可靠。但是,拥抱变化何尝不是一件趣事?非常幸运的是,我能与众多才华横溢的设计师共同工作。在最近的一个项目中,他们提出了一种基于栅格布局的菱形布局。话不多说,迎战问题(•̀o•́)ง!

旋转 div

首先,我并没有迅速投入到实际效果的开发中,而是使用 HTML 和 CSS 对脑海中的一些灵感进行验证。第一个浮现在我脑海中的想法就是使用 CSS transforms 来处理这种布局。只是使用 transform: rotate(45deg) 就可以了吗?然而这并没有达到我们想要的效果。设计师提供的效果图由两小、两中、一大五个菱形组成,各个菱形相邻分布,而且稍微改动一下还可以实现反向效果。

菱形网格

菱形网格

我编写的布局标签如下所示:

<div class="grid-wrapper layout-1">
    <div class="grid-item diamond-small diamond-s1">
        <div class="diamond__content">
            <p>small diamond</p>
        </div>
    </div>
    <div class="grid-item diamond-med diamond-m1">
        <div class="diamond__content">
            <p>medium diamond</p>
        </div>
    </div>
    <div class="grid-item diamond-large">
        <div class="diamond__content">
            <p>large diamond</p>
        </div>
    </div>
    <div class="grid-item diamond-small diamond-s2">
        <div class="diamond__content">
            <p>small diamond</p>
        </div>
    </div>
    <div class="grid-item diamond-med diamond-m2">
        <div class="diamond__content">
            <p>medium diamond</p>
        </div>
    </div>
</div>

然后我使用 Sass 创建了一些变量,比如创建了一个 grid-unit 来保存栅格单元的尺寸,其中 95vw/16 就是这个栅格单元的尺寸,这个尺寸并没有太多深意,在这里只是用于演示效果:

$gridUnit: 95vw / 16;
$small: $gridUnit * 2;
$med: $gridUnit * 3;
$large: $gridUnit * 4;

看到这里,相信聪明的你已经猜到了这种方法决不能创建我们需要的布局,因为当我们旋转时,所有的标签是以自身为中心进行旋转的,最终我们看到的效果就是这样:

菱形网格

菱形网格

裁剪 div

我的第二个想法是使用 CSS clip-path,该属性允许开发者隐藏元素的特定区域,所有超过该区域的内容都不会被裁减掉。要创建裁剪区域,需要引用 SVG 的路径,或者使用类似于 CSS shapes 中用到的塑形方法(shape method)。不幸的是,任何版本的 IE 浏览器都不支持 CSS clip-path,Firefox 只支持 url() 引用 SVG 的方式,而 Chrome 不支持使用 url() 引用外部 SVG 的方式。所以,我找到了一个用于 CSS clip-path 的脚本(ployfill),用于解决浏览器的不支持问题。

该想法的实质就是裁剪掉正方形的边角模拟出菱形来,而正方形的边长正好是菱形对角线的长度,稍微加工一下,效果如下:

此时,看起来我已经实现了设计师想要的那种效果,但是实际上还缺少了一些视觉效果。我可以假设它的背景就是菱形栅格,然后使用 CSS 来模拟实现。如果所有的菱形栅格都是相同尺寸的菱形,那就更容易了。稍作修饰,效果如下:

然后我仔细查看了设计师提供的设计图。简而言之,这个菱形布局是用于偏向于图片展示的网站,上面将会有大量的图片,而且每个栅格单元的背景具有一定的纹理。此外,为了突出显示某些菱形,需要为它们的边角添加一些高亮效果。那么,我们可以给这些需要突出显示的菱形添加一些内阴影。

中学数学的救赎

因为这里的菱形可以看成是由正方形旋转之后得到的,所有可知图示的三角形 AOH 为等腰直角三角形:

菱形网格

由中学数学知识可以,在等腰直角三角形中,斜边除以 Math.sqrt(2) 等于直角边,所以我使用 Sass 写了一个 @function 来计算 Math.sqrt(2)

@function sqrt($r) {
    $x0: 1;
    $x1: $x0;
    @for $i from 1 through 10 {
        $x1: $x0 - ($x0 * $x0 - abs($r)) / (2 * $x0);
        $x0: $x1;
    }
    @return $x1;
}
$gridUnit: (100vw / 8);
$transformUnit: $gridUnit / sqrt(2);
$small: $transformUnit * 2;
$med: $transformUnit * 3;
$large: $transformUnit * 4;

现在我还没有想出让每一个菱形绝对定位的方式,如果你有什么建议欢迎交流。我已经尽力结构化标签上的类名了,如果时间允许,我想我会尽可能多地去尝试不同的方式。现在,根据之前创建的栅格单元确定大小和位置是最大的一个活了,幸亏 Sass 的帮助我才能这么顺利地搞定这项工作:

See the Pen Diamond grid with Sass (Transform) by Chen Hui Jing (@huijing) on CodePen.

视觉优化

使用 CSS 旋转 div,可以让需要突出显示的菱形拥有内阴影。对于菱形的背景,我使用了纹理图片,然后微调了 div 的对齐方式以贴合纹理图片。因为我是用了 viewport width(vw) 作为栅格单元的长度单位,所以布局效果时响应式,然而,这种方式的缺点在于背景的纹理图片也会根据视图宽度收缩或拉伸。

解决这一问题的方法就是让背景图片非常精确地贴合相应的栅格,但实际上由于屏幕尺寸多种多样很难实现尺寸的精准贴合。在大尺寸的屏幕上 1 像素的缺失都会非常显眼。因为我所做的项目并非整体都是响应式的,所有并没有遇到这样的问题:

body {
    @media screen and (min-width: 1000px) and (max-width: 1919px) {
        background: url('../img/bg-tile.jpg') repeat-y;
        background-size: contain;
    }
}

这里的技巧就是使用 background-size: contain 来设置背景图片。根据 MDN 的资料,浏览器会自动伸缩图片保持屏宽比。虽然我尽力让背景和 Sass 的栅格单元尺寸保持一致,但总有一两个像素的差异。好在这些差异在我的项目中并不明显。高亮效果使用了 :before:after 伪元素,同时使用了 Sass 栅格单元的尺寸来定位到正确的位置。

总结

这是一个有趣的项目,视野和技能方面都有所收获。在这个项目中还有很多值得思考的地方,但是布局效果是其他设计效果的基础。CSS 属性中的 clip-path/transform/css shapes,为我们提供了足够的灵活性去探索不同的布局。在我开发这个项目的同时,Trevor Davis 同样实现了一个菱形布局。我们正在突破现有的布局桎梏,相信未来 CSS 将会更加健壮,我们可以创建更富有创造性的设计效果。

本文根据@Hui Jing的《Diamond grid layout with Sass》所译,整个译文带有我们自己的理解与思想,如果译得不好或有不对之处还请同行朋友指点。如需转载此译文,需注明英文出处:http://www.chenhuijing.com/blog/diamond-grid-using-sass/

南北

在校学生,本科计算机专业。狂热地想当一名作家,为色彩和图形营造的视觉张力折服,喜欢调教各类JS库,钟爱CSS,希望未来加入一个社交性质的公司,内心极度肯定“情感”在社交中的决定性地位,立志于此改变社交关系的快速迭代。个人博客

如需转载,烦请注明出处:https://www.fedev.cn/preprocessor/diamond-grid-using-sass.htmlAir Max 95 - Fresh Mint