欢迎来到这个三部分系列的第二部分!我们仍在装饰图像,而无需任何额外的元素和伪元素。我希望您已经花时间消化了 第一部分,因为我们将继续使用大量渐变来创建很棒的视觉效果。我们还将介绍 CSS mask
属性以实现更复杂的装饰和悬停效果。
让我们转向我们一起处理的第一个示例……
邮票
信不信由你,制作邮票 CSS 效果只需要两个渐变和一个滤镜
img {
--r: 10px; /* control the radius of the circles */
padding: calc(2 * var(--r));
filter: grayscale(.4);
background:
radial-gradient(var(--r),#0000 98%,#fff) round
calc(-1.5 * var(--r)) calc(-1.5 * var(--r)) / calc(3 * var(--r)) calc(3 * var(--r)),
linear-gradient(#fff 0 0) no-repeat
50% / calc(100% - 3 * var(--r)) calc(100% - 3 * var(--r));
}
正如我们在 上一篇文章 中看到的,第一步是使用 padding
在图像周围留出空间,以便我们绘制背景渐变并在那里看到它。然后,我们结合使用 radial-gradient()
和 linear-gradient()
来裁剪图像周围的圆圈。
这是一个逐步说明,展示了渐变是如何配置的
请注意第二步中使用了 round
值。这对于技巧来说非常重要,因为它确保渐变的大小调整为完美地对齐所有边,无论图像宽度或高度是多少。
来自 规范:图像会重复尽可能多地填充背景定位区域。如果它不能完全容纳整数次,则会重新缩放以使其能够容纳。
圆形边框
让我们看看另一个使用圆圈的图像装饰……
此示例也使用 radial-gradient()
,但这次我在图像周围创建了圆圈,而不是剪切效果。请注意,我再次使用了 round
值。这里最棘手的地方是边框和图像之间的透明间隙,这就是我使用 CSS mask
属性的地方
img {
--s: 20px; /* size of the frame */
--g: 10px; /* the gap */
--c: #FA6900;
padding: calc(var(--g) + var(--s));
background:
radial-gradient(farthest-side, var(--c) 97%, #0000)
0 0 / calc(2 * var(--s)) calc(2 * var(--s)) round;
mask:
conic-gradient(from 90deg at calc(2 * var(--s)) calc(2 * var(--s)), #0000 25%, #000 0)
calc(-1 * var(--s)) calc(-1 * var(--s)),
linear-gradient(#000 0 0) content-box;
}
蒙版允许我们显示图像的区域——这要归功于其中的 linear-gradient()
——以及它每一侧周围的 20px
——这要归功于 conic-gradient()
。20px
仅仅是定义边框大小的变量 --s
。换句话说,我们需要隐藏间隙。
我的意思是这个
线性渐变是背景的蓝色部分,而圆锥渐变是背景的红色部分。这两个渐变之间的透明部分就是我们从元素中裁剪的部分,以创造内部透明边框的错觉。
内部透明边框
对于这个,我们不会创建边框,而是尝试一些不同的东西。我们将尝试在图像内部创建透明的内部边框。在现实世界的场景中可能不是那么有用,但对于 CSS 蒙版来说是一个很好的练习。
与前面的示例类似,我们将依靠两个渐变:一个用于内部部分的 linear-gradient()
和一个用于外部部分的 conic-gradient()
。我们将在它们之间留出空间来创建透明边框效果。
img {
--b: 5px; /* the border thickness */
--d: 20px; /* the distance from the edge */
--_g: calc(100% - 2 * (var(--d) + var(--b)));
mask:
conic-gradient(from 90deg at var(--d) var(--d), #0000 25%, #000 0)
0 0 / calc(100% - var(--d)) calc(100% - var(--d)),
linear-gradient(#000 0 0) 50% / var(--_g) var(--_g) no-repeat;
}
您可能已经注意到,此示例的圆锥渐变与上一个示例的语法不同。两者都应该创建相同的形状,那么为什么它们会不同呢?这是因为我们可以使用不同的语法来达到相同的结果。这乍一看可能令人困惑,但这是一个很好的特性。您不必找到实现特定形状的唯一解决方案。您只需要从众多可能性中找到一个适合您的解决方案即可。
以下是使用渐变创建外部正方形的四种方法
还有更多方法可以实现这一点,但您明白了。
没有最好的™方法。就我个人而言,我尝试找到代码最短且最优化的那个。对我来说,任何需要更少渐变、更少计算和更少重复值的解决方案都是最合适的。有时我选择更冗长的语法,因为它给了我更多灵活性来更改变量和修改内容。这需要经验和实践。您玩得越多渐变,您就越了解何时使用哪种语法。
让我们回到我们的内部透明边框并深入研究悬停效果。如果您没有注意到,有一个很酷的悬停效果,它使用 font-size
技巧移动该透明边框。这个想法是使用 1em
的值定义 --d
变量。此变量控制边框距边缘的距离。我们可以像这样转换
--_d: calc(var(--d) + var(--s) * 1em)
…为我们提供以下更新的 CSS
img {
--b: 5px; /* the border thickness */
--d: 20px; /* the distance from the edge */
--o: 15px; /* the offset on hover */
--s: 1; /* the direction of the hover effect (+1 or -1)*/
--_d: calc(var(--d) + var(--s) * 1em);
--_g: calc(100% - 2 * (var(--_d) + var(--b)));
mask:
conic-gradient(from 90deg at var(--_d) var(--_d), #0000 25%, #000 0)
0 0 / calc(100% - var(--_d)) calc(100% - var(--_d)),
linear-gradient(#000 0 0) 50% / var(--_g) var(--_g) no-repeat;
font-size: 0;
transition: .35s;
}
img:hover {
font-size: var(--o);
}
font-size
最初等于 0
,因此 1em
也等于 0
,并且 --_d
等于 --d
。但是,在悬停时,font-size
等于由 --o
变量定义的值,该变量设置边框的偏移量。这反过来更新了 --_d
变量,通过偏移量移动边框。然后我添加另一个变量 --s
来控制决定边框向内还是向外移动的符号。
如果我们想要动画化原本无法动画化的属性,font-size
技巧确实很有用。使用 @property
定义的 自定义属性 可以解决此问题,但 对它的支持 在我撰写本文时仍然不足。
边框显示
我们在本系列的第一部分制作了以下显示动画
我们可以采用同样的想法,但不是使用具有纯色的边框,我们将使用这样的渐变
如果比较这两段代码,您会注意到以下更改
- 我在
mask
属性内使用了第一个示例中的相同渐变配置。我只是将渐变从background
属性移动到mask
属性。 - 我添加了一个
repeating-linear-gradient()
来创建渐变边框。
就是这样!我重新使用了我们已经看到的大部分相同代码——并进行了一些微小的调整——并获得了另一个带有悬停效果的酷炫图像装饰。
/* Solid color border */
img {
--c: #8A9B0F; /* the border color */
--b: 10px; /* the border thickness*/
--g: 5px; /* the gap on hover */
padding: calc(var(--g) + var(--b));
--_g: #0000 25%, var(--c) 0;
background:
conic-gradient(from 180deg at top var(--b) right var(--b), var(--_g))
var(--_i, 200%) 0 / 200% var(--_i, var(--b)) no-repeat,
conic-gradient(at bottom var(--b) left var(--b), var(--_g))
0 var(--_i, 200%) / var(--_i, var(--b)) 200% no-repeat;
transition: .3s, background-position .3s .3s;
cursor: pointer;
}
img:hover {
--_i: 100%;
transition: .3s, background-size .3s .3s;
}
/* Gradient color border */
img {
--b: 10px; /* the border thickness*/
--g: 5px; /* the gap on hover */
background: repeating-linear-gradient(135deg, #F8CA00 0 10px, #E97F02 0 20px, #BD1550 0 30px);
padding: calc(var(--g) + var(--b));
--_g: #0000 25%, #000 0;
mask:
conic-gradient(from 180deg at top var(--b) right var(--b), var(--_g))
var(--_i, 200%) 0 / 200% var(--_i, var(--b)) no-repeat,
conic-gradient(at bottom var(--b) left var(--b), var(--_g))
0 var(--_i, 200%) / var(--_i, var(--b)) 200% no-repeat,
linear-gradient(#000 0 0) content-box;
transition: .3s, mask-position .3s .3s;
cursor: pointer;
}
img:hover {
--_i: 100%;
transition: .3s, mask-size .3s .3s;
}
让我们尝试另一个边框动画。这个有点棘手,因为它有一个 三步动画
动画的第一步是使底部边缘更大。为此,我们调整 linear-gradient()
的 background-size
您可能想知道为什么我也要添加顶部边缘。我们需要它用于第三步。我始终尝试优化我编写的代码,因此我使用一个渐变来覆盖顶部和底部两侧,但顶部渐变被隐藏并在稍后使用 mask
显示。
对于第二步,我们添加第二个渐变以显示左右边缘。但这次,我们使用 background-position
来实现。
我们可以在这里停止,因为我们已经有了两个渐变的不错效果,但我们在这里是为了突破极限,所以让我们添加一点蒙版来实现第三步。
诀窍是在显示底部和侧面之前隐藏顶部边缘,然后我们更新 mask-size
(或 mask-position
)以显示顶部部分。正如我之前所说,我们可以找到很多渐变配置来实现相同的效果。
这是我将要使用的渐变的插图
我正在使用两个圆锥渐变,宽度等于 200%
。这两个渐变覆盖了该区域,只留下顶部部分未被覆盖(该部分稍后将不可见)。在悬停时,我滑动这两个渐变以覆盖该部分。
以下是其中一个渐变的更好插图,让您更好地了解正在发生的事情
现在我们将它放在 mask
属性内,我们就完成了!这是完整的代码
img {
--b: 6px; /* the border thickness*/
--g: 10px; /* the gap */
--c: #0E8D94;
padding: calc(var(--b) + var(--g));
--_l: var(--c) var(--b), #0000 0 calc(100% - var(--b)), var(--c) 0;
background:
linear-gradient(var(--_l)) 50%/calc(100% - var(--_i,80%)) 100% no-repeat,
linear-gradient(90deg, var(--_l)) 50% var(--_i,-100%)/100% 200% no-repeat;
mask:
conic-gradient(at 50% var(--b),#0000 25%, #000 0) calc(50% + var(--_i, 50%)) / 200%,
conic-gradient(at 50% var(--b),#000 75%, #0000 0) calc(50% - var(--_i, 50%)) / 200%;
transition:
.3s calc(.6s - var(--_t,.6s)) mask-position,
.3s .3s background-position,
.3s var(--_t,.6s) background-size,
.4s transform;
cursor: pointer;
}
img:hover {
--_i: 0%;
--_t: 0s;
transform: scale(1.2);
}
我还引入了一些变量来优化代码,但您现在应该习惯了这一点。
四步动画怎么样?是的,这是可能的!
这部分没有解释,因为这是你的作业!请运用你在本文中学习到的所有知识来分析代码,并尝试阐述它的作用。其逻辑与之前的所有示例类似。关键是隔离每个渐变,以理解动画的每个步骤。为了方便阅读,我保留了未优化的代码。如果你有兴趣,我确实有一个优化版本,但你也可以尝试自己优化代码,并将其与我的版本进行比较,以获得额外的练习。
总结
这就是关于仅使用<img>
元素创建创意图像装饰的三部分系列的第二部分。我们现在对如何组合渐变和蒙版以创建令人惊叹的视觉效果,甚至动画有了很好的了解——无需使用额外的元素或伪元素。是的,一个<img>
标签就足够了!
在本系列中,我们还有一篇文章要发布。在此之前,这里有一个带有酷炫悬停效果的额外演示,我使用mask
来组合破碎的图像。
很棒的东西:) 特别是邮票和蒙版演示是一种有趣的艺术指导方向。