предисловие
Первый портал:кликните сюда
На самом деле, большая часть умений уже была описана в первой части, эта статья является дополнительной.
3D куб
Как создать трехмерные квадраты в CSS? Просто используйте следующий миксин SCSS
Длину, высоту и глубину блока можно свободно регулировать с помощью переменных CSS.
@mixin cube($width, $height, $depth) {
&__front {
@include cube-front($width, $height, $depth);
}
&__back {
@include cube-back($width, $height, $depth);
}
&__right {
@include cube-right($width, $height, $depth);
}
&__left {
@include cube-left($width, $height, $depth);
}
&__top {
@include cube-top($width, $height, $depth);
}
&__bottom {
@include cube-bottom($width, $height, $depth);
}
.face {
position: absolute;
}
}
@mixin cube-front($width, $height, $depth) {
width: var($width);
height: var($height);
transform-origin: bottom left;
transform: rotateX(-90deg) translateZ(calc(calc(var(#{$depth}) * 2) - var(#{$height})));
}
@mixin cube-back($width, $height, $depth) {
width: var($width);
height: var($height);
transform-origin: top left;
transform: rotateX(-90deg) rotateY(180deg) translateX(calc(var(#{$width}) * -1)) translateY(
calc(var(#{$height}) * -1)
);
}
@mixin cube-right($width, $height, $depth) {
width: calc(var(#{$depth}) * 2);
height: var($height);
transform-origin: top left;
transform: rotateY(90deg) rotateZ(-90deg) translateZ(var(#{$width})) translateX(calc(var(#{$depth}) * -2)) translateY(calc(var(
#{$height}
) * -1));
}
@mixin cube-left($width, $height, $depth) {
width: calc(var(#{$depth}) * 2);
height: var($height);
transform-origin: top left;
transform: rotateY(-90deg) rotateZ(90deg) translateY(calc(var(#{$height}) * -1));
}
@mixin cube-top($width, $height, $depth) {
width: var($width);
height: calc(var(#{$depth}) * 2);
transform-origin: top left;
transform: translateZ(var($height));
}
@mixin cube-bottom($width, $height, $depth) {
width: var($width);
height: calc(var(#{$depth}) * 2);
transform-origin: top left;
transform: rotateY(180deg) translateX(calc(var(#{$width}) * -1));
}
.cube {
--cube-width: 3rem;
--cube-height: 3rem;
--cube-depth: 1.5rem;
@include cube(--cube-width, --cube-height, --cube-depth);
width: 3rem;
height: 3rem;
}
шахматное вращение
Box Applications к нескольким пораженным анимации будут иметь следующие эффекты
.spiral-tower {
display: grid;
grid-auto-flow: row;
transform: rotateX(-30deg) rotateY(45deg);
.cube {
@for $i from 1 through 48 {
&:nth-child(#{$i}) {
animation-delay: 0.015s * ($i - 1);
}
}
}
}
@keyframes spin {
0%,
15% {
transform: rotateY(0);
}
85%,
100% {
transform: rotateY(1turn);
}
}
Этот демонстрационный адрес:Spiral Tower
Телескопическая длина
В CSS-анимации мы не можем напрямую анимировать переменную (на самом деле она анимирована, но жестковата).
На данный момент мы должны прибегнуть к CSS Houdini и объявить переменную как тип единицы длины, потому что единицу длины можно перемещать.
CSS.registerProperty({
name: "--cube-width",
syntax: "<length>",
initialValue: 0,
inherits: true,
});
CSS.registerProperty({
name: "--cube-height",
syntax: "<length>",
initialValue: 0,
inherits: true,
});
CSS.registerProperty({
name: "--cube-depth",
syntax: "<length>",
initialValue: 0,
inherits: true,
});
Этот демонстрационный адрес:3D Stair Loading
сегментация текста
В последнем мы упомянули, как использовать JS для разделения текста здесь, это представит более компактную реализацию --gsap плагина SplitText, используя его, мы можем использовать меньше кода для достижения эффекта следующей диаграммы.
<div class="staggered-land-in font-bold text-2xl">Fushigi no Monogatari</div>
const t1 = gsap.timeline();
const staggeredLandInText = new SplitText(".staggered-land-in", {
type: "chars",
});
t1.from(staggeredLandInText.chars, {
duration: 0.8,
opacity: 0,
y: "-20%",
stagger: 0.05,
});
Упрощенный демонстрационный адрес:SplitText Starter
Ключевой кадр
Простую анимацию можно получить, но как насчет относительно сложной анимации? В настоящее время вам все еще приходится полагаться на мощные @keyframes и переменные CSS.
Примечание. Хотя в настоящее время gsap поддерживает ключевые кадры, его нельзя комбинировать с чересстрочной анимацией, поэтому в качестве альтернативы используйте @keyframes.
<div class="staggered-scale-in font-bold text-6xl">Never Never Give Up</div>
.scale-in-bounce {
animation: scale-in-bounce 0.4s both;
animation-delay: calc(0.1s * var(--i));
}
@keyframes scale-in-bounce {
0% {
opacity: 0;
transform: scale(2);
}
40% {
opacity: 1;
transform: scale(0.8);
}
100% {
opacity: 1;
transform: scale(1);
}
}
const t1 = gsap.timeline();
const staggeredScaleInText = new SplitText(".staggered-scale-in", {
type: "chars",
});
const staggeredScaleInChars = staggeredScaleInText.chars;
staggeredScaleInChars.forEach((item, i) => {
item.style.setProperty("--i", `${i}`);
});
t1.to(staggeredScaleInChars, {
className: "scale-in-bounce",
});
Этот демонстрационный адрес:Staggered Scale In Text
SVG-фильтры
Фильтры CSS на самом деле являются инкапсулированными версиями фильтров SVG, которые нам удобно использовать.
Фильтры SVG более гибкие и мощные. Ниже приведены несколько распространенных сценариев использования фильтров.
Прикрепленный веб-сайт для отладки фильтров SVG онлайн:SVG Filters
липкий эффект
<svg width="0" height="0" class="absolute">
<filter id="goo">
<feGaussianBlur stdDeviation="10 10" in="SourceGraphic" result="blur" />
<feColorMatrix
type="matrix"
values="1 0 0 0 0
0 1 0 0 0
0 0 1 0 0
0 0 0 18 -7"
in="blur"
result="colormatrix"
/>
<feComposite in="SourceGraphic" in2="colormatrix" operator="over" result="composite" />
</filter>
</svg>
.gooey {
filter: url("#goo");
}
Этот демонстрационный адрес:SVG Filter Gooey Menu
эффект глюка
<svg width="0" height="0" class="absolute">
<filter id="glitch">
<feTurbulence type="fractalNoise" baseFrequency="0.00001 0.000001" numOctaves="1" result="turbulence1">
<animate
attributeName="baseFrequency"
from="0.00001 0.000001"
to="0.00001 0.4"
dur="0.4s"
id="glitch1"
fill="freeze"
repeatCount="indefinite"
></animate>
<animate
attributeName="baseFrequency"
from="0.00001 0.4"
to="0.00001 0.2"
dur="0.2s"
begin="glitch1.end"
fill="freeze"
repeatCount="indefinite"
></animate>
</feTurbulence>
<feDisplacementMap
in="SourceGraphic"
in2="turbulence1"
scale="30"
xChannelSelector="R"
yChannelSelector="G"
result="displacementMap"
/>
</filter>
</svg>
.glitch {
filter: url("#glitch");
}
Этот демонстрационный адрес:SVG Filter Glitch Button
Размытость
Размытие фильтра CSS является всенаправленным размытием, в то время как размытие фильтра SVG может управлять размытием в одном направлении.
<svg width="0" height="0" class="absolute">
<filter id="motion-blur" filterUnits="userSpaceOnUse">
<feGaussianBlur stdDeviation="100 0" in="SourceGraphic" result="blur">
<animate dur="0.6s" attributeName="stdDeviation" from="100 0" to="0 0" fill="freeze"></animate>
</feGaussianBlur>
</filter>
</svg>
.motion-blur {
filter: url("#motion-blur");
}
Этот демонстрационный адрес:SVG Filter Motion Blur
маска маска
Иногда мы хотим создать переходный полупрозрачный эффект, как на изображении ниже.
В это время вы должны использовать атрибут маски, потому что перекрывающаяся часть прозрачного градиента, созданного изображением и маской, станет прозрачной.
.divider-grad-mask {
background: linear-gradient(90deg, var(--blue-color) 0 50%, transparent 0 100%) 0 0 / 2rem 1rem;
mask: linear-gradient(-90deg, black, transparent);
}
демонстрационный адрес:Gradient Mask Divider
Комбинирование с clip-path также будет довольно интересным, как показано на рисунке ниже для загрузки эффектов.
демонстрационный адрес:Mask Loader
CSS-переменные
отслеживание мыши
В последней статье упоминалось об использовании API веб-анимации для достижения эффекта отслеживания наведения мыши, но на самом деле переменные CSS также могут быть достигнуты, и это более лаконично и эффективно.
Определите переменные x и y в CSS, затем прослушивайте события движения мыши в JS и получайте координаты мыши, а также обновляйте соответствующие переменные x и y.
:root {
--mouse-x: 0;
--mouse-y: 0;
}
.target {
transform: translate(var(--mouse-x), var(--mouse-y));
}
let mouseX = 0;
let mouseY = 0;
let x = 0;
let y = 0;
let offset = 50; // center
let windowWidth = window.innerWidth;
let windowHeight = window.innerHeight;
const percentage = (value, total) => (value / total) * 100;
window.addEventListener("mousemove", (e) => {
mouseX = e.clientX;
mouseY = e.clientY;
x = percentage(mouseX, windowWidth) - offset;
y = percentage(mouseY, windowHeight) - offset;
document.documentElement.style.setProperty("--mouse-x", `${x}%`);
document.documentElement.style.setProperty("--mouse-y", `${y}%`);
});
window.addEventListener("resize", () => {
windowWidth = window.innerWidth;
windowHeight = window.innerHeight;
});
Адрес сокращенной версии:Mousemove Starter
эффект остаточного изображения
Если вы объедините отслеживание мыши с поэтапной анимацией, добавите небольшой фильтр размытия, вы можете создать красивый эффект остаточного изображения.
Этот демонстрационный адрес:Motion Table - Delay
сегментация изображения
Для того, чтобы сделать анимацию, связанную с движением фрагментов картинки, или пазл, нам нужно разделить картинку, при этом по желанию можно управлять количеством блоков, размером и т. д. В это время могут прийти переменные CSS в игру.
.puzzle {
--puzzle-width: 16rem;
--puzzle-height: 24rem;
--puzzle-row: 3;
--puzzle-col: 4;
--puzzle-gap: 1px;
--puzzle-frag-width: calc(var(--puzzle-width) / var(--puzzle-col));
--puzzle-frag-height: calc(var(--puzzle-height) / var(--puzzle-row));
--puzzle-img: url(...);
display: flex;
flex-wrap: wrap;
width: calc(var(--puzzle-width) + calc(var(--puzzle-col) * var(--puzzle-gap) * 2));
height: calc(var(--puzzle-height) + calc(var(--puzzle-row) * var(--puzzle-gap) * 2));
.fragment {
--x-offset: calc(var(--x) * var(--puzzle-frag-width) * -1);
--y-offset: calc(var(--y) * var(--puzzle-frag-height) * -1);
width: var(--puzzle-frag-width);
height: var(--puzzle-frag-height);
margin: var(--puzzle-gap);
background: var(--puzzle-img) var(--x-offset) var(--y-offset) / var(--puzzle-width) var(--puzzle-height) no-repeat;
}
}
- Установите разделенные строки и столбцы и динамически рассчитайте размер фрагментов в соответствии со строками и столбцами.
- Общая ширина пазла|высота=ширина пазла|высота+столбцы|строки * пробел * 2
- При отображении среза используется смещение фона по оси xy. Смещение рассчитывается как: координата x|y * ширина среза | высота * -1.
В JS установите значение переменной и динамически сгенерируйте координаты xy среза, чтобы завершить сегментацию изображения.
class Puzzle {
constructor(el, width = 16, height = 24, row = 3, col = 3, gap = 1) {
this.el = el;
this.fragments = el.children;
this.width = width;
this.height = height;
this.row = row;
this.col = col;
this.gap = gap;
}
create() {
this.ids = [...Array(this.row * this.col).keys()];
const puzzle = this.el;
const fragments = this.fragments;
if (fragments.length) {
Array.from(fragments).forEach((item) => item.remove());
}
puzzle.style.setProperty("--puzzle-width", this.width + "rem");
puzzle.style.setProperty("--puzzle-height", this.height + "rem");
puzzle.style.setProperty("--puzzle-row", this.row);
puzzle.style.setProperty("--puzzle-col", this.col);
puzzle.style.setProperty("--puzzle-gap", this.gap + "px");
for (let i = 0; i < this.row; i++) {
for (let j = 0; j < this.col; j++) {
const fragment = document.createElement("div");
fragment.className = "fragment";
fragment.style.setProperty("--x", j);
fragment.style.setProperty("--y", i);
fragment.style.setProperty("--i", j + i * this.col);
puzzle.appendChild(fragment);
}
}
}
}
const puzzle = new Puzzle(document.querySelector(".puzzle"));
Этот демонстрационный адрес:Split Image With CSS Variable
сложная анимация
Дело 1
Этот демонстрационный адрес:Elastic Love
Случай 2
Этот демонстрационный адрес:Infinite Line Animation
Случай 3
Этот демонстрационный адрес:Orbit Reverse
Случай 4
Этот демонстрационный адрес:Motion Table - Solid Rotation
Случай 5
Этот демонстрационный адрес:Motion Table - Symmetric Move
резюме
Вышеуказанные сложные анимации имеют более или менее следующие характеристики:
-
div
Много, очень требовательная компоновка -
@keyframes
Много, очень требовательна к анимации - Некоторые анимации имеют больше 3D-преобразований.
Учебное пособие для случая 5 было написано в предыдущем сообщении в блоге.История рисования — красота CSS-анимации», другие случаи также могут быть изучены методами, упомянутыми в этой статье.
Все авторские CSS-анимационные работы размещены в этой подборке:CSS Animation Collection
пасхальные яйца
Анимация винтовой лестницы (вдохновленная серым фруктом OP)
Этот демонстрационный адрес:Spiral Stair Loading