单元素装载机:走向 3D! PlatoBlockchain 数据智能。 垂直搜索。 哎。

单元素装载机:走向 3D!

对于我们的第四篇也是最后一篇文章 关于单元素装载机的小系列,我们将探索 3D 模式。 在创建 3D 元素时,很难想象仅一个 HTML 元素就足以模拟立方体的所有六个面。 但也许我们可以用更立方体的东西逃脱-喜欢 而不是只显示形状的前三个侧面——这是完全可能的,这就是我们要一起做的事情。

文章系列

拆分立方体加载器

这是一个 3D 加载器,其中一个立方体被分成两部分,但仅由一个元素组成:

CodePen 嵌入后备

立方体的每一半都是使用一个伪元素制作的:

单元素装载机:走向 3D! PlatoBlockchain 数据智能。 垂直搜索。 哎。
单元素装载机:走向 3D!

酷,对吧?! 我们可以在 CSS 中使用圆锥渐变 clip-path 在元素的 ::before::after pseudos 来模拟 3D 立方体的三个可见面。 负边距是将两个伪模型拉在一起以重叠并模拟一个完整的立方体。 我们剩下的工作主要是为这两部分设置动画,以获得看起来整洁的装载机!

让我们看看一个解释用于创建这个立方体元素的剪辑路径点背后的数学的视觉效果:

单元素装载机:走向 3D! PlatoBlockchain 数据智能。 垂直搜索。 哎。
单元素装载机:走向 3D!

我们有我们的变量和一个方程,所以让我们把它们付诸实践。 首先,我们将建立我们的变量并设置主要的尺寸 .loader 元件:

.loader { --s: 150px; /* control the size */ --_d: calc(0.353 * var(--s)); /* 0.353 = sin(45deg)/2 */ width: calc(var(--s) + var(--_d)); aspect-ratio: 1; display: flex;
}

到目前为止没有什么太疯狂了。 我们有一个 150px 设置为灵活容器的正方形。 现在我们建立我们的伪:

.loader::before,
.loader::after { content: ""; flex: 1;
}

那是两半 .loader 容器。 我们需要把它们画进去,所以这就是我们的 圆锥梯度 开始:

.loader::before,
.loader::after { content: ""; flex: 1; background: conic-gradient(from -90deg at calc(100% - var(--_d)) var(--_d), #fff 135deg, #666 0 270deg, #aaa 0);
}

渐变是存在的,但是 看起来很奇怪。 我们要 将其剪辑到元素:

.loader::before,
.loader::after { content: ""; flex: 1; background: conic-gradient(from -90deg at calc(100% - var(--_d)) var(--_d), #fff 135deg, #666 0 270deg, #aaa 0); clip-path: polygon(var(--_d) 0, 100% 0, 100% calc(100% - var(--_d)), calc(100% - var(--_d)) 100%, 0 100%, 0 var(--_d));
}

让我们确保两半重叠 负边际:

.loader::before { margin-right: calc(var(--_d) / -2);
} .loader::after { margin-left: calc(var(--_d) / -2);
}

现在让我们让他们动起来!

.loader::before,
.loader::after { /* same as before */ animation: load 1.5s infinite cubic-bezier(0, .5, .5, 1.8) alternate;
} .loader::after { /* same as before */ animation-delay: -.75s
} @keyframes load{ 0%, 40% { transform: translateY(calc(var(--s) / -4)) } 60%, 100% { transform: translateY(calc(var(--s) / 4)) }
}

这是最后的演示:

CodePen 嵌入后备

进度立方体加载器

让我们使用相同的技术来创建一个 3D 进度加载器。 是的,仍然只有一个元素!

CodePen 嵌入后备

除了改变装载机的高度和纵横比之外,我们并没有像以前一样模拟立方体。 我们正在制作的动画依赖于一种非常简单的技术,我们更新左侧的宽度,而右侧填充剩余空间,这要归功于 flex-grow: 1.

第一步是使用在右侧添加一些透明度 opacity:

CodePen 嵌入后备

这模拟了立方体的一侧被填充而另一侧为空的效果。 然后我们更新左侧的颜色。 为此,我们要么更新圆锥渐变内的三种颜色,要么通过添加带有 background-blend-mode:

.loader::before { background-color: #CC333F; /* control the color here */ background-blend-mode: multiply;
}

这个技巧只允许我们只更新一次颜色。 加载器的右侧与锥形渐变中的三种白色阴影混合,以创建我们颜色的三种新阴影,即使我们只使用一个颜色值。 颜色诡计!

CodePen 嵌入后备

让我们为加载器左侧的宽度设置动画:

CodePen 嵌入后备

哎呀,一开始的动画有点奇怪! 注意它是如何在立方体之外开始的? 这是因为我们在 0% 宽度。 但由于 clip-path 和我们正在使用的负边距,我们需要做的是从我们的 --_d 变量,我们用来定义 clip-path 点和负边距:

@keyframes load { 0%, 5% {width: var(--_d); } 95%, 100% {width: 100%; }
}

这有点好:

CodePen 嵌入后备

但是我们可以让这个动画更加流畅。 您是否注意到我们遗漏了一些东西? 让我向您展示一个屏幕截图,以比较最终演示与上一个演示的外观:

单元素装载机:走向 3D! PlatoBlockchain 数据智能。 垂直搜索。 哎。

这是立方体的底面! 由于第二个元素是透明的,我们需要看到该矩形的底面,如左侧示例中所示。 它很微妙,但应该在那里!

我们可以向主元素添加渐变并像使用伪元素一样对其进行剪辑:

background: linear-gradient(#fff1 0 0) bottom / 100% var(--_d) no-repeat;

将所有内容放在一起后,这是完整的代码:

.loader { --s: 100px; /* control the size */ --_d: calc(0.353*var(--s)); /* 0.353 = sin(45deg) / 2 */ height: var(--s); aspect-ratio: 3; display: flex; background: linear-gradient(#fff1 0 0) bottom / 100% var(--_d) no-repeat; clip-path: polygon(var(--_d) 0, 100% 0, 100% calc(100% - var(--_d)), calc(100% - var(--_d)) 100%, 0 100%, 0 var(--_d));
}
.loader::before,
.loader::after { content: ""; clip-path: inherit; background: conic-gradient(from -90deg at calc(100% - var(--_d)) var(--_d), #fff 135deg, #666 0 270deg, #aaa 0);
}
.loader::before { background-color: #CC333F; /* control the color here */ background-blend-mode: multiply; margin-right: calc(var(--_d) / -2); animation: load 2.5s infinite linear;
}
.loader:after { flex: 1; margin-left: calc(var(--_d) / -2); opacity: 0.4;
} @keyframes load { 0%, 5% { width: var(--_d); } 95%, 100% { width: 100%; }
}
CodePen 嵌入后备

而已! 我们只是使用了一种巧妙的技术,它使用伪元素、圆锥渐变、剪裁、背景混合和负边距来获得,不是一个,而是 外观精美的 3D 加载器,标记中只有一个元素。

更多 3D

我们仍然可以更进一步,使用一个元素模拟无限数量的 3D 立方体——是的,这是可能的! 这是一个立方体网格:

CodePen 嵌入后备

在撰写本文时,Safari 不支持此演示和以下演示。

疯了吧? 现在我们正在创建使用单个元素制作的重复立方体图案……而且也没有伪元素! 我不会详细介绍我们正在使用的数学(那里有非常具体的数字),但这里有一个图表来可视化我们是如何到达这里的:

单元素装载机:走向 3D! PlatoBlockchain 数据智能。 垂直搜索。 哎。
单元素装载机:走向 3D!

我们首先使用一个 conic-gradient 创建重复的立方体图案。 模式的重复由三个变量控制:

  • --size:名副其实,它控制每个立方体的大小。
  • --m:这表示列数。
  • --n: 这是行数。
  • --gap:这是立方体之间的间隙或距离
.cube { --size: 40px; --m: 4; --n: 5; --gap :10px; aspect-ratio: var(--m) / var(--n); width: calc(var(--m) * (1.353 * var(--size) + var(--gap))); background: conic-gradient(from -90deg at var(--size) calc(0.353 * var(--size)), #249FAB 135deg, #81C5A3 0 270deg, #26609D 0) /* update the colors here */ 0 0 / calc(100% / var(--m)) calc(100% / var(--n));
}

然后我们使用另一个具有相同大小的图案应用遮罩层。 这是这个想法中最棘手的部分。 使用一个组合 linear-gradient 的网络 conic-gradient 我们将切割元素的一些部分,以仅保持立方体形状可见。

.cube { /* etc. */ mask: linear-gradient(to bottom right, #0000 calc(0.25 * var(--size)), #000 0 calc(100% - calc(0.25 * var(--size)) - 1.414 * var(--gap)), #0000 0), conic-gradient(from -90deg at right var(--gap) bottom var(--gap), #000 90deg, #0000 0); mask-size: calc(100% / var(--m)) calc(100% / var(--n)); mask-composite: intersect;
}

代码可能看起来有点复杂,但由于 CSS 变量,我们需要做的就是更新一些值来控制我们的立方体矩阵。 需要 10⨉10 网格? 更新 --m--n 变量 10. 立方体之间需要更宽的间隙吗? 更新 --gap 价值。 颜色值只使用一次,所以更新那些新的调色板!

现在我们有了另一种 3D 技术,让我们通过玩不同的动画来使用它来构建加载器的变体。 例如,立方体从左到右无限滑动的重复模式怎么样?

CodePen 嵌入后备

这个加载器在一行中定义了四个立方体。 这意味着我们的 --n 价值是 4--m 等于 1 . 换句话说,我们不再需要这些!

相反,我们可以使用 --size--gap 网格容器中的变量:

.loader { --size: 70px; --gap: 15px; width: calc(3 * (1.353 * var(--size) + var(--gap))); display: grid; aspect-ratio: 3;
}

这是我们的容器。 我们有四个立方体,但一次只想在容器中显示三个,这样我们总是有一个滑入,一个滑出。 这就是为什么我们将宽度分解为 3 并将纵横比设置为 3 以及。

让我们确保我们的立方体图案设置为四个立方体的宽度。 我们将在容器上执行此操作 ::before 伪元素:

.loader::before { content: ""; width: calc(4 * 100% / 3); /* Code to create four cubes */
}

现在我们在一个三立方体容器中有四个立方体,我们可以将立方体图案对齐到网格容器的末端以使其溢出,显示最后三个立方体:

.loader { /* same as before */ justify-content: end;
}

到目前为止,这是我们所拥有的,用红色轮廓表示网格容器的边界:

CodePen 嵌入后备

现在我们要做的就是通过添加动画将伪元素向右移动:

@keyframes load { to { transform: translate(calc(100% / 4)); }
}
CodePen 嵌入后备

你掌握了动画的诀窍吗? 让我们通过隐藏溢出的立方体图案并添加一点遮罩来创建开始和结束的褪色效果来完成这个:

.loader { --size: 70px; --gap: 15px; width: calc(3*(1.353*var(--s) + var(--g))); display: grid; justify-items: end; aspect-ratio: 3; overflow: hidden; mask: linear-gradient(90deg, #0000, #000 30px calc(100% - 30px), #0000);
}
CodePen 嵌入后备

我们可以通过引入一个变量来使其更加灵活, --n, 设置一次在容器中显示多少个立方体。 而且由于模式中的立方体总数应该比 --n, 我们可以表示为 calc(var(--n) + 1).

这是完整的事情:

CodePen 嵌入后备

好的,还有一个类似的 3D 加载器,但立方体连续改变颜色而不是滑动:

CodePen 嵌入后备

我们将依赖动画背景 background-blend-mode 对于这个:

.loader { /* ... */ background: linear-gradient(#ff1818 0 0) 0% / calc(100% / 3) 100% no-repeat, /* ... */; background-blend-mode: multiply; /* ... */ animation: load steps(3) 1.5s infinite;
}
@keyframes load { to { background-position: 150%; }
}

我删除了用于创建与上一个示例相同的布局的多余代码,但使用三个立方体而不是四个。 我在这里添加的是一个用特定颜色定义的渐变,它与圆锥渐变混合,就像我们之前为进度条 3D 加载器所做的那样。

从那里开始,它正在为背景渐变设置动画 background-position 作为一个三步动画,使立方体一次闪烁一种颜色。

如果您不熟悉我使用的值 background-position 和背景语法,我强烈推荐 我以前的一篇文章 和一个 我的堆栈溢出答案. 你会在那里找到非常详细的解释。

我们可以更新立方体的数量以使其可变吗?

是的,我确实有一个 解决方案,但我希望您尝试一下,而不是将其嵌入此处。 借鉴我们从上一个示例中学到的知识,并尝试对这个示例做同样的事情——然后在评论中分享您的工作!

变化万千!

与本系列的其他三篇文章一样,我想给您一些启发,让您继续创建自己的加载器。 这是一个集合,其中包括我们一起制作的 3D 加载器,以及其他一些让您发挥想象力的东西:

CodePen 嵌入后备

这是一个包装

我当然希望你喜欢在过去的几周里花时间和我一起制作单元素加载器。 令人疯狂的是,我们从看似简单的微调器开始,然后逐渐添加新的部件,一直到 3D 技术,这些技术仍然只在标记中使用单个元素。 这正是我们利用 CSS 强大功能时的样子:可扩展、灵活和可重用。

再次感谢您阅读这个小系列! 我会通过提醒你我有一个 收集超过 500 台装载机 如果您正在寻找更多的想法和灵感。

文章系列


单元素装载机:走向 3D! 最初发表于 CSS技巧。 你应该 获取时事通讯.

时间戳记:

更多来自 CSS技巧