css实现六边形及其它灵活布局

本文介绍了如何使用CSS创建六边形网格,利用clip-path、shape-outside和flexbox解决布局问题,详细阐述了各个步骤和技术细节,包括处理元素间隙、浮动元素的形状以及六边形的交错排列。

制作六边形网格

首先,创建我们的六边形。这个任务使用 clip-path 实现起来相当容易。另外推荐一个很棒的剪辑路径的在线生成器Clippy裁剪示意图一:

 <div class="main"><div class="container"><div></div><div></div><div></div><!--更多的元素. --> </div></div> 

css设置为:

 .main {display: flex;--s: 100px;/* size*/--m: 4px; /* margin */}.container {font-size: 0; /* 禁用内联块元素之间的空白 */}.container div {width: var(--s);margin: var(--m);height: calc(var(--s) * 1.1547);display: inline-block;font-size: initial;clip-path: polygon(0% 25%, 0% 75%, 50% 100%, 100% 75%, 100% 25%, 50% 0%);} 

到目前为止并没有什么复杂的处理逻辑,我们设置了一个容器container来存放inline-block的六边形元素,另外我们需要处理因为inline-block而导致的空白间隙问题(我们使用font-size: 0;进行修复):

<img src=“https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/1ab71f73de2d4087afde739f7c4de970~tplv-k3u1fbpfcp-zoom-in-crop-mark:4536:0:0:0.image?) 每隔一行我们都需要设置一些偏移量,以便使六边形元素重叠而不是直接堆叠在彼此之上。该偏移量将等于25%的元素高度(参考图 1)。我们将该偏移量应用于margin-bottom” style=“margin: auto” />

 .container div {width: var(--s);margin: var(--m);height: calc(var(--s) * 1.1547);display: inline-block;font-size: initial;clip-path: polygon(0% 25%, 0% 75%, 50% 100%, 100% 75%, 100% 25%, 50% 0%);margin-bottom: calc(var(--m) - var(--s) * 0.2886); /* 设置底部边距 */} 

…结果变成: <img src=“https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/a05659e35f23495ebbdedf2dc51ced73~tplv-k3u1fbpfcp-zoom-in-crop-mark:4536:0:0:0.image?) 现在我们面临的问题是如何移动第二行元素以获得完美的六边形网格。我们已经将元素压缩到行彼此垂直重叠的程度,我们还需要的是将元素每隔一行向右推,以便六边形交错而不是重叠。这时候就是float发挥shape-outside作用的时刻了” style=“margin: auto” />

你有没有想过为什么我们要设置一个display: flex.main元素来包裹我们的容器.container?该操作也是 div 布局技巧的一部分:

弹性项目的例子:

<div style="display:flex">

<!-- flex item: block child -->
<div id="item1">block</div>

<!-- flex item: floated element; 浮动被忽略 -->
<div id="item2" style="float: left;">float</div>

<!-- flex item: 行内文本会生成一个匿名的块 -->
anonymous item 3

<!-- flex item: inline child -->
<span>
item 4
<!-- flex items 内为普通流布局 -->
<q style="display: block" id=not-an-item>item 4</q>
item 4
</span>
</div> 

上述代码会生成:

请注意,元素间的空白消失了:它不会成为自己的弹性项目,即使元素间文本_确实_被包裹在匿名弹性项目中。

还要注意匿名项的框是不可设置样式的,因为没有要为其分配样式规则的元素。然而,它的内容将从 flex 容器继承样式(例如字体设置)。

这里我们使用.container::before伪类元素创建一个浮动元素,它占据了网格左侧的所有高度,并且宽度等于半个六边形(加上边距):

 .container::before { content: ""; width: calc(var(--s)/2 + var(--m)); float: left; height: 100%; } 

我们得到以下结果:

<img src=“https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/d50f61af4a704c318cf82bbfc6a22c6e~tplv-k3u1fbpfcp-zoom-in-crop-mark:4536:0:0:0.image?) 现在我们快速回顾一下shape-outsideMDN的描述” style=“margin: auto” />

shape-outsideCSS 属性定义了一个可以是非矩形的形状,相邻的内联内容应围绕该形状进行包装。默认情况下,内联内容包围其边距框; shape-outside提供了一种自定义此包装的方法,可以将文本包装在复杂对象周围而不是简单的框中。

注意定义中的“内联内容”。这恰恰解释了为什么六边形需要的是inline-block元素。但要了解我们需要什么样的形状,让我们放大图案:

 shape-outside: repeating-linear-gradient(#0000 0 A, #000 0 B); /* #0000 是 transparent 的一种写法 */ 

现在我们需要定义A、B的值。因为六边形网格布局,我们需要重复每两行,因此B的值两行的高度,两行的高度等于两个六边形的高度(包括它们的边距)减去重叠的两倍(2*Height + 4*M - 2*Height*25% = 1.5*Height + 4*M ),使用csscalc()并将该数值存在css变量f中:

 .main {display:flex;--s: 100px;/* size*/--m: 4px;/* margin */--f: calc(1.732 * var(--s) + 4 * var(--m)- 1px);} 

A(上图中蓝色箭头定义的)的值需要至少等于一个六边形的大小,或更大一点。为了将第二行推到右边,我们需要一些不透明颜色的像素,所以A可以简单地等于B - Xpx,其中X是一个小值,我们最终得到shape-outside的值如下:

 shape-outside: repeating-linear-gradient(#0000 0 calc(var(--f) - 3px),#000 0 var(--f)); 

我们将得到:

我们重复的线性渐变的形状是将每隔一行向右推一个六边形宽度的一半,以抵消图案,最终代码如下:

 .main {display:flex;--s: 100px;/* size*/--m: 4px;/* margin */--f: calc(var(--s) * 1.732 + 4 * var(--m) - 1px); }.container {font-size: 0; /* 清除行内块级元素的边距 */}.container div {width: var(--s);margin: var(--m);height: calc(var(--s) * 1.1547);display: inline-block;font-size:initial;clip-path: polygon(0% 25%, 0% 75%, 50% 100%, 100% 75%, 100% 25%, 50% 0%);margin-bottom: calc(var(--m) - var(--s) * 0.2885);}.container::before {content: "";width: calc(var(--s) / 2 + var(--m));float: left;height: 120%; shape-outside: repeating-linear-gradient(#0000 0 calc(var(--f) - 3px), #000 0 var(--f));} 

至此,六边形网格布局基本完成。您可能已经注意到我在变量f中添加了-1px。由于我们正在处理涉及小数的计算,四舍五入可能会给我们带来不好的结果。为了避免这种情况,我们添加或删除了几个像素。出于类似的原因,我们也使用120%而不是100%浮动元素的高度。这些值没有特定的逻辑;我们只是简单地调整它们以确保覆盖大多数情况而不会错位我们的形状。

最后

整理了75个JS高频面试题,并给出了答案和解析,基本上可以保证你能应付面试官关于JS的提问。



有需要的小伙伴,可以点击下方卡片领取,无偿分享

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值