JS30. Задание 3 CSS Variables and JS



Демо: https://js3003.github.io/
Код: https://github.com/js3003/js3003.github.io

Должно получиться приложение для редактирования фото, движением ползунков регулирующее ширину рамки, размытие фото и цвет рамки.

Мне бы хотелось применить к фото больше фильтров css, благо, работают они хорошо и эффекты предлагают интересные,  менять цвет всего фона, а не только рамки, и, возможно, менять размер всего фото, а не только рамки (здесь нужно подумать)

Но пока сделаю точную копию, посмотрю что получится. Потому что трудно представить, но весь js-код этого приложения у автора поместился всего в шесть строчек (!!!)

Вот как он выглядит:

const inputs = document.querySelectorAll('.controls input');

    function handleUpdate() {
      const suffix = this.dataset.sizing || '';
      document.documentElement.style.setProperty(`--${this.name}`, this.value + suffix);
    }

    inputs.forEach(input => input.addEventListener('change', handleUpdate));
    inputs.forEach(input => input.addEventListener('mousemove', handleUpdate));

Попробую разобраться как ему это удалось.

Первое наблюдение.
Код не такой уж минималистичный, часть кода вынесена в css

:root {
    --base: #ffc600;
    --spacing: 10px;
    --blur: 10px;
}

img {
    padding: var(--spacing);
    background: var(--base);
    filter: blur(var(--blur));
}

.hl {
    color: var(--base);
}

Странная конструкция.
Предположим,  :root это некие базовые цвета и значения.
А зачем вначале две точки? Это псевдокласс? Не похоже. В коде этот :root встречается только один раз - откуда css будет знать какому элементу его присваивать?

Поэкспериментировала. Если убрать две точки и изменить имя, всё работает по-прежнему. Если полностью убрать :root, тоже работает. И если фигурные скобки убрать, работает. А если вместо двух чёрточек ставить одну - уже не работает. И без фигурных скобок теперь тоже не работает. В общем, какие-то чудеса.

Нашла. Это называется пользовательские свойства CSS - Custom Properties
Достаточно новые, кстати, статьи о них датируются 2016-2017 годами. Название одной особенно говорящее "Вы не знаете CSS!". Согласна, действительно не знаю.
Хотя, нет. На хабре о них была статья ещё в 2013 г. Хабр молодцы. 

CSS - Custom Properties

Пользовательские свойства, объявляющие переменные, должны именоваться начиная с var-
Общие значения объявляются в стилевых правилах для корневого элемента :root, они будут доступны для каждого элемента документа:

:root {
    var-color: #009EE0;
    var-spacing: 24px;
}

Обращаться к переменным можно в любом месте внутри значения другого свойства:

h1 {
    color: var(color);
}

p {
    margin-top: var(spacing);
}

Можно подстраховаться и написать что-то вроде

h1 {
    color: var(color, red);
}

Это значит, что элемент h1 будет цвета color, указанного в корневом элементе :root, но если переменная color почему-то не определена, h1 будет красным (red).

Это было в 2013 году.

В 2017 синтаксис немного изменился. Смотрим MDN

CSS переменные (пользовательские CSS-свойства) это сущности, определяемие автором CSS, хранящие конкретные значения, которые можно повторно использовать в документе. Они устанавливаются с использованием custom property нотации (например. --main-color: black;) и доступны через функцию var() (например. color: var(--main-color);) .

Note: В более ранней спецификации префикс для переменных был var- , но позже был изменен на --

Теперь понятно зачем нужны две чёрточки вначале.

CSS переменные подчиняются каскаду и наследуют значения от своих родителей.

Объявив переменную в псевдо-классе :root, автор CSS может избежать ненужных повторений, используя эту переменную.

Вроде бы как разобралась )
То есть автор установил базовые значения пользовательских свойств, применил  их к элементам документа, и теперь, очевидно, будет менять базовые значения при помощи js.

Заслуживает внимания разметка.

<input type="range">

Этот элемент сразу даст нам шкалу с ползунком, который передвигается мышкой. Он полностью прорисовывается самим браузером и не требует стилизации в css и настройки в js.
Подробнее: http://htmlbook.ru/samhtml5/formy/polzunok  

<input type="color">

Это окно для выбора цвета. Как и для предыдущего элемента, стили для него прописаны в самом браузере.

Разбираем код по строчкам

1. const inputs = document.querySelectorAll('.controls input'); - метод поиска элементов нашёл все input и присвоил их переменной inputs. В результате получили что-то вроде массива элементов. На самом деле это не массив, а объект NodeList (неожиданно, да) о его отличиях от массива можно почитать здесь
основное отличие - у NodeList работают не все методы массива. Впрочем for (var i = 0; i < myNodeList.length; i++) работает, и этого достаточно. Но ещё лучше, что работает метод .forEach() Хоть я им, к сожалению, до сих пор ни разу не пользовалась. Почитать о методе можно здесь.

2.    function handleUpdate() { - красивое говорящее название функции подсказывает, что она будет обновлять положение ползунка. Наверное

      const suffix = this.dataset.sizing || ''; это он создал новую переменную suffix (кстати, почему он переменные константами называет?) и присвоил ей значение px или пустая строка

this.dataset возвращает объект, содержащий все значения атрибута data-.
То есть this.dataset.sizing вернёт px, если data-sizing="px", или пустую строку, если у элемента нет атрибута data-

Перескакиваем через строку и видим два слушателя:

    inputs.forEach(input => input.addEventListener('change', handleUpdate));
    inputs.forEach(input => input.addEventListener('mousemove', handleUpdate));

Ну, во-первых, здесь появилась функция стрелки. Вообще-то это новая функция, которую ввели только в  ECMAScript 6
Она вызывается для каждого элемента inputs (inputs.forEach)  принимает его в качестве аргумента input и возвращает input.addEventListener(), который отслеживает события change и mousemove и вызывает функцию handleUpdate.

Событие change происходит по окончании изменении значения элемента формы, когда это изменение зафиксировано.
Событие mousemove срабатывает при передвижении мыши

И осталась последняя строка кода. Что же делает функция handleUpdate кроме того, что определяет  значение атрибута data-sizing и присваивает его переменной suffix.

 Строка:
      document.documentElement.style.setProperty(`--${this.name}`, this.value + suffix);

Расшифровываю практически посимвольно

document.documentElement - это корневой элемент документа. То есть html? Хотя нет. Раз функция вызывается для input, возможно, именно его она и меняет?

И вот этому корневому элементу мы добавляем стиль - css-правило
setProperty - метод, использующийся для задания стилевых свойств. Метод имеет два аргумента: name - имя свойства, которое меняется, и value - значение свойства.

Что же это за правило?
(`--${this.name}`, this.value + suffix) 
- две чёрточки - это то, с чего начинается пользовательское css-свойство
- $ - знак доллара это не просто один из разрешённых символов в имени переменной в js, как, например, уверяют здесь, а часть шаблонной строки - новой экспериментальной технологии, предложенной ECMAScript 6

Шаблонные строки заключены в обратные кавычки (` `)  вместо двойных или одинарных. Они могут содержать местозаполнители, которые обозначаются знаком доллара и фигурными скобками (${выражение}). Выражения в местозаполнителях и текст между ними передаются в функцию. 

Соответственно, `--${this.name}` это две чёрточки и name input бля которого слушатель заметил изменение. То есть  document.documentElement действительно не html, у которого никакого name нет, а input, name которого указано таким же, как и имя свойства, за которое он отвечает.

<input type="range" name="spacing"> - отвечает за отступ,
<input type="range" name="blur"> - отвечает за размытие и т.д

Итак, у нас есть две чёрточки и свойство, дальше идёт запятая значение this.value и единицы измерения - suffix

М-да. 5 часов (!!!) я разбирала 6 строчек кода
В оправдание могу сказать, что код новый, современный и узнала я много нового
- пользовательские свойства CSS - Custom Properties
- ползунок input type="range"
- шаблонные строки
- функция стрелки
И ещё много всего разного.
Ну что ж, удачи мне. Попробую применить полученные знания на практике.