本文翻译自 CSS Grid and Custom Shapes, Part 3,略有删改 原作者:Temani Afif基于CSS自定义网格已发布第一部分和第二部分,本文将开始第三部分探讨更多的奇特自定义形状,与之前的文章一样,核心还是基于CSS grid,clip 和 mask来自定义网格形状布局。
CSS网格和自定义形状系列 第1部分 第2部分 第3部分(当前文章)三部分文章不一定要按照顺序阅读,之间没有强制的关联关系,但是可以看看之前的文章,了解作者是如何完成当前的效果,接下来开始我们的第一个案例。
以上效果图我们的HTML代码如下:
<div class="gallery">
<img src="..." alt="...">
<img src="..." alt="...">
<img src="..." alt="...">
<img src="..." alt="...">
</div>
本系列的主要挑战都是尽可能使用少量的html标签,后续的示例也是使用相同的html代码,不会有其他的div,嵌套元素等,仅需要如上的代码结构。
然后再来看看CSS代码:
.gallery {
--g: 6px; /* the gap */
display: grid;
width: 450px; /* the size */
aspect-ratio: 1; /* equal height */
grid: auto-flow 1fr / repeat(3, 1fr);
gap: var(--g);
}
.gallery img:nth-child(2) {
grid-area: 1 / 2 / span 2 / span 2;
}
.gallery img:nth-child(3) {
grid-area: 2 / 1 / span 2 / span 2;
}
基于上面的CSS是可以看出把整个盒子分为了一个3 ✖️ 3 的网格,第二个和第三个图像设定了相应的网格属性,第一个和最后一个图像将自动围绕布局。
这里的核心代码是 grid: auto-flow 1fr / repeat(3, 1fr);,这里使用了CSS网格简写属性,相当于以下代码:
grid-template-columns: repeat(3, 1fr);
grid-auto-rows: 1fr;
简写属性对应每个属性的值可以通过浏览器DevTools展开看到以下数据。
此同样适用于网格区域属性,当我们定义CSS网格面积为:
grid-area: 1 / 2 / span 2 / span 2;
最终对应的具体属性值如下:
grid-row-start: 1; /* 从第一行开始 */
grid-column-start: 2; /* 从第二列开始 */
grid-row-end: span 2; /* 占据两行 */
grid-column-end: span 2; /* 占据两列 */
基于以上网格区域声明,即得到以下结果:
我们的第二张和第三张图像在中间重叠,这是故意将它们重叠在一起,这样就可以使用 clip-path,从两个图像中裁剪出一部分,得到最终的效果:
们可以使用CSS clip-path 属性裁剪第二张图片(img:nth-child(2))的左下角:
clip-path: polygon(0 0, 100% 0, 100% 100%, calc(50% + var(--g) / 4) 100%, 0 calc(50% - var(--g) / 4))
裁剪第三张图片(img:nth-child(3))的右上角:
clip-path: polygon(0 0, calc(50% - var(--g) / 4) 0, 100% calc(50% + var(--g) / 4), 100% 100%, 0 100%);
如果不理解 clip-path 的用法,我有一篇文章详细介绍如何使用这种技术。
这个效果的网格配置没有上一张强烈,因为我们只需要两张重叠的图像:
.gallery {
display: grid;
}
.gallery > img {
grid-area: 1 / 1;
width: 350px; /* the size */
aspect-ratio: 1; /* equal height */
}
悬停效果依赖于动画剪辑路径。我们将详细剖析第一个图像的代码,看看它是如何实现的,然后用更新的值将相同的代码应用到第二个图像。仔细分析可以得出挣个动画过程中出现有三种不同的状态:
在每种状态下,我们都有一个三角形。这意味着我们需要一个三点多边形作为clip-path的值。
什么?你可能有疑问,第二个状态不是三角形,而是一个带有切角的正方形。肉眼看确实是一个带有切角的正方形,但如果我们仔细看,我们可以看到一个“隐藏”的三角形,给图像添加一个方框阴影的效果就比较清晰了。
box-shadow: 0 0 0 200px red;
这是什么原理呢?原理就是 clip-path 接受0%-100%范围之外的值,这将允许我们创建“溢出”元素本身的形状。这样我们只需要使用三个点,而不是使用五个点,就可以完成我们期望的效果。最终图片的 clip-path 属性值如下所示:
.gallery > img:first-child {
clip-path: polygon(0 0, calc(100% + var(--_p)) 0 , 0 calc(100% + var(--_p)))
}
.gallery > img:last-child {
clip-path: polygon(100% 100%, 100% calc(0% - var(--_p)), calc(0% - var(--_p)) 100%)
}
这里增加了--_p变量,即两图之间的间隙距离。基于此来优化代码,因为我们添加了悬停过渡。我们不需要更新整个clip-path,而只更新此变量即可以获得动画效果。
最后是增加悬停后的完整代码:
.gallery {
--g: 8px; /* the gap */
}
.gallery > img {
/* etc. */
--_p: calc(-1 * var(--g));
transition: .4s .1s;
}
.gallery:hover > img:last-child,
.gallery:hover > img:first-child:hover{
--_p: calc(50% - var(--g));
}
.gallery:hover > img:first-child,
.gallery:hover > img:first-child:hover + img {
--_p: calc(-50% - var(--g));
}
每个图像是一个圆的四分之一,鼠标悬停时,基于动画将一个图像转换为一个完整的圆,覆盖其余的图像。看起来是不是很炫酷呢,接下来开始具体的实现过程。
首先给整个元素增加 border-radius: 50%使其变为圆形。
然后是针对每个图像设置 clip-path 值,clip-path由七个点组成,其中三个点位于固定位置,如上图所示,默认就是一个三角形。当悬停时,修改剩余几个点的数值并加上过渡动画。
transition: transform .2s, clip-path .3s .2s, z-index 0s;
但是当它运行缓慢时,效果看起来不那么酷,但我们可以看到剪辑路径如何在形状之间进行变化的。以下是第一个图像的代码,其他的几个图像类似,只是对应方向的数值不同:
.gallery > img:nth-child(1) {
clip-path: polygon(50% 50%, calc(50% * var(--_i, 0)) calc(120% * var(--_i, 0)), 0 calc(100% * var(--_i, 0)),0 0, 100% 0, 100% calc(100% * var(--_i, 0)), calc(100% - 50% * var(--_i, 0)) calc(120% * var(--_i, 0)));
}
.gallery > img:hover {
--_i: 1;
}
这里还是像往常一样,我使用一个变量来优化代码。变量将在0和1之间切换来达到更新多边形的效果。
基于上面的效果图,我们来分析每个图像的位置和大小。我们需要确定网格需要多少列和行数:
这仅仅是我理解它的方式。我相信还有其他的配置可以得到同样的布局,有兴趣的同学可以用自己的思路实现看看。
基于以上我们定义的网格,然后将图像放在对应的网格上面:
.gallery {
display: grid;
grid: repeat(2, 1fr) / repeat(4, 1fr);
aspect-ratio: 2;
}
.gallery img:nth-child(1) {
grid-area: 1 / 1 / span 2 / span 2;
}
.gallery img:nth-child(2) {
grid-area: 1 / 2 / span 2 / span 2;
}
.gallery img:nth-child(3) {
grid-area: span 2 / span 2 / -1 / -1;
}
.gallery img:nth-child(4) {
grid-area: 2 / 1 / span 1 / span 2;
}
.gallery img:nth-child(5) {
grid-area: span 1 / span 2 / -1 / -1;
}
看到这相信你已经发现我们使用相同方法的例子。我们定义了一个网格并将图像显式地放置在网格上,使用网格区域使图像重叠。最后将重叠的部分进行裁剪达到最终的目的。接下来就是裁剪的部分,我们总共有四个三角形和一个菱形。
完整代码:
.gallery img:nth-child(1) {
grid-area: 1/1/span 2/span 2;
clip-path: polygon(0 0,100% 0,0 100%);
}
.gallery img:nth-child(2) {
grid-area: 1/2/span 2/span 2;
clip-path: polygon(50% 0,100% 50%,50% 100%,0 50%);
}
.gallery img:nth-child(3) {
grid-area: span 2/span 2/-1/-1;
clip-path: polygon(0 0,100% 0,100% 100%);
}
.gallery img:nth-child(4) {
grid-area: 2/1/span 1/span 2;
clip-path: polygon(50% 0,100% 100%,0 100%);
}
.gallery img:nth-child(5) {
grid-area: span 1/span 2/-1/-1;
clip-path: polygon(50% 0,100% 100%,0 100%);
}
基于这个效果可以引出一个更为复杂的多图排版效果,此效果没有上面的对称效果,实现起来相对复杂一点。
但是核心的实现过程都是一样的,可以将整体按以下网格布局进行排列,有兴趣的同学可以自己实现看看。
我正在尝试设置一个puppet节点,但rubygems似乎不正常。如果我通过它自己的二进制文件(/usr/lib/ruby/gems/1.8/gems/facter-1.5.8/bin/facter)在cli上运行facter,它工作正常,但如果我通过由rubygems(/usr/bin/facter)安装的二进制文件,它抛出:/usr/lib/ruby/1.8/facter/uptime.rb:11:undefinedmethod`get_uptime'forFacter::Util::Uptime:Module(NoMethodError)from/usr/lib/ruby
我在MiniTest::Spec和Capybara中使用以下规范:find_field('Email').must_have_css('[autofocus]')检查名为“电子邮件”的字段是否具有autofocus属性。doc说如下:has_css?(path,options={})ChecksifagivenCSSselectorisonthepageorcurrentnode.据我了解,字段“Email”是一个节点,因此调用must_have_css绝对有效!我做错了什么? 最佳答案 通过JonasNicklas得到了答案:No
我在我的项目中添加了一个系统来重置用户密码并通过电子邮件将密码发送给他,以防他忘记密码。昨天它运行良好(当我实现它时)。当我今天尝试启动服务器时,出现以下错误。=>BootingWEBrick=>Rails3.2.1applicationstartingindevelopmentonhttp://0.0.0.0:3000=>Callwith-dtodetach=>Ctrl-CtoshutdownserverExiting/Users/vinayshenoy/.rvm/gems/ruby-1.9.3-p0/gems/actionmailer-3.2.1/lib/action_mailer
我想向我的Controller传递一个参数,它是一个简单的复选框,但我不知道如何在模型的form_for中引入它,这是我的观点:{:id=>'go_finance'}do|f|%>Transferirde:para:Entrada:"input",:placeholder=>"Quantofoiganho?"%>Saída:"output",:placeholder=>"Quantofoigasto?"%>Nota:我想做一个额外的复选框,但我该怎么做,模型中没有一个对象,而是一个要检查的对象,以便在Controller中创建一个ifelse,如果没有检查,请帮助我,非常感谢,谢谢
我已经从我的命令行中获得了一切,所以我可以运行rubymyfile并且它可以正常工作。但是当我尝试从sublime中运行它时,我得到了undefinedmethod`require_relative'formain:Object有人知道我的sublime设置中缺少什么吗?我正在使用OSX并安装了rvm。 最佳答案 或者,您可以只使用“require”,它应该可以正常工作。我认为“require_relative”仅适用于ruby1.9+ 关于ruby-主要:Objectwhenrun
我有一些代码在几个不同的位置之一运行:作为具有调试输出的命令行工具,作为不接受任何输出的更大程序的一部分,以及在Rails环境中。有时我需要根据代码的位置对代码进行细微的更改,我意识到以下样式似乎可行:print"Testingnestedfunctionsdefined\n"CLI=trueifCLIdeftest_printprint"CommandLineVersion\n"endelsedeftest_printprint"ReleaseVersion\n"endendtest_print()这导致:TestingnestedfunctionsdefinedCommandLin
我有一个只接受一个参数的方法:defmy_method(number)end如果使用number调用方法,我该如何引发错误??通常,我如何定义方法参数的条件?比如我想在调用的时候报错:my_method(1) 最佳答案 您可以添加guard在函数的开头,如果参数无效则引发异常。例如:defmy_method(number)failArgumentError,"Inputshouldbegreaterthanorequalto2"ifnumbereputse.messageend#=>Inputshouldbegreaterthano
我使用Ember作为我的前端和GrapeAPI来为我的API提供服务。前端发送类似:{"service"=>{"name"=>"Name","duration"=>"30","user"=>nil,"organization"=>"org","category"=>nil,"description"=>"description","disabled"=>true,"color"=>nil,"availabilities"=>[{"day"=>"Saturday","enabled"=>false,"timeSlots"=>[{"startAt"=>"09:00AM","endAt"=>
我想获取模块中定义的所有常量的值:moduleLettersA='apple'.freezeB='boy'.freezeendconstants给了我常量的名字:Letters.constants(false)#=>[:A,:B]如何获取它们的值的数组,即["apple","boy"]? 最佳答案 为了做到这一点,请使用mapLetters.constants(false).map&Letters.method(:const_get)这将返回["a","b"]第二种方式:Letters.constants(false).map{|c
我正在阅读一本关于Ruby的书,作者在编写类初始化定义时使用的形式与他在本书前几节中使用的形式略有不同。它看起来像这样:classTicketattr_accessor:venue,:datedefinitialize(venue,date)self.venue=venueself.date=dateendend在本书的前几节中,它的定义如下:classTicketattr_accessor:venue,:datedefinitialize(venue,date)@venue=venue@date=dateendend在第一个示例中使用setter方法与在第二个示例中使用实例变量之间是