- Передача данных между CSS и JavaScript с помощью CSS-переменных
- Передача данных в CSS
- Инлайн-стили
- CSS-классы
- CSS in JS
- Решаем задачу нативно
- CSS Custom Properties
- Взаимодействие между Javascript и CSS с помощью CSS-переменных
- Что такое CSS-переменные?
- CSS-переменные и JavaScript
- P.S. Это тоже может быть интересно:
Передача данных между CSS и JavaScript с помощью CSS-переменных
Одно из самых серьёзных противостояний в мире веб-разработки – CSS против JavaScript. У обоих есть свои достоинства, собственный синтаксис и идеи, иногда понять их может быть непросто. Но есть способы заставить их общаться и использовать достоинства каждого.
С позиции JavaScript для установки различных CSS-свойств HTML-элементу, требуется найти его в DOM и получить доступ к нему. После добавления стилей, у этого элемента появляется атрибут style , который вы не стали бы, наверное, писать вручную.
Ещё один способ доступа к CSS-свойствам из JavaScript – использовать настраиваемые CSS-свойства, они также известны, как «CSS-переменные» (CSS variables), которые можно определять с помощью синтаксиса — . Так:
Это «переменные», поэтому их можно неоднократно использовать в таблице стилей.
Получить к ним доступ и управлять значениями этих переменных можно с помощью JavaScript. В этом примере настраиваемое CSS-свойство устанавливается для корневого элемента документа. Его можно прочитать так:
let bg = getComputedStyle(document.documentElement). getPropertyValue('--pagebackground');
И его можно установить с помощью JavaScript, получив доступ к стилю корневого элемента (или вообще любого другого элемента с настраиваемыми свойствами), так:
document.documentElement.style.setProperty('--pagebackground', 'firebrick');
Но самое выдающееся во всей этой истории то, что используя возможности JavaScript, можно предоставить CSS то, к чему он не может получить доступ. Например, CSS не может прочитать координаты курсора мыши, а JavaScript может.
Для начала, в CSS надо определить пару свойств —mouse-x и —mouse-y , а также установить им начальные значения – 0 :
Затем, в JavaScript следует добавить документу обработчик mousemove . Тогда при движении курсора можно получать его координаты и управлять этими двумя CSS-свойствами с помощью JavaScript:
let root = document.documentElement document.addEventListener('mousemove', e => < root.style.setProperty('--mouse-x', e.x); root.style.setProperty('--mouse-y', e.y); >);
В-общем, дело нехитрое. Поскольку настраиваемые CSS-свойства реагируют на движение мыши и изменяют свое значение, теперь можно, например, показать кружок и заставить его двигаться вслед за курсором, так:
Здесь некоторые пояснения к CSS:
- ширина и высота DIV установлены равными 20 пикселей, а фон – белый
- добавление border-radius: 100% гарантирует, что из квадрата получится круг.
- затем используется transform: translate , чтобы позиционировать круг на экране. Это может быть что-то вроде transform: translate (200px, 300px) , чтобы расположить наш шар на 200 пикселей по горизонтали и 300 пикселей по вертикали относительно левого верхнего угла.
- поскольку JavaScript возвращает для настраиваемого CSS-свойства числовое значение, его необходимо преобразовать в пиксели, умножив на 1px .
- так как размер шара составляет 20 пикселей, то чтобы поместить его центр в точки —mouse-x и —mouse-y , нужно вычесть из координат 10.
Этот трюк позволяет выполнять сложные вычисления, считывать состояние браузера и внешнее взаимодействие с ним в JavaScript, затем передавать результат в CSS и изменять его.
Передача данных в CSS
28 марта 2023 г.
При разработке интерфейсов часто возникает необходимость динамически менять стили HTML-элементов в зависимости от текущего состояния приложения. Существует довольно много способов передать данные из Javascript в CSS и в этой статье я предлагаю их рассмотреть.
Инлайн-стили
Самый простой способ стилизовать элемент — указать CSS-свойства прямо в HTML:
p style="color: #272727;">Lorem ipsum dolor sit.p>
Этот древнейший споособ стилизации максимально прост в использовании, но имеет ряд существенных недостатков:
- Смешивается структура страницы и её оформление (мы же не пишем Javascript прямо в HTML);
- Нет возможности использовать каскад, медиа-выражения и некоторые другие инструменты, доступные в CSS;
- Нет возможности переиспользовать стили для одинаковых элементов.
В JSX последний пункт можно решить с помощью создания переменной:
const paragraphStyles = color: "#272727" >; const MyComponent = () => ( div> p style=paragraphStyles>>Lorem ipsum dolor sit ametp> p style=paragraphStyles>>Lorem ipsum dolor sit ametp> div> );
Похожий подход применяется в React Native , но там каскада нет и возможности CSS довольно сильно ограничены, а в бразуере — родной среде для CSS — подобных ограничений нет и было бы неразумно отказываться от такой богатой функциональности.
CSS-классы
Проблема выше решается путём выноса стилей из HTML:
style> .my-paragraph color: #272727; > style> div> p class="my-paragraph">Lorem ipsum dolor sit ametp> p class="my-paragraph">Lorem ipsum dolor sit ametp> div>
Придумывая название класса, мы создаём некую абстракцию, которую зачастую наделяем смыслом. Вероятно этот класс будет представлять собой некий компонент, но у компонентов в привычном нам понимании бывают свойства, которые можно менять при необходиости. И это не CSS свойства — мы создали абстракцию в виде класса над стилями, не будем спешить её ломать, смешивая её с конкретными стилевыми параметрами.
CSS in JS
Раз речь зашла о компонентах, попробуем вернуться к React и посмотреть, как подобная задача решается там.
В общем-то очень остроумно проблему решают CSS-in-JS фреймворки: чтобы не передавать данные из JS в CSS, мы перенесли CSS в JS:
import styled from "styled-components"; const Paragraph = styled.p` color: #272727; `; const MyComponent = () => ( div> Paragraph>Lorem ipsum dolor sit ametParagraph> Paragraph>Lorem ipsum dolor sit ametParagraph> div> );
Если нам понадобится передать данные из JS в CSS, мы можем сделать это так же, как и с любым другим React-компонентом:
import styled, css > from "styled-components"; interface ParagraphProps type?: "regular" | "important"; > const paragraphTypeStyles = regular: css` color: #272727; `, important: css` background-color: #ff6287; font-weight: bold; `, >; const Paragraph = styled.pParagraphProps>` $( type = "regular" >) => paragraphTypeStyles[type]> `; const MyComponent = () => ( div> Paragraph>Lorem ipsum dolor sit ametParagraph> Paragraph type="important">Lorem ipsum dolor sit ametParagraph> div> );
Мы передаём некий дискретный набор данных в компонент и для каждой новой их комбинации styled-components будет создавать уникальный класс и вставлять его в DOM. Но что, если параметр не дискретный и меняется часто?
import useEffect, useState > from "react"; import styled from "styled-components"; interface BallProps position: [x: number, y: number]; > const Ball = styled.divBallProps>` width: 32px; height: 32px; border-radius: 16px; background-color: #ff6287; transform: $( position >) => `translate($position[0]>px, $position[1]>px)`>; `; const MyComponent = () => const [position, setPosition] = useState([0, 0]); useEffect(() => let rafId; /** Меняем позицию 60 раз в секунду */ const update = (time: number) => setPosition([Math.sin(time * 30), Math.cos(time * 30)]); rafId = window.requestAnimationFrame(update); >; rafId = window.requestAnimationFrame(update); return () => window.cancelAnimationFrame(rawId); >; >, []); return Ball position=position> />; >;
Спустя некоторое время styled-components вежливо намекнёт, что так делать не стоит, прямо в консоли браузера:
Для этого случая нам предлагают использовать инлайновые стили, но по прежнему они спрятаны за абстракцией в виде пропсы position , за счёт чего стили отделены от логики:
import useEffect, useState > from "react"; import styled from "styled-components"; interface BallProps position: [x: number, y: number]; > const Ball = styled.divBallProps>.attrs(( position >: BallProps) => ( style: transform: `translate($position[0]>px, $position[1]>px)` > >))` width: 32px; height: 32px; border-radius: 16px; background-color: #ff6287; `; const MyComponent = () => const [position, setPosition] = useState([0, 0]); // . return Ball position=position> />; >;
Но что если СSS-in-JS решение не подходит?
Решаем задачу нативно
Методология БЭМ предлагает модификаторы , которые могут быть:
input class="input input_invalid" /> style> .input__invalid border-color: red; > style>
p class="paragraph paragraph_type_important">Lorem ipsump>
Аналогично можно использовать data-атрибуты:
input class="input" data-invalid="true" /> style> .input[data-invalid="true"] border-color: red; > style>
Во многих случаях, кстати, data-атрибуты можно заменить на aria-атрибуты и таким образом убить сразу двух зайцев: стили и доступность:
input class="input" aria-invalid="true" /> style> .input[aria-invalid="true"] border-color: red; > style>
Перечисленные выше решения опять же позволяют создавать конечные наборы значений. Вот бы был способ передать Javascript-переменную в CSS.
Что? Такой способ уже есть?
CSS Custom Properties
С их помощью можно в том числе организовать API между бизнес-логикой и визуалом:
div class="ball" style="--position-x: 35px; --position-y: 54px;">div> style> .ball width: 32px; height: 32px; border-radius: 16px; background-color: #ff6287; transform: translate(var(--position-x), var(--position-y)); > style>
const MyComponent = () => const [position, setPosition] = useState([0, 0]); // . return ( div className="ball" style= "--position-x": position[0], "--position-y": position[1], >> /> ); >;
И самая главная мощь тут заключается в том, что CSS-переменные действуют каскадно!
То есть мы можем разработать компонент, состоящий из нескольких вложенных друг в друга HTML-элементов, установить значение СSS-переменной на корневом элементе и использовать его в потомках:
div id="cube-demo" class="viewport" style="--scroll-top: 0"> div class="cube"> div class="cube-edge cube-edge_front">div> div class="cube-edge cube-edge_left">div> div class="cube-edge cube-edge_back">div> div class="cube-edge cube-edge_right">div> div class="cube-edge cube-edge_top">div> div> div> style> .cube transform: rotateY( calc(var(--scroll-top) * 1deg) /* Не забудем о единицах измерения */ ); > style> script> document.addEventListener("scroll", ( event >) => document .getElementById("cube-demo") .style.setAttribute("--scroll-top", event.target.scrollTop.toString()); >); script>
Взаимодействие между Javascript и CSS с помощью CSS-переменных
На 2016 г. CSS-переменные полностью работоспособны в Chrome и Firefox, у IE тоже в планах реализовать их.
Как часто бывает с новинками JavaScript и CSS, не сразу удается представить себе, для чего CSS-переменные могут пригодиться. Для большинства из нас эти переменные — что-то новое и непривычное, так что не всегда очевидно, к чему их применить. Но мы нашли замечательный ответ — взаимодействие между Javascript и CSS.
Что такое CSS-переменные?
CSS-переменные (см. спецификацию) добавляют в CSS два новых понятия. Отныне можно определять собственные свойства, начинающиеся с двойного дефиса ( — ):
А затем использовать их с помощью var():
Для всех, кто знаком с SASS или подобным языком, компилирующимся в CSS, преимущества этого очевидны, можно запросто менять цвета, размеры и т.п. всего в одном месте.
Что интересно, переменные подчиняются тем же правилам наследования, что другие CSS-свойства. Например, вдруг мы решили поэкспериментировать с основным цветом нашего блога:
Все ссылки внутри той части страницы, что относится к записи в блоге, окажутся страшноватого коричневого оттенка.
CSS-переменные просто великолепно сочетаются с выражением calc() :
CSS-переменные и JavaScript
Недавно мы натолкнулись на полифил для ползунка, который написала Лиа Веру, с интересным примером использования CSS-переменных для связи между JavaScript и CSS.
Исторически единственным способом управлять стилями переменной или функцией из JavaScript было, по сути, писать CSS в самом скрипте:
myElement.style.height = height + 'px'
Не так уж редко случается отказываться от отдельного CSS вообще и просто писать стили в JS:
var newStyles = document.createElement('style') document.head.append(newStyles) newStyles.innerHTML = ".my-element "
CSS-переменные позволяют делать намного лучше, возьмем тот же пример:
Тогда в JavaScript можно прописать эту переменную именно для нашего элемента:
myElement.style.setProperty('--element-height', height + 'px')
Если исхитриться, можно обойтись и без конкатенации:
myElement.style.setProperty('--element-height', height)
Можно даже определить в CSS значение по умолчанию, которое потом переопределится скриптом:
Теперь можно аккуратно передавать информацию между JavaScript и стилями. Ну разве это не потрясающе?
Вот готовый пример, с которым можно поиграть:
P.S. Это тоже может быть интересно:
Если вам понравилась статья, поделитесь ей!