Давайте посмотрим, как получить положение мыши пользователя и отобразить его в настраиваемых свойствах CSS: - positionX
и - positionY
.
Мы могли бы сделать это с помощью JavaScript. Если бы мы это сделали, мы могли бы делать такие вещи, как сделать элемент перетаскиваемым или перемещать фон. Но на самом деле мы все еще можем делать то же самое, но не использовать JavaScript!
Я использовал этот метод как часть демонстрации, которую я сделал для получения эффекта «Щелкни и перетащи» с помощью чистого CSS. Я использовал советы перспективы
из моей предыдущей статьи. Это довольно изящный эффект — сделать это полностью на CSS, который может иметь более широкую пользу, чем моя демонстрация, так что давайте взглянем.
Содержание статьи
Установка
Наша первая демонстрация будет использовать настраиваемые свойства - positionX
и - positionY
для установки ширины
и высоты
элемент.
Внимание, здесь мы используем SCSS только для краткости, но все это можно сделать на чистом CSS.
Это наше исходное состояние. У нас есть «обертка»
.content
который распространяется на ширину и высоту корпуса. Этот
будет содержать содержимое нашего проекта и элементы, которыми мы хотим управлять с помощью позиции мыши — в данном случае элемент .square
.
Мы также добавили два настраиваемых свойства к содержимому
. мы будем использовать положение мыши, чтобы установить значения этих свойств, а затем с их помощью установить .square
элемент ширину
и высоту
соответственно.
После того, как мы сопоставили настраиваемые свойства для положения мыши, мы можем использовать их, чтобы делать практически все, что захотим. Например, мы могли бы использовать их, чтобы установить свойства top
/ left
для позиционированного элемента absolute
управлять свойством transform
установить background-position
управлять цветами или даже устанавливать содержание псевдоэлемента. Мы увидим некоторые из этих бонусных демонстраций в конце статьи.
Сетка
Цель состоит в том, чтобы создать невидимую сетку на экране и использовать псевдокласс : hover
для сопоставления каждой «ячейки» с набором значений, которые мы назначим к настраиваемым свойствам. Таким образом, когда курсор мыши перемещается в правую часть экрана, значение - positionX
будет выше; и когда он перемещается влево, он становится ниже. Мы сделаем то же самое с - positionY
: значение будет ниже, когда курсор перемещается вверх, и выше, когда он перемещается вниз.
Несколько слов о размере сетки, которую мы используем: мы действительно можем сделать сетку любого размера, какой захотим. Чем он больше, тем точнее будут значения наших настраиваемых свойств. Но это также означает, что у нас будет больше ячеек, что может привести к проблемам с производительностью. Важно поддерживать правильный баланс и настраивать размер сетки в соответствии с конкретными потребностями каждого проекта.
А пока предположим, что нам нужна сетка 10 × 10 для всего 100 ячеек в нашей разметке. (И да, для этого можно использовать Pug, хотя я не буду в этом примере.)
Вы, наверное, задаетесь вопросом, почему элементы .cell
предшествуют .content
. Это из-за каскада.
Мы хотим использовать класс .cell
для управления .square
и способ работы каскада (на данный момент) таков, что элемент может управлять только своими дочерними элементами (или потомки) и его братьев и сестер (или их потомков) — но только до тех пор, пока брат находится после контролирующего элемента.
Это означает две вещи:
- Каждая
.cell
должна стоять перед элементом, которым мы хотим управлять (в данном случае, .square
).
- Мы не можем поместите эти
.cell
в контейнер, потому что в этом случае .content
больше не будет их родственником.
Размещение камер
Есть несколько способов позиционирования .cell
s. мы можем позиционировать : абсолютные
их и компенсировать их свойствами top
и left
. Или мы можем перевести
их в положение, используя преобразование
. Но самый простой вариант, вероятно, использовать display: grid
.
тело {
цвет фона: # 000;
высота: 100vh;
дисплей: сетка;
сетка-шаблон: повтор (10, 1fr) / повтор (10, 1fr);
}
.клетка {
ширина: 100%;
высота: 100%;
граница: 1 пиксель сплошного серого цвета;
z-индекс: 2;
}
- Граница
временная, поэтому мы могли видеть на экране ячейки
. мы удалим его позже.
-
z-index
важен, потому что мы хотим, чтобы ячейка
располагалась перед содержимым
.
Вот что у нас есть на данный момент:
Добавление значений
Мы хотим использовать .cell
для установки значений - positionX
и - positionY
.
Когда мы наводим курсор на .cell
который находится в первом (левом) столбце, значение - positionX
должно быть 0
. Когда мы наводим курсор на .cell
во втором столбце, значение должно быть 1
. В третьем столбце должно быть 2
и т. Д.
То же самое и для оси y. Когда мы наводим курсор на .cell
который находится в первом (верхнем) ряду, - positionY
должен быть 0
а когда мы наводим курсор на ] ячейку
во второй строке, значение должно быть 1
и т. д.
Цифры на этом изображении представляют собой номера элементов ячеек в сетке. Если мы возьмем только одну .cell
в качестве примера — скажем, ячейку 42 — мы можем выбрать ее, используя : nth-child ()
:
.cell: nth-child (42) {}
Но нам нужно помнить пару вещей:
- Мы хотим, чтобы этот селектор работал только при наведении курсора на ячейку, поэтому мы прикрепим к нему
: hover
.
- Мы хотим выбрать
. содержимое
вместо самой ячейки, поэтому мы будем использовать для этого General Sibling Combinator ( ~
).
Итак, чтобы установить - от -positionX
до 1
и - positionY
до 3
для .content
когда 42-я ячейка
зависает, нам нужно сделать что-то вроде этого:
.cell: nth-child (42): hover ~ .content {
--positionX: 1;
--положениеY: 3;
}
Но кто хочет сделать это 100 раз !? Есть несколько способов упростить задачу:
- Используйте цикл Sass
@for
чтобы просмотреть все 100 ячеек, и выполните некоторые вычисления, чтобы установить правильные - positionX
и - positionY
значений для каждой итерации.
- Разделите оси x и y, чтобы выбрать каждую строку и каждый столбец индивидуально с помощью функциональной записи
: nth-child
.
- ] Объедините эти два подхода и используйте цикл Sass
@for
и : nth-child
функциональную нотацию.
Я долго думал и твердо о том, что было бы лучшим и самым простым подходом, и хотя у всех этих подходов есть свои плюсы и минусы, я остановился на третьем подходе. Объем кода, который нужно написать, качество скомпилированного кода и математическая сложность — все это у меня в голове. Не согласен? Расскажите почему в комментариях!
Установка значений с помощью цикла @for
@ for $ i от 0 до 10 {
.cell: nth-child (???): hover ~ .content {
--positionX: # {$ i};
}
.cell: nth-child (???): hover ~ .content {
--positionY: # {$ i};
}
}
Это основной цикл. Мы повторим это 10 раз, так как у нас 10 строк и 10 столбцов. И мы разделили оси x и y, чтобы установить - positionX
для каждого столбца и - positionY
для каждой строки. Все, что нам нужно сделать сейчас, это заменить эти элементы ???
на правильную нотацию для выбора каждой строки и столбца.
Начнем с оси x
Возвращаясь к нашему изображению сетки (изображенному с числами), мы видим, что номера всех ячеек во втором столбце кратны 10 плюс 2. Ячейки в третьем столбце кратны 10 плюс 3 . И так далее.
Теперь давайте «переведем» его в функциональную нотацию : nth-child
. Вот как это выглядит для второго столбца:
: nth-ребенок (10n + 2)
-
10n
выбирает каждое кратное 10.
-
2
— номер столбца.
И для нашего цикла , мы заменим номер столбца на # {$ i + 1}
для последовательной итерации:
.cell: nth-child (10n + # {$ i + 1}): hover ~ .content {
--positionX: # {$ i};
}
Теперь займемся осью Y
Посмотрите еще раз на изображение сетки и сосредоточьтесь на четвертой строке. Номера ячеек находятся где-то от 41 до 50. Ячейки в пятой строке — от 51 до 60 и так далее. Чтобы выбрать каждую строку, нам нужно определить ее диапазон. Например, диапазон для четвертой строки:
.cell: nth-child (n + 41): nth-child (-n + 50)
-
(n + 41)
— начало диапазона.
-
(- n + 50)
— конец диапазона.
Теперь мы заменим числа математическими вычислениями для значения $ i
. Для начала диапазона мы получаем (n + # {10 * $ i + 1})
а для конца диапазона мы получаем (- n + # {10 * ( $ i + 1)})
.
Итак, последний цикл @for
выглядит так:
@ for $ i от 0 до 10 {
.cell: nth-child (10n + # {$ i + 1}): hover ~ .content {
--positionX: # {$ i};
}
.cell: nth-child (n + # {10 * $ i + 1}): nth-child (-n + # {10 * ($ i + 1)}): hover ~ .content {
--positionY: # {$ i};
}
}
Отображение готово! Когда мы наводим курсор на элементы, - positionX
и - positionY
меняются в зависимости от положения мыши. Это означает, что мы можем использовать их для управления элементами внутри .content
.
Обработка пользовательских свойств
Хорошо, теперь у нас есть положение мыши, сопоставленное с двумя настраиваемыми свойствами. Следующее, что нужно использовать, — это использовать их для управления .square
элементами шириной
и высотой
значения.
Давайте начнем с ширины
и скажем, что мы хотим, чтобы минимальная ширина
.square
была 100 пикселей
(т. Е. Когда курсор мыши находится в левой части экрана), и мы хотим, чтобы он увеличивался 20 пикселей
с каждым шагом, когда курсор мыши перемещается вправо.
Используя calc ()
мы можем сделать это:
.square {
ширина: calc (100px + var (- positionX) * 20px);
}
И, конечно же, мы сделаем то же самое для высоты
но вместо - positionY
:
.square {
ширина: calc (100px + var (- positionX) * 20px);
высота: calc (100px + var (- positionY) * 20px);
}
Вот и все! Теперь у нас есть простой элемент .square
с шириной
и высотой
который управляется положением мыши. Наведите курсор мыши на окно и посмотрите, как квадрат
изменяет свою ширину
и высоту
соответственно.
Я добавил небольшой переход
чтобы сделать эффект более плавным. Конечно, это не обязательно. И я также прокомментировал границу .cell
.
Давайте попробуем альтернативный метод
Возможно, вы захотите «обойти» - positionX
и - positionY
и установить конечное значение непосредственно внутри @for
] петля. В нашем примере это будет выглядеть так:
@ for $ i от 0 до 10 {
.cell: nth-child (10n + # {$ i + 1}): hover ~ .content {
--squareWidth: # {100 + $ i * 20} пикселей;
}
.cell: nth-child (n + # {10 * $ i + 1}): nth-child (-n + # {10 * ($ i + 1)}): hover ~ .content {
--squareHeight: # {100 + $ i * 20} px ;: # {$ i};
}
}
Тогда .square
будет использовать такие настраиваемые свойства:
.square {
ширина: var (- squareWidth);
высота: var (- squareHeight);
}
Этот метод немного более гибкий, поскольку он позволяет использовать более сложные математические (и строковые) функции Sass. Тем не менее, общий принцип абсолютно тот же, что мы уже рассмотрели.
Что дальше?
Что ж, остальное зависит от вас — а возможности безграничны! Как вы думаете, вы бы это использовали? Можете ли вы пойти дальше? Попробуйте использовать этот трюк в своем CSS и поделитесь своей работой в комментариях или дайте мне знать об этом в Twitter. Было бы здорово увидеть их целую коллекцию.
Вот несколько примеров, чтобы у вашего хомячка вращалось колесо: