Съставни стилове с CSS променливи
Собствените свойства на CSS позволяват да съхраняваме не само пълни стойности, но и частични. Такива стилове можем да наречем съставни.
padding
и margin
Както можем да зададем:
p {
--padding: 0 1em;
padding: var(--padding);
}
Така можем да имаме и:
p {
--padding-x: 1em;
--padding-y: 0;
padding: var(--padding-y) var(--padding-x);
}
Вторият пример ни позволява лесно да променим padding-а или само по X координатата, или само по Y.
Често пъти в медийни заявки може да ни се наложи да променим padding (или пък margin) само по едно от двете направление. За да не презапишем другото направление не можем да си позволим да използваме shorthand синтаксиса и трябва да пишем padding-left
и отделно padding-right
. Не е кой-знае-колко много работа, но все пак е тягостно.
Ако обаче имаме:
* {
padding: var(--padding-y, 0) var(--padding-x, 0);
margin: var(--margin-y, 0) var(--margin-x, 0);
}
Това би означавало, че като част от reset-а си задаваме padding и margin със стойности 0 (което са стойностите по подразбиране, ако променливите не са дефинирани). В същото време можем много лесно за всички елементи на сайта си да дефинираме просто --padding-x
, --padding-y
, --margin-x
и --margin-y
лесно и удобно.
Ако сте срещали CSS framework-а Tailwind, то вероятно сте се сблъсквали и с класове като px-2
, py-2
, mx-2
и my-2
, където p
и m
идват съкратено от padding
и margin
, x
и y
са направленията съответно по ординатата или абсцисата, а числовите стойности накрая са относителни размери на свойствата, които задаваме (можем да използваме и други числа). Принципът на работа там е аналогичен.
transform
Друго свойство, при което можем да имаме голяма полза от съставни стилове посредством CSS променливи е transform
.
Тук ситуацията е такава, че не сме ограничени само откъм shorthand синтаксис, но каквато и промяна да се опитаме да добавим към transform
тя ще презапише предходните опции.
Така, че ако имаме елемент, който е центриран спрямо релативния си родител си по следния начин:
.centered {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
Ако при hover (примерно) се опитаме да уголемим елемента със scale()
, не можем да добавим само:
.centered:hover {
transform: scale(1.1);
}
защото по този начин ще изгубим частта translate(-50%, -50%)
.
Вместо това трябва да повторим translate
и тогава да добавим scale
:
.centered:hover {
transform: translate(-50%, -50%) scale(1.1);
}
Това отново е най-малкото тягостно, но също може да доведе и пропуск, в следствие от който и грешка. А може да доведе и до почти невъзможно ситуации, в които част от тези стилове всъщност се задават с JavaScript. В подобни ситуации първата ни идея може да е:
- да вземем текущия стил
- да го парсираме с някакъв сложен регулярен израз
- ако новата трансформация, която искаме да зададем я няма – да я append-нем
- ако трянсформацията я има, да пресметнем наслагването между старата и новата ѝ версия и да направим replace в текущите стилове и да ги обновим
Горното е толкова немислимо, че по-добре да прибегнем към това, което библиотеки като GSAP правят вместо това: използват transform: matrix()
за да приложан комплексна трансформация, като тази матрица е изчислена на база математически функции спрямо отделните трансформации, които искаме да направим.
И това не е особено лесно, тъй като има такова количество математика, че освен ако не разработвате самите вие някаква подобна библиотека – не си струва труда.
Вместо това обаче можем да приложим подход подобен на margin
и padding
:
* {
transform: translate(var(--translate, 0)) rotate(var(--rotate, 0)) scale(var(--scale, 1));
}
Горният пример е опростен и не включва всички трансформации, които могат да бъдат приложени, но мисля, че е достатъчно илюстративен и вероятно ще покрие нуждите ви в над 90% от случаите.
Други
Разбира се същият принцип може да се приложи и с background
(макар, че конкретно за URL да има проблеми с ползване на CSS променливи), font
, text-shadow
, box-shadow
, градиенти, вътре в rgb()
и rgba()
и т.н. С повече въображение може да намерите и много други приложения.