今天,收到一个很有意思的提问,如何实现类似如下的背景效果图:
嗯?核心主体是由多个六边形网格叠加形成。
那么我们该如何实现它呢?使用纯 CSS 能够实现吗?
当然可以,下面我们就将尝试如何使用 CSS 去实现这样一个背景效果。
首先,看到这样一个图形,如果想要使用一个标签完成整个背景,最先想到的肯定是使用背景 background 实现,不过可惜的是,尽管 CSS 中的 background 非常之强大,但是没有特别好的方式让它足以批量生成重复的六边形背景。
因此,在这个需求中,我们可能不得不退而求其次,一个六边形实现使用一个标签完成。
那么,就拿 1 个 DIV 来说,我们有多少实现六边形的方式呢?这里简单介绍 2 种方式:
首先,使用 border 实现六边形。这里的核心在于上下两个三角形叠加中间一个矩形。这里,利用元素的两个伪元素实现上下两个三角形,从而让这个元素看起来像一个六边形。
思路比较简单,直接上代码:
.hexagon {
position: relative;
width: 200px;
height: 100px;
background-color: red;
}
.hexagon:before,
.hexagon:after {
content: "";
position: absolute;
width: 0;
height: 0;
border-left: 100px solid transparent;
border-right: 100px solid transparent;
}
.hexagon:before {
bottom: 100%;
border-bottom: 50px solid red;
}
.hexagon:after {
top: 100%;
border-top: 50px solid red;
}
上面的代码会创建一个宽度为 200 像素,高度为 100 像素的六边形,其中由两个三角形和一个矩形组成。使用伪元素的优点是可以很方便地控制六边形的大小、颜色等样式。
当然,上述的代码不是一个正六边形,这是因为正六边形中,元素的高是元素的宽的 1.1547 倍。
并且,上述的方式也稍微复杂了点,因此,在今天,我们更推荐使用 clip-path 的方式去实现一个六边形:
.clippath {
--w: 100px;
width: var(--w);
height: calc(var(--w) * 1.1547);
clip-path: polygon(0% 25%, 0% 75%, 50% 100%, 100% 75%, 100% 25%, 50% 0%);
background: deeppink;
margin: auto;
}
这样,基于 clip-path,也能快速得到一个六边形图形:
CodePen Demo -- Two ways to achieve a hexagon
好了,有了上一步的铺垫之后,接下来我们要做的,就是绘制多个六边形,组成背景。
但是我们仔细观察一下由多个六边形组成的背景,会发现每双数行的的六边形,需要向右侧有一个明显的缩进,宽度大概为单个六边形的宽度的一半:
这里其实是一个非常棘手的问题。首先,我们会想到这样一种解决方案:
margin-left基于这个策略,我们的代码,大概会是这样:
<div class="container">
<div class="wrap">
// ... 填满六边形
</div>
<div class="wrap" style="margin-left: 25px">
// ... 填满六边形
</div>
<div class="wrap">
// ... 填满六边形
</div>
<div class="wrap" style="margin-left: 25px">
// ... 填满六边形
</div>
</div>
可以看到,我们给偶数行,都添加了一个 margin-left。
但是这个代码,会有几个问题:
什么意思呢?也就是效果可能在屏幕非常宽的情况下,失效。
看看,正常情况,我们设置了每行 20 个六边形,下图是正常的
但是如果我们的屏幕特别宽,那么,可能会得到这样一种效果:
因此,这种方式存在非常大的弊端,我们希望能有一整布局方式,能够满足我们如下两个诉求:
仔细思考一下,CSS 中有能够实现类似布局的方法么?
有的!在 CSS 中,有一个神奇的元素能够让元素以非直线形式排布。它就是 shape-outside!
如果你对
shape-outside不太了解,也可以先看看我的这篇文章 -- 奇妙的 CSS shapes
shape-outside 是 CSS 中的一个属性,用于控制元素的浮动方式。它允许你定义一个元素浮动时周围元素的形状。例如,你可以使用 shape-outside 属性来定义一个元素浮动时周围元素的形状为圆形、六边形等。
它和 clip-path 的语法非常类似,很容易触类旁通。看看实例,更易理解:
假设我们有下面这样的结构存在:
<div class="container">
<div class="shape-outside">
<img src="image.png">
</div>
xxxxxxxxxxx,文字描述,xxxxxxxxx
</div>
定义如下 CSS:
.shape-outside {
width: 160px;
height: 160px;
shape-outside: circle(80px at 80px 80px);
float: left;
}
注意,上面 .shape-outside 使用了浮动,并且定义了 shape-outside: circle(80px at 80px 80px) ,表示在元素的 (80px, 80px) 坐标处,生成一个 80px 半径的圆。
如此,将会产生一种图文混排的效果:
CodePen Demo -- 图文混排 shape-outside
总得来说,shape-outside 有两个核心特点:
shape-outside 属性仅在元素定义了 float 属性且不为 none 时才会生效shape-outside 的本质划重点,划重点,划重点。
所以,shape-outside 的本质其实是生成几何图形,并且裁剪掉其几何图形之外周围的区域,让内容能排列在这些被裁剪区域之内。
所以,了解了这个本质之后,我们再将他运用在上面的六边形布局之中。
为了方便理解,我们首先使用文字代替上面的六边形,假设我们有这样一段文本内容:
<p>
Lorem ipsum dolor sit amet conse...
</p>
p {
line-height: 36px;
font-size: 24px;
}
非常平平无奇的一段代码,效果如下:
现在,我们想利用 shape-outside,让文本内容的偶数行,向内缩进 24px,怎么实现呢?非常简单:
p {
position: relative;
line-height: 36px;
font-size: 24px;
&::before {
content: "";
height: 100%;
width: 24px;
shape-outside: repeating-linear-gradient(
transparent 0,
transparent 36px,
#000 36px,
#000 72px
);
float: left;
}
}
这样,我们就实现了文字隔行缩进 24px 的效果:
一定有小伙伴会很好奇,为什么呢?核心在于我们利用元素的伪元素实现了一个 shape-outside 图形,如果我们把这个图形用 background 绘制出来,其实它长这样:
p {
position: relative;
line-height: 36px;
font-size: 24px;
&::before {
content: "";
height: 100%;
width: 24px;
shape-outside: repeating-linear-gradient(
transparent 0,
transparent 36px,
#000 36px,
#000 72px
);
float: left;
background: repeating-linear-gradient(
transparent 0,
transparent 36px,
#f00 36px,
#f00 72px
);
}
}
效果如下:
因为文本的行高是 36px,这样我们以 72 为一段,每 36px 绘制一段透明,另外 36px 绘制一段宽为 24px 的内容,这样,结合 shape-outside 的特性,我们就实现了隔行将内容向里面挤 24px 的效果!
非常的 Amazing 的技巧!完整的代码你可以戳这里:
CodePen Demo -- Shape-outside achieves even line indentation
基于这个技巧,我们就可以实现上述我们想要的效果了。我们回到正题,重新实现一个充满六边形的背景:
<ul class="wrap">
<li></li>
//... 非常多个 li
<ul>
:root {
--s: 50px; /* size */
--m: 4px; /* margin */
--perHeight: calc(calc(var(--s) * 2 * 1.1547) + calc(var(--m) * 4) - 0.4px)
}
.wrap {
position: relative;
height: 100%;
font-size: 0;
&::before {
content: "";
height: 100%;
width: 27px;
shape-outside: repeating-linear-gradient(
transparent 0,
transparent 70px,
#000 70px,
#000 var(--perHeight)
);
float: left;
}
}
li {
width: var(--s);
height: calc(var(--s) * 1.1547);
background: #000;
clip-path: polygon(0% 25%, 0% 75%, 50% 100%, 100% 75%, 100% 25%, 50% 0%);
margin: var(--m);
display: inline-block;
}
借助 shape-outside,我们就实现了隔行让我们的六边形向内缩进的诉求!效果如下:
当然,有一些优化点:
120%,然后水平居中,这样,两侧的留白就解决了margin-bottom做完这两点优化之后,效果如下:
可以做到任意屏幕宽度下的六边形完美平铺布局:
完整的代码你可以戳这里:CodePen Demo -- Hexagon Layout
有了上述的铺垫后,要实现文章一开头的效果就不难了。
是的,我们要实现这样一个效果:
如何让它们动态的实现颜色变换呢?是给每一个六边形一个单独的颜色,然后进行动画吗?不,借助混合模式,我们可以非常快速的实现不同的颜色值。
首先,我们将上述效果,改成白底黑色六边形色块:
然后,利用父容器剩余的一个伪元素,我们叠加一层渐变层上去:
.wrap {
position: relative;
// 代码与上述保持一致
&::before {
content: "";
// ... 实现 shape-outside 功能,代码与上述保持一致
}
&::after {
content: "";
position: absolute;
inset: 0;
background: linear-gradient(45deg, #f44336, #ff9800, #ffe607, #09d7c4, #1cbed3, #1d8ae2, #bc24d6);
}
}
这样,我们就叠加了一层渐变色彩层在原本的六边形背景之上:
接着,只需要一个混合模式 mix-blend-mode: darken,就能实现六边形色块与上层渐变颜色的融合效果:
.wrap {
position: relative;
// 代码与上述保持一致
&::before {
content: "";
// ... 实现 shape-outside 功能,代码与上述保持一致
}
&::after {
content: "";
position: absolute;
inset: 0;
background: linear-gradient(45deg, #f44336, #ff9800, #ffe607, #09d7c4, #1cbed3, #1d8ae2, #bc24d6);
z-index: 1;
+ mix-blend-mode: darken;
}
}
效果如下:
好, 我们再给上层的渐变色块,添加一个 filter: hue-rotate() 动画,实现色彩的渐变动画:
.wrap {
position: relative;
// 代码与上述保持一致
&::before {
content: "";
// ... 实现 shape-outside 功能,代码与上述保持一致
}
&::after {
content: "";
position: absolute;
inset: 0;
background: linear-gradient(45deg, #f44336, #ff9800, #ffe607, #09d7c4, #1cbed3, #1d8ae2, #bc24d6);
z-index: 1;
mix-blend-mode: darken;
+ animation: change 10s infinite linear;
}
}
@keyframes change {
100% {
filter: hue-rotate(360deg);
}
}
这样,我们就完美的实现了我们想要的效果:
完整的代码,你可以戳这里:CodePen Demo -- Hexagon Gradient Layout
当然,有了这个基础图形之后,其实我们可以基于这个图形,去做非常多有意思的效果。
下面我是尝试的一些效果示意,譬如,我们可以将颜色放置在六边形背景的下方,制作这样一种效果:
CodePen Demo -- Hexagon Gradient Layout
配合 mask 的蒙版效果及鼠标定位,我们还能实现这样一种有趣的交互效果:
CodePen Demo -- Hexagon Gradient & MASK Layout
当然,3D 效果也不在话下:
CodePen Demo -- 3D Hexagon Gradient Layout
好了,本文到此结束,希望本文对你有所帮助 ?
更多精彩 CSS 技术文章汇总在我的 Github -- iCSS ,持续更新,欢迎点个 star 订阅收藏。
如果还有什么疑问或者建议,可以多多交流,原创文章,文笔有限,才疏学浅,文中若有不正之处,万望告知。
所以我在关注Railscast,我注意到在html.erb文件中,ruby代码有一个微弱的背景高亮效果,以区别于其他代码HTML文档。我知道Ryan使用TextMate。我正在使用SublimeText3。我怎样才能达到同样的效果?谢谢! 最佳答案 为SublimeText安装ERB包。假设您安装了SublimeText包管理器*,只需点击cmd+shift+P即可获得命令菜单,然后键入installpackage并选择PackageControl:InstallPackage获取包管理器菜单。在该菜单中,键入ERB并在看到包时选择
我有一张背景图片,我想在其中添加一个文本框。我想弄清楚如何将标题放置在其顶部的正确位置。(我使用标题是因为我需要自动换行功能)。现在,我只能让文本显示在左上角,但我需要能够手动定位它的开始位置。require'RMagick'require'Pry'includeMagicktext="Loremipsumdolorsitamet"img=ImageList.new('template001.jpg')img 最佳答案 这是使用convert的ImageMagick命令行的答案。如果你想在Rmagick中使用这个方法,你必须自己移植
动漫制作技巧是很多新人想了解的问题,今天小编就来解答与大家分享一下动漫制作流程,为了帮助有兴趣的同学理解,大多数人会选择动漫培训机构,那么今天小编就带大家来看看动漫制作要掌握哪些技巧?一、动漫作品首先完成草图设计和原型制作。设计草图要有目的、有对象、有步骤、要形象、要简单、符合实际。设计图要一致性,以保证制作的顺利进行。二、原型制作是根据设计图纸和制作材料,可以是手绘也可以是3d软件创建。在此步骤中,要注意的问题是色彩和平面布局。三、动漫制作制作完成后,加工成型。完成不同的表现形式后,就要对设计稿进行加工处理,使加工的难易度降低,并得到一些基本准确的概念,以便于后续的大样、准确的尺寸制定。四、
在学习Python之后,我现在正在尝试学习Ruby,但我在将这段代码转换为Ruby时遇到了问题:defcompose1(f,g):"""Returnafunctionh,suchthath(x)=f(g(x))."""defh(x):returnf(g(x))returnh我必须使用block来翻译吗?或者Ruby中是否有类似的语法? 最佳答案 您可以使用Ruby中的lambda执行此操作(我在这里使用的是1.9stabby-lambda):compose=->(f,g){->(x){f.(g.(x))}}所以compose是一个返
写在之前Shader变体、Shader属性定义技巧、自定义材质面板,这三个知识点任何一个单拿出来都是一套知识体系,不能一概而论,本文章目的在于将学习和实际工作中遇见的问题进行总结,类似于网络笔记之用,方便后续回顾查看,如有以偏概全、不祥不尽之处,还望海涵。1、Shader变体先看一段代码......Properties{ [KeywordEnum(on,off)]USL_USE_COL("IsUseColorMixTex?",int)=0 [Toggle(IS_RED_ON)]_IsRed("IsRed?",int)=0}......//中间省略,后续会有完整代码 #pragmamulti_c
我有以下代码#coloursarandomcellwithacorrectcolourdefcolour_random!whiletruedocol,row=rand(columns),rand(rows)cell=self[row,col]ifcell.empty?thencell.should_be_filled??cell.colour!(1):cell.colour!(0)breakendendend做什么并不重要,尽管它应该很明显。关键是Rubocop给了我一个警告Neveruse'do'withmulti-line'while为什么我不应该那样做?那我该怎么办呢?
我在阅读有关.each迭代器的Ruby问题,有人说如果更高阶的迭代器更适合该任务,则使用.each可能会产生代码味道。Ruby中的高阶迭代器是什么?编辑:我提到的StackOverflow答案的作者JörgWMittag提到他是要编写更高级别的迭代器,但他还解释了下面的内容。 最佳答案 哎呀。我的意思是更高级别的迭代器,而不是更高阶的迭代器。当然,每个迭代器都是高阶的。基本上,迭代是一个非常低级的概念。编程的目的是与团队中的其他利益相关者交流意图。“初始化一个空数组,然后遍历另一个数组,并将该数组的当前元素添加到第一个数组中(如果该
我将RoR与PostGIS结合使用来存储位置数据。我正在尝试使用圆(例如,带半径的中心点)来存储估计位置。我试过类似的东西,但它不起作用:@location=Location.new(:place_id=>place.id,:circle=>%{ST_Buffer(ST_MakePoint(#{latitude},#{longitude})::geography,#{accuracy})})我也尝试过使用RGeo,它是出厂设置,但不确定如何准确使用它。任何帮助将不胜感激。谢谢。编辑1:我取得了一些进步。factory=RGeo::Cartesian.factorycenter_poin
我尝试用Ruby设计一个基于Web的应用程序。我开发了一个简单的核心应用程序,在没有框架和数据库的情况下在六边形架构中实现DCI范例。核心六边形中有小六边形和网络,数据库,日志等适配器。每个六边形都在没有数据库和框架的情况下自行运行。在这种方法中,我如何提供与数据库模型和实体类的关系作为独立于数据库的关系。我想在将来将框架从Rails更改为Sinatra或数据库。事实上,我如何在这个核心Hexagon中实现完全隔离的rails和mongodb的数据库适配器或框架适配器。有什么想法吗? 最佳答案 ROM呢?(Ruby对象映射器)。还有
我在View中有这段代码prawn_document(:page_size=>"A4",:top_margin=>80,:bottom_margin=>40,:background=>"public/uploads/1.png")do|pdf|creation_date=Time.now.strftime('%d-%m-%Y')posts=@posts.eachdo|post|pdf.pad(10)dopdf.textpost.titlepdf.textpost.textendendpdf.page_count.timesdo|i|pdf.go_to_page(i+1)pdf.draw