CSS — это узкоспециализированный язык программирования, ориентированный на системы стилей. Из-за этого уникального варианта использования и его декларативного характера иногда это трудно понять. Некоторые люди вообще отрицают, что это язык программирования. Давайте докажем, что они ошибаются, запрограммировав умную и гибкую систему стилей.
Более традиционные языки общего назначения (например, JavaScript) предоставляют нам такие инструменты, как условия ( if/then
), циклы ( for
, while
), логические элементы ( ===
, &&
, и т. д.) и переменные. Эти структуры называются в CSS по-разному, их синтаксис сильно отличается, чтобы лучше соответствовать конкретному варианту использования при оформлении документа, а некоторые из них просто не были доступны в CSS еще несколько лет назад.
Переменные — самые простые. В CSS они называются пользовательскими свойствами (хотя все равно все называют их переменными, даже в собственном синтаксисе).
1 2 3 4 5 6 7 8 9 |
:root { --color: red; } span { color: var(--color, blue); } |
Двойное тире объявляет переменную и присваивает ей значение. Это должно происходить в области действия, потому что это вне селектора нарушится синтаксис CSS. Обратите внимание на :root
селектор, который работает как глобальная область.
Условия могут быть записаны несколькими способами, в зависимости от того, где вы хотите их использовать. Селекторы привязаны к своим элементам, медиа-запросы имеют глобальную область действия и нуждаются в собственных селекторах.
1 2 3 4 5 6 7 8 9 10 11 12 |
[data-attr='true'] { /* if */ } [data-attr='false'] { /* elseif */ } :not([data-attr]) { /* else */ } |
1 2 3 4 5 6 7 8 9 |
:checked { /* if */ } :not(:checked) { /* else */ } |
1 2 3 4 5 6 7 8 9 10 11 |
:root { color: red; /* else */ } @media (min-width > 600px) { :root { color: blue; /* if */ } } |
Это самая простая форма циклов в CSS, но также и самая узкая форма использования. В свойстве можно использовать только счетчики content
, отображая их в виде текста. Вы можете настроить его приращение, его начальную точку и его значение в любой заданной точке, но вывод всегда ограничен текстом.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
main { counter-reset: section; } section { counter-increment: section; counter-reset: section; } section > h2::before { content: 'Headline ' counter(section) ': '; } |
Но что, если вы хотите использовать цикл для определения повторяющегося шаблона макета? Этот вид loops немного более неясен: это auto-fill
свойство сетки.
1 2 3 4 5 6 7 |
.grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); } |
Заполняется сетка настолько большим количеством элементов, насколько она может поместиться, при этом масштабируя их, чтобы заполнить доступное пространство, но при необходимости разбивая их на несколько строк. Повторения идут до тех пор, пока находятся элементы и ограничиваются их минимальной шириной в 300 пикселей и максимальной шириной в одну часть собственного размера. Наверное, вам проще увидеть, чем объяснить:
https://codepen.io/iamschulz/embed/MWOVgQe?height=600&default-tab=result&embed-version=2#html-box
И, наконец, есть циклические селекторы.
1 2 3 4 5 6 7 8 9 10 |
section:nth-child(2n) { /* selects every even element */ } section:nth-child(4n + 2) { /* selects every fourth, starting from the 2nd */ } |
Для особых случаев вы можете комбинировать :nth-child()
с :not()
, например:
1 2 3 4 5 6 |
section:nth-child(3n):not(:nth-child(6)) { /* selects every 3rd element, but not the 6th */ } |
https://codepen.io/iamschulz/embed/NWwYxGX?height=600&default-tab=result&embed-version=2
Вы можете заменить :nth-child()
на :nth-of-type()
и :nth-last-of-type()
изменить область этих последних нескольких примеров.
Ана Тюдор написала статью о CSS Logic Gates . Она работала над идеей объединения переменных с calc
, занимается 3D-моделированием и анимацией объектов. Это является одним из лучших объяснений того, почему CSS на самом деле является языком программирования.
1 2 3 4 5 6 |
* + * { margin-top: 1rem; } |
Селектор Owl выбирает каждый элемент, который следует за элементом. Применение margin-top
к этому эффективно добавляет зазор между элементами, как grid-gap
это делает, но без системы сетки. Это также означает, что он более настраиваемый. Вы можете перезаписать свой margin-top
и адаптировать для любого вида контента. Хотите иметь 1rem
место между каждым пунктом, но 3rem
перед заголовком? Это проще сделать с помощью селектора owl, чем в сетке.
У Кевина Пеннекампа есть подробная статья об этом, в которой даже объясняется его алгоритм в псевдокоде.
Мы можем создавать переключатели в нашем коде css, которые включают и выключают определенные правила с помощью переменных и calc
. Это дает нам очень универсальные условия.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
.box { padding: 1rem 1rem 1rem calc(1rem + var(--s) * 4rem); color: hsl(0, calc(var(--s, 0) * 100%), 80%); background-color: hsl(0, calc(var(--s, 0) * 100%), 15%); border: calc(var(--s, 0) * 1px) solid hsl(0, calc(var(--s, 0) * 100%), 80%); } .icon { opacity: calc(var(--s) * 100%); transform: scale(calc(var(--s) * 100%)); } |
https://codepen.io/iamschulz/embed/jOazEed?height=600&default-tab=result&embed-version=2
В зависимости от значения --s
он .box
либо включает, либо отключает стили предупреждений.
Давайте сделаем еще один шаг в той же логике и создадим переменную цвета, которая зависит от ее контраста с цветом фона:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
:root { --theme-hue: 210deg; --theme-sat: 30%; --theme-lit: 20%; --theme-font-threshold: 51%; --background-color: hsl(var(--theme-hue), var(--theme-sat), var(--theme-lit)); --font-color: hsl( var(--theme-hue), var(--theme-sat), clamp(10%, calc(100% - (var(--theme-lit) - var(theme-font-threshold)) * 1000), 95%) ); } |
Этот фрагмент вычисляет цвет фона на основе значений HSL и черного или белого цвета шрифта путем инвертирования значения яркости фона. Это само по себе может привести к низкому цветовому контрасту (40% серый шрифт на 60% сером фоне практически неразборчив), поэтому мы вычтем пороговое значение (точка, в которой цвет переключается с белого на черный), умножив его на безумно высокое значение, такое как 1000, и зафиксируйте его между 10% и 95%, чтобы в конце получить действительный процент легкости. Все это можно контролировать, редактируя четыре переменные в начале фрагмента.
https://codepen.io/iamschulz/embed/podLgoK?height=600&default-tab=result&embed-version=2
Этот метод также можно использовать для написания сложной цветовой логики и автоматических тем , основанных только на значениях HSL.
Давайте объединим то, что у нас есть, чтобы очистить таблицу стилей.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
/* define variales */ :root { --paragraph-width: 90ch; --sidebar-width: 30ch; --layout-s: "header header" "sidebar sidebar" "main main" "footer footer"; --layout-l: "header header" "main sidebar" "footer footer"; --template-s: auto auto minmax(100%, 1fr) auto / minmax(70%, var(--paragraph-width)) minmax(30%, var(--sidebar-width)); --template-l: auto minmax(100%, 1fr) auto / minmax(70%, var(--paragraph-width)) minmax(30%, var(--sidebar-width)); --layout: var(--layout-s); --template: var(--template-s); --gap-width: 1rem; } /* manipulate variables by viewport */ @media (min-width: 48rem) { :root { --layout: var(--layout-l); --template: var(--template-l); } } /* bind to DOM */ body { display: grid; grid-template: var(--template); grid-template-areas: var(--layout); grid-gap: var(--gap-width); justify-content: center; min-height: 100vh; max-width: calc( var(--paragraph-width) + var(--sidebar-width) + var(--gap-width) ); padding: 0 var(--gap-width); } |
https://codepen.io/iamschulz/embed/qBVowod?height=600&default-tab=result&embed-version=2
Все глобальные переменные определены в самом верху и отсортированы по области просмотра. Этот раздел фактически становится «Определением поведения» , решая такие вопросы, как:
font-size
повторяющиеся размеры и т. д.Ниже приведены определения правил, отсортированные по компонентам. Медиа-запросы здесь больше не нужны, потому что они уже определены вверху и помещены в переменные. Мы можем просто кодировать в наших таблицах стилей, не прерываясь на этом этапе.
Особым случаем псевдоклассов является :target
селектор, который может считывать хеш-фрагмент URL-адреса. Вот демонстрация, которая использует эту механику для имитации SPA-подобного опыта:
https://codepen.io/iamschulz/embed/GbdQpz?height=600&default-tab=result&embed-version=2
Просто имейте в виду, что это имеет серьезные последствия для доступности и требует некоторой механики JavaScript, чтобы быть удобным.
Манипулирование переменными CSS к настоящему времени стало очень мощным инструментом. Мы также можем использовать это в JavaScript:
1 2 3 4 5 6 7 8 9 10 11 12 |
// set --s on :root document.documentElement.style.setProperty('--s', e.target.value); // set --s scoped to #myID const el = document.querySelector('#myID'); el.style.setProperty('--s', e.target.value); // read variables from an alement const switch = getComputedStyle(el).getPropertyValue('--s'); |
Приведенные выше примеры codepen работают именно так.
CSS очень хорошо подходит для определения интеллектуальных и реактивных систем макета. Его управляющие структуры и алгоритмы могут быть немного странными по сравнению с другими языками, но они есть и справляются со своей задачей. Давайте перестанем просто описывать некоторые стили и начнем заставлять их работать .
Источник статьи: http://dev.to/