那些你不知道的css自定义形状网格布局(代码片段)

南城FE 南城FE     2022-12-01     369

关键词:

在正常的开发中,我们会遇到很多元素块排列对齐的需求,如九宫格抽奖,多张图片上传后等分布局预览,微信朋友圈多张图片展示等。这都是正常的正方形很规整的布局。

如下所示,如果图像不是完全正方形,而是形状像六边形或菱形怎么办?我们怎么做呢。事实上,我们将结合我们已经研究过的 CSS 网格技术,并加入一些 CSS clip-pathmask魔法,为您可以想象的任何形状创建精美的图像网格!

相同的HTML

我们将要研究的大多数布局乍一看似乎很容易实现,但具有挑战性的部分是使用相同的 HTML 标记来实现它们。我们可以使用很多包装器、divs 等等,但这篇文章的目标是使用相同且最少的 HTML 代码,并且仍然可以实现我们想要的所有不同风格的网格。

这就是说,让我们从以下的HTML开始:

<div class="gallery">
  <img src="..." >
  <img src="..." >
  <img src="..." >
  <img src="..." >
  <!-- as many times as we want -->
</div>

一个带有图像的容器就是我们在这里所需要的。足已!

六边形 CSS 网格

这个形状有时也称为蜂窝网格。

首先,我们使用clip-path在图像上使用来创建六边形形状,并将它们全部放在同一个网格区域中,以便它们重叠。

.gallery 
  --s: 150px; /* controls the size */
  display: grid;


.gallery > img 
  grid-area: 1/1;
  width: var(--s);
  aspect-ratio: 1.15;
  object-fit: cover;
  clip-path: polygon(25% 0%, 75% 0%, 100% 50%, 75% 100%, 25% 100%, 0 50%);

此时所有的图像都是六边形并且重叠在一起。所以看起来我们只有一个六边形的图像元素,但实际上有七个。下一步将把图像平移到它们正确放置的网格上。

保留其中一张图像在中心位置。其余图像使用 CSS translate 平移在它周围。这是我为网格中的每个图像提出的模拟公式:

translate((height + gap)*sin(0deg), (height + gap)*cos(0))
translate((height + gap)*sin(60deg), (height + gap)*cos(60deg))
translate((height + gap)*sin(120deg), (height + gap)*cos(120deg))
translate((height + gap)*sin(180deg), (height + gap)*cos(180deg))
translate((height + gap)*sin(240deg), (height + gap)*cos(240deg))
translate((height + gap)*sin(300deg), (height + gap)*cos(300deg))

经过一些计算和优化后,我们得到以下最终 CSS

.gallery 
  --s: 150px; /* control the size */
  --g: 10px;  /* control the gap */
  display: grid;

.gallery > img 
  grid-area: 1/1;
  width: var(--s);
  aspect-ratio: 1.15;
  object-fit: cover;
  clip-path: polygon(25% 0%, 75% 0%, 100% 50% ,75% 100%, 25% 100%, 0 50%);
  transform: translate(var(--_x,0), var(--_y,0));

.gallery > img:nth-child(1)  --_y: calc(-100% - var(--g)); 
.gallery > img:nth-child(7)  --_y: calc( 100% + var(--g)); 
.gallery > img:nth-child(3),
.gallery > img:nth-child(5)  --_x: calc(-75% - .87*var(--g)); 
.gallery > img:nth-child(4),
.gallery > img:nth-child(6)  --_x: calc( 75% + .87*var(--g)); 
.gallery > img:nth-child(3),
.gallery > img:nth-child(4)  --_y: calc(-50% - .5*var(--g)); 
.gallery > img:nth-child(5), 
.gallery > img:nth-child(6)  --_y: calc( 50% + .5*var(--g)); 

每个图像都由基于这些公式的--_x和变量转换。--_y只有第二张图片 ( nth-child(2)) 在任何选择器中未定义,因为它位于中心。如果您决定使用不同的顺序,它可以是任何图像。这是我使用的顺序:

只需几行代码,我们就得到了一个很酷的图像网格。为此,我在图像上添加了悬停的效果,让交互效果更上一层楼,代码在线预览如下:

https://code.juejin.cn/pen/7132450107156332552

CSS 菱形网格

菱形是将一个正方形旋转45度。

还是相同的 HTML,我们首先在 CSS 中定义一个 2×2 的图像网格:

.gallery 
  --s: 150px; /* controls the size */

  display: grid;
  gap: 10px;
  grid: auto-flow var(--s) / repeat(2, var(--s));
  place-items: center;

.gallery > img 
  width: 100%; 
  aspect-ratio: 1;
  object-fit: cover;

然后设置旋转,请注意我如何将它们都旋转45deg,但方向相反。

.gallery 
  transform: rotate(45deg);

.gallery > img 
  transform: rotate(-45deg);

向负方向旋转图像可防止它们与网格一起旋转,因此它们保持笔直。现在,我们应用 clip-path 从它们中剪出菱形。

此时的图像并没有按我们的预期的间距排列,我们需要纠正图像的大小以使它们适合在一起。否则,它们的间距会很远,以至于看起来不像图像网格。

图像在绿色圆圈的边界内,即放置图像的网格区域的内切圆。我们想要的是将图像放大以适合红色圆圈,即网格区域的外接圆。

.gallery > img 
  width: 141%; /* 100%*sqrt(2) = 141% */
  aspect-ratio: 1;
  object-fit: cover;
  transform: rotate(-45deg);
  clip-path: polygon(50% 0, 100% 50%, 50% 100%, 0 50%);

最后,还是给图像增加悬停的效果,在线代码如下:
https://code.juejin.cn/pen/7132464081167974434

三角形的 CSS 网格

你现在可能知道,最大的窍门是找出clip-path我们想要的形状。对于这个网格,每个元素都有自己的clip-path值,而最后两个网格使用一致的形状。所以,这一次,就像我们正在处理几个不同的三角形形状,它们组合在一起形成一个矩形的图像网格。

我们使用以下 CSS 将它们放置在 3×2 网格中:

.gallery 
  display: grid;
  gap: 10px; 
  grid-template-columns: auto auto auto; /* 3 columns */
  place-items: center;

.gallery > img 
  width: 200px; /* controls the size */
  aspect-ratio: 1;
  object-fit: cover;

/* the clip-path values */
.gallery > img:nth-child(1)  clip-path: polygon(0 0, 50% 0, 100% 100% ,0 100%); 
.gallery > img:nth-child(2)  clip-path: polygon(0 0, 100% 0, 50% 100%); 
.gallery > img:nth-child(3)  clip-path: polygon(50% 0, 100% 0, 100% 100%, 0 100%); 
.gallery > img:nth-child(4)  clip-path: polygon(0 0, 100% 0, 50% 100%, 0 100%); 
.gallery > img:nth-child(5)  clip-path: polygon(50% 0, 100% 100%, 0% 100%); 
.gallery > img:nth-child(6)  clip-path: polygon(0 0, 100% 0 ,100% 100%, 50% 100%);  

最终得到的效果如下图所示:

最后一点是使中间列的宽度等于0消除图像之间的空间。我们在菱形网格中遇到了同样的间距问题,但对我们使用的形状采用了不同的方法:

grid-template-columns: auto 0 auto;

最终的在线代码如下:

https://code.juejin.cn/pen/7132468930584510502

比萨形状的 CSS 网格

基于上面的三角形网格通过添加简单的border-radius和overflow就可以实现另一个很酷的网格,比萨形状的 CSS 网格。

拼图风格的 CSS 网格

这次我们将使用 CSS mask 属性来使图像看起来像拼图。

现在设置网格应该是小菜一碟,所以让我们把注意力集中在mask上。我们需要两个渐变来创建最终的拼图形状。一个渐变创建一个圆形(绿色部分),另一个渐变创建红色区域并填充半圆白色区域。

--g: 6px; /* controls the gap */
--r: 42px;  /* control the circular shapes */

background: 
  radial-gradient(var(--r) at left 50% bottom var(--r), green 95%, #0000),
  radial-gradient(calc(var(--r) + var(--g)) at calc(100% + var(--g)) 50%, #0000 95%, red)
  top/100% calc(100% - var(--r)) no-repeat;

两个变量控制形状。--g变量控制网格间隙,相对不是最重要的。重要的是考虑间隙之间如何正确放置我们的圆圈,以便在组装整个拼图时它们完美重叠。该--r变量则控制拼图形状的圆形部分的大小。

然后我们使用相同的 CSS 值并针对不同的位置稍加调整来创建其他三个形状:

此时整体拼图形状好了,但没有按我们的预期重叠在一起。因为每个图像都被限制在它所在的网格单元中,所以现在形状有点混乱是对的:

我们需要通过增加图像的高度/宽度来创建溢出。从上图中,我们必须增加第一个和第四个图像的高度,同时增加第二个和第三个图像的宽度。您可能已经猜到我们需要使用--r变量来增加它们。

.gallery > img:is(:nth-child(1),:nth-child(4)) 
  width: 100%;
  height: calc(100% + var(--r));

.gallery > img:is(:nth-child(2),:nth-child(3)) 
  height: 100%;
  width: calc(100% + var(--r));

此时左边两张图片按预期展示了,但默认情况下,我们的图像要么在右侧(如果我们增加宽度)重叠,要么在底部(如果我们增加高度)重叠。但这不是我们想要的第二张和第四张图片。解决方法是在这两个图像上使用place-self: end,最后我们的完整代码如下:

https://code.juejin.cn/pen/7132472038211452942

最后来一个不一样的,为保障gif图加载速度,我将图片替换成纯色图像,这次我们使用clip-path,因为它是我们可以动画的属性,我们只需更新控制形状的自定义属性即可获得很酷的悬停效果。我们设置一个自定义变量控制默认的三角形的角度,在鼠标悬停时设置该变量为0则回到正常的正方形,效果图如下:

在线代码如下:
https://code.juejin.cn/pen/7133195476844675103

最后

本文通过将我们已经了解的有关 CSS Grid 的知识与一些附加clip-path的mask魔法相结合,我们能够制作不同形状的网格布局。而且我们每次都使用相同的 HTML 代码!代码本身只不过是一个包含少量图像元素的容器!看完是不是觉得很简单很神奇呢,有兴趣的同学可以自己试试看,兴许你能创造出更多有趣的网格图形。

看到最后如果觉得有用,记得点个赞收藏起来吧,说不定哪天就用上啦。

专注前端开发,分享前端相关技术干货,公众号:南城大前端(ID: nanchengfe)

8.13-8.19博客精彩回顾

一、优秀文章推荐1.​​那些你不知道的CSS自定义形状网格布局​​2.​​java之继承精选​​3.​​Java8重构传统设计模式,是真的优雅!​​4.​​实战Node.js之GET/POST请求在Web应用架构在客户端的使用​​5.​​【Docker那些事儿... 查看详情

那些你不知道的炫酷导航交互效果(代码片段)

基于上次发布的那些你不知道的炫酷按钮交互效果反馈比较好,后续将继续收集那些炫酷的交互效果,希望可以给你的项目添砖加瓦,更上一层楼。那些你不知道的炫酷交互效果系列:那些你不知道的炫酷按钮交互效果那些你不... 查看详情

那些你不知道的炫酷开关交互效果(12种)(代码片段)

本文将继续更新那些炫酷交互效果系列文章,今天带来的是有关toggle开关相关的组件。以下是本次文章涉及到的开关组件总览图,总计收集12款不同交互效果,相信总有一款适合你。那些你不知道的炫酷交互效果系列:那些你不... 查看详情

matplotlib使用gridspec和其他功能自定义图形布局(代码片段)

如何创建轴的网格状组合。subplots()也许用于创建图形和轴的主要功能。它也类似于matplotlib.pyplot.subplot(),但是会立即在图形上创建并放置所有轴。GridSpec指定将放置子图的网格的几何形状。需要设置网格的行数和列数。可选地,... 查看详情

如何将自定义网格添加到 ImageItem?

...示例相同:aitoff-hammer地图投影:.问题是,我的图像没有那些网格线。我已经验证了将像素值转换为纬度/经度坐标的代码是否有效,但 查看详情

css自定义网格css1/5与bootstrap断点(代码片段)

查看详情

字符串,那些你不知道的事(代码片段)

 Everythingyouthoughtyouknewaboutstringsiswrong.也许你会诧异,字符串有什么难的,即便遇到乱码的情况随便Google下就能找到解决方法,但是这样你不觉得有种被动的感觉嘛,我觉得和学习任何东西一样,学习编程首要是学习其思想,... 查看详情

你不知道的css---position小技巧(代码片段)

众所周时"position:sticky;"是粘性布局,相当于sticky与fixed的组合。但他的细节和妙用,未必人人皆知。所以记录下我这一周的学习总结,供大家参考使用。回顾positionvaluesposition中目前有五个值分别是static、relative、absolute、f... 查看详情

那些你不知道的kotlin冷知识(代码片段)

Lambda表达式Lambda固然好用,但是你知道Kotlin是如何实现的吗?kotlin代码funfoo(item:Int)=print(item)转换为java字节码@NotNullpublicfinalFunction0foo(finalintitem)return(Function0)(newFunction0()//$FF:syntheticm 查看详情

springcloudzuul那些你不知道的功能点(代码片段)

本文摘自于《SpringCloud微服务入门实战与进阶》一书。1./routes端点当@EnableZuulProxy与SpringBootActuator配合使用时,Zuul会暴露一个路由管理端点/routes。借助这个端点,可以方便、直观地查看以及管理Zuul的路由。将所有端点都暴露出来... 查看详情

你不知道的css单位(代码片段)

CSS中大部分属性值都有对应的量词单位,常见的如描述盒模型尺寸的width,height,margin,padding,border,又比如CSS3中的transform属性的一些值。下面的导图中基本上包括了所有的单位,下面将详细介绍它们的定义及使用方式。?一、长度单... 查看详情

grid布局(代码片段)

...局使我们能够比以往任何时候都可以更灵活构建和控制自定义网格;能够将网页分成具有简单属性的行和列来完成我们需要的网格布局。CSSGrid布局由两个核心组成部分是wrapper(父元素)和items(子元素)。wrapper是实际的grid(网格)... 查看详情

详解css中的网格布局,小程序中实现预约列表功能(代码片段)

...组成,我们在画图软件里标一下行、列及轨道的号码知道这个布局的构成后,我们就需要 查看详情

详解css中的网格布局,小程序中实现预约列表功能(代码片段)

...组成,我们在画图软件里标一下行、列及轨道的号码知道这个布局的构成后,我们就需要 查看详情

你不知道的线程池构造方法的那些趣事?(代码片段)

(手机横屏看源码更方便)注:java源码分析部分如无特殊说明均基于java8版本。简介ThreadPoolExecutor的构造方法是创建线程池的入口,虽然比较简单,但是信息量很大,由此也能引发一系列的问题,同样地,这也是面试中经常被问... 查看详情

vue.use内部那些你不知道的事儿(代码片段)

1.Vue.use的作用Vue.use的作用是注册全局插件强化Vue的功能 它也可以用来注册全局组件但是有一个条件注册的对象中必须提供 install 方法。如果插件是一个函数,它会被作为install方法。install方法调用时,会将Vue作为参数... 查看详情

css布局网格(代码片段)

查看详情

text现代浏览器的css网格布局(代码片段)

查看详情