花式图像装饰:单元素魔法柏拉图区块链数据智能。 垂直搜索。 哎。

花式图像装饰:单元素魔法

正如标题所说,我们要装饰图像! 那里还有很多其他文章讨论了这个问题,但我们在这里介绍的内容有很大不同,因为它更具挑战性。 挑战? 仅使用 标签,仅此而已。

没错,没有额外的标记,没有 div,也没有伪元素。 只有一个标签。

听起来很难,对吧? 但在本文的结尾——以及组成这个小系列的其他文章——我将证明 CSS 足够强大,可以为我们提供出色而令人惊叹的结果,尽管存在使用单个元素的限制。

花式形象装饰品系列

  • 单元素魔法—— 你在这里
  • 蒙版和高级悬停效果 (即将于 21 月 XNUMX 日 )
  • 轮廓和复杂动画 (即将于 28 月 XNUMX 日 )

让我们从我们的第一个例子开始

在深入研究代码之前,让我们列举一下样式的可能性 没有任何额外的元素或伪元素。 我们可以用 border, box-shadow, outline当然,并且, background. 为图像添加背景可能看起来很奇怪,因为我们看不到它,因为它会在图像后面——但诀窍是创造空间 围绕 图像使用 paddingborder 然后在该空间内绘制我们的背景。

我想你知道接下来会发生什么,因为我谈到了 background, 正确的? 是的, 渐变! 我们要制作的所有装饰都依赖于很多渐变。 如果你有 跟着我 有一段时间,我认为这对你来说可能一点也不奇怪。 😁

让我们回到我们的第一个例子:

img {
  --s: 10px; /* control the size */
  padding: var(--s);
  border: calc(2 * var(--s)) solid #0000;
  outline: 1px solid #000;
  outline-offset: calc(-1 * var(--s));
  background: conic-gradient(from 90deg at 1px 1px, #0000 25%, #000 0);
}

我们正在定义 padding 和一个透明的 border 使用变量 --s 在我们的图像周围创建一个等于该变量三倍的空间。

为什么我们同时使用 paddingborder 而不是其中一个? 我们可以只使用其中一个,但我的渐变需要这种组合,因为默认情况下,初始值 background-clip is border-boxbackground-origin 等于 padding-box.

这是理解逻辑的分步说明:

最初,我们在图像上没有任何边框,因此我们的渐变将创建两个分段 1px 的厚度。 (我在用 3px 在这个特定的演示中,所以更容易看到。)我们添加了一个彩色边框,渐变在填充区域内仍然给我们相同的结果(由于 background-origin) 但它在边界后面重复。 如果我们让边框的颜色透明,我们可以使用重复,我们得到我们想要的框架。

outline 在演示中有一个负偏移量。 这会在渐变的顶部创建一个正方形。 而已! 我们使用一个渐变和一个 outline. 我们可以使用更多的渐变! 但我总是尽量让我的代码尽可能简单,我发现添加一个 outline 那样更好。

这是我仅使用的仅渐变解决方案 padding 来定义空间。 仍然是相同的结果,但语法更复杂。

让我们尝试另一个想法:

对于这个,我把前面的例子去掉了 outline,并应用了一个 clip-path 切割每一侧的渐变。 这 clip-path value 有点冗长且令人困惑,但这里有一个插图可以更好地了解其要点:

花式图像装饰:单元素魔法

我想你明白了主要的想法。 我们将结合背景、轮廓、剪裁和一些蒙版来实现不同类型的装饰。 我们还将考虑一些很酷的悬停动画作为额外的奖励! 到目前为止,我们所看到的只是对即将发生的事情的一个小概述!

仅角落框架

这个需要四个渐变。 每个渐变覆盖一个角,在悬停时,我们扩展它们以在图像周围创建一个完整的框架。 让我们剖析其中一种渐变的代码:

--b: 5px; /* border thickness */
background: conic-gradient(from 90deg at top var(--b) left var(--b), #0000 90deg, darkblue 0) 0 0;
background-size: 50px 50px; 
background-repeat: no-repeat;

我们将绘制一个大小等于 50px 50px 并将其放在左上角(0 0)。 对于渐变的配置,这里有一个分步说明,展示了我是如何达到这个结果的。

我们倾向于认为渐变只适用于两种颜色之间的过渡。 但实际上,我们可以用它们做更多的事情! 在创建不同的形状时,它们特别有用。 诀窍是确保我们在颜色之间有硬停——就像上面的例子一样——而不是平滑过渡:

#0000 25%, darkblue 0

这基本上是在说:“用透明颜色填充渐变,直到 25% 的区域,然后填充剩余的区域 darkblue.

你可能正在为这个问题挠头 0 价值。 简化语法是一个小技巧。 实际上,我们应该使用它在颜色之间进行硬停止:

#0000 25%, darkblue 25%

这更符合逻辑! 透明色结束于 25%darkblue 从透明度结束的地方开始,硬停止。 如果我们将第二个替换为 0,浏览器将为我们完成这项工作,因此这是一种更有效的方式。

在某处 规范, 它说:

如果一个 颜色停止 or 过渡提示 具有小于列表中任何颜色停止或过渡提示的指定位置的位置,将其位置设置为等于其之前任何颜色停止或过渡提示的最大指定位置。

0 总是小于任何其他值,因此浏览器总是将其转换为声明中它之前的最大值。 在我们的例子中,这个数字是 25%.

现在,我们将相同的逻辑应用于所有角落,并以以下代码结束:

img {
  --b: 5px; /* border thickness */
  --c: #0000 90deg, darkblue 0; /* define the color here */
  padding: 10px;
  background:
    conic-gradient(from 90deg  at top    var(--b) left  var(--b), var(--c)) 0 0,
    conic-gradient(from 180deg at top    var(--b) right var(--b), var(--c)) 100% 0,
    conic-gradient(from 0deg   at bottom var(--b) left  var(--b), var(--c)) 0 100%,
    conic-gradient(from -90deg at bottom var(--b) right var(--b), var(--c)) 100% 100%;
  background-size: 50px 50px; /* adjust border length here */
  background-repeat: no-repeat;
}

我引入了 CSS 变量以避免一些冗余,因为所有渐变都使用相同的颜色配置。

对于悬停效果,我所做的只是增加渐变的大小以创建全帧:

img:hover {
  background-size: 51% 51%;
}

是的,它就是 51% 而不是 50% - 这会产生小的重叠并避免可能的间隙。

让我们使用相同的技术尝试另一个想法:

这次我们只使用了两个渐变,但动画更复杂。 首先,我们更新每个渐变的位置,然后增加它们的大小以创建完整的帧。 我还引入了更多变量,以便更好地控制颜色、大小、厚度,甚至图像和框架之间的间隙。

img {
  --b: 8px;  /* border thickness*/
  --s: 60px; /* size of the corner*/
  --g: 14px; /* the gap*/
  --c: #EDC951; 

  padding: calc(var(--b) + var(--g));
  background-image:
    conic-gradient(from  90deg at top    var(--b) left  var(--b), #0000 25%, var(--c) 0),
    conic-gradient(from -90deg at bottom var(--b) right var(--b), #0000 25%, var(--c) 0);
  background-position:
    var(--_p, 0%) var(--_p, 0%),
    calc(100% - var(--_p, 0%)) calc(100% - var(--_p, 0%));
  background-size: var(--s) var(--s);
  background-repeat: no-repeat;
  transition: 
    background-position .3s var(--_i,.3s), 
    background-size .3s calc(.3s - var(--_i, .3s));
}
img:hover {
  background-size: calc(100% - var(--g)) calc(100% - var(--g));
  --_p: calc(var(--g) / 2);
  --_i: 0s;
}

为什么这样做 --_i--_p 变量名称中有下划线? 下划线是我用来考虑用于优化代码的“内部”变量的命名约定的一部分。 它们没什么特别的,但我想在我们调整以控制框架的变量之间有所不同(比如 --b, --c等)以及我用来缩短代码的那些。

代码可能看起来令人困惑且不容易掌握,但我写了一个 三部分系列 我详细介绍了这种技术。 我强烈建议至少阅读第一篇文章以了解我是如何获得上述代码的。

这是一个插图,可以更好地理解不同的值:

将两辆老爷车的同一张图片展示三遍,以说明代码中使用的 CSS 变量。
花式图像装饰:单元素魔法

框架显示

让我们尝试另一种类型的动画,我们在悬停时显示全帧:

酷,对吧? 如果你仔细观察,你会发现鼠标移开时线条在相反的方向消失,这使得效果更加奇特! 我使用了类似的效果 以前的文章.

但是这一次,我没有覆盖所有元素,而是通过定义一个 height 得到这样的东西:

这是我们框架的顶部边框。 我们在图像的每一侧重复相同的过程,我们就有了悬停效果:

img {
  --b: 10px; /* the border thickness*/
  --g: 5px; /* the gap on hover */
  --c: #8A9B0F; 

  padding: calc(var(--g) + var(--b));
  --_g: no-repeat linear-gradient(var(--c) 0 0);
  background: 
    var(--_g) var(--_i, 0%) 0,
    var(--_g) 100% var(--_i, 0%),
    var(--_g) calc(100% - var(--_i, 0%)) 100%,
    var(--_g) 0 calc(100% - var(--_i, 0%));
  background-size: var(--_i, 0%) var(--b),var(--b) var(--_i, 0%);
  transition: .4s, background-position 0s;
  cursor: pointer;
}
img:hover {
  --_i: 100%;
}

正如你所看到的,我四次应用相同的渐变,每次都具有不同的位置,一次只覆盖一侧。

另一个? 我们走吧!

这个看起来有点棘手,它确实需要一些想象力才能理解两个圆锥梯度是如何发挥这种魔力的。 这是一个演示来说明其中一个渐变:

伪元素模拟渐变。 它最初是看不见的,在悬停时,我们首先改变它的位置以获得框架的顶部边缘。 然后我们增加高度以获得正确的边缘。 渐变形状类似于我们在上一节中使用的形状:两段覆盖两侧。

但是为什么我要设置渐变的宽度 200%? 你会认为 100% 就够了,对吧?

100% 应该足够了,但如果我保持它的宽度等于,我将无法像我想要的那样移动渐变 100%. 这是另一个与如何相关的小怪癖 background-position 作品。 我涵盖了这个 以前的文章。 我也 在 Stack Overflow 上发布了答案 处理这个。 我知道阅读量很大,但这真的值得你花时间。

既然我们已经解释了一个渐变的逻辑,第二个就很简单了,因为它做的完全一样,只是覆盖了左边缘和下边缘。 我们所要做的就是交换一些值,我们就完成了:

img {
  --c: #8A9B0F; /* the border color */
  --b: 10px; /* the border thickness*/
  --g: 5px;  /* the gap */

  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;
}

如您所见,两个渐变几乎相同。 我只是交换大小和位置的值。

框架旋转

这次我们不会在图像周围画一个框架,而是调整现有图像的外观。

你可能会问我怎么能把一条直线变成一条斜线。 不,魔法与此不同。 这只是我们在为四个渐变组合简单动画后得到的错觉。

让我们看看顶部渐变的动画是如何制作的:

我只是在更新重复渐变的位置。 还没有什么花哨的! 让我们对右侧做同样的事情:

你开始看到诀​​窍了吗? 两个渐变在拐角处相交以产生直线变为有角度的错觉。 让我们删除轮廓并隐藏溢出以更好地查看它:

现在,我们再添加两个渐变来覆盖剩余的边缘,我们就完成了:

img {
  --g: 4px; /* the gap */
  --b: 12px; /* border thickness*/
  --c: #669706; /* the color */

  padding: calc(var(--g) + var(--b));
  --_c: #0000 0 25%, var(--c) 0 50%;
  --_g1: repeating-linear-gradient(90deg ,var(--_c)) repeat-x;
  --_g2: repeating-linear-gradient(180deg,var(--_c)) repeat-y;
  background:
    var(--_g1) var(--_p, 25%) 0, 
    var(--_g2) 0 var(--_p, 125%),
    var(--_g1) var(--_p, 125%) 100%, 
    var(--_g2) 100% var(--_p, 25%);
  background-size: 200% var(--b), var(--b) 200%;
  transition: .3s;
}
img:hover {
  --_p: 75%;
}

如果我们把这段代码稍微调整一下,我们可以得到另一个很酷的动画:

你能弄清楚这个例子中的逻辑吗? 那是你的功课! 该代码可能看起来很吓人,但它使用与我们之前看到的示例相同的逻辑。 尝试隔离每个渐变并想象它的动画效果。

结束了

一篇文章中有很多渐变!

肯定是的,我警告过你! 但是,如果挑战是在没有额外元素和伪元素的情况下装饰图像,那么我们只剩下几种可能性,而渐变是最强大的选择。

如果您在某些解释中迷失了方向,请不要担心。 我总是推荐我的一些旧文章,其中我更详细地介绍了我们为这一挑战回收的一些概念。

我将留下最后一个演示,让您等待本系列的下一篇文章。 这一次,我使用 radial-gradient() 创建另一个有趣的悬停效果。 我会让你剖析代码以了解它是如何工作的。 如果您遇到困难,请在评论中向我提问!

花式形象装饰品系列

  • 单元素魔法—— 你在这里
  • 蒙版和高级悬停效果 (即将于 21 月 XNUMX 日 )
  • 轮廓和复杂动画 (即将于 28 月 XNUMX 日 )

时间戳记:

更多来自 CSS技巧