Русский
Русский
English
Статистика
Реклама

Preprocessor

Из песочницы Atomizer vs Minimalist Notation (MN)

12.07.2020 14:15:44 | Автор: admin

Minimalist Notation (MN) (минималистическая нотация) гибкая адаптивная технология генерации стилей.


Она генерирует стили только для существующих классов разметки html, jsx, и т.п. благодаря чему отпадает необходимость заботиться о компонентом подходе в CSS, мёртвом CSS коде, и отпадает необходимость писать CSS код вообще.


В ней поддерживаются брейкпонты (медиа-запросы), селекторы, приоритеты, группировки, необходимые автопрефиксы и полифилы.


Применение этой технологии похоже на использование инлайновых стилей, только с гораздо более выразительным синтаксисом и множеством дополнительных возможностей, поэтому MN можно даже назвать технологией inline styles 2.0.


MN подразумевает не только правила нотации как таковые, но и, по-сути, даже усовершенствованный альтернативный синтаксис каскадного языка установки стилей, который ориентирован на инлайновое применение.


Я разработал MN в 2017 году, и с того момента успел во многом усовершенствовать эту технологию, добавить достаточно пресетов и удобных инструментов для её изучения.


Если кто-то желает узнать о том, как мне пришло в голову разработать собственную технологию, я оставляю ссылку на свой репозиторий, дабы не плагиатить у самого себя.


Технология MN имеет обширную функциональность.


Для многих она является новой, и почти не имеет других первоисточников для изучения, кроме этой статьи, поэтому предупреждаю, что ниже будет МНОГО БУКВ и примеров кода.


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


Лучший способ что-то объяснить это показать наглядные примеры.


Начнём с сравнения Minimalist-Notation с более менее известными функциональностями его первого аналога: Atomizer.


Актуальные на момент написания статьи версии пакетов:


  • minimalist-notation 1.5.17 ;
  • atomizer 3.6.2 .

Проверить примеры ниже с Atomizer можно будет здесь:
https://pankajparashar-zz.github.io/atomizer-web/


Проверить примеры ниже с MN можно можно будет здесь:
https://viewer.minimalist-notation.org/


Документация по всем предустановленным пресетам MN здесь:
https://styles.minimalist-notation.org/




Atomizer vs MN. Простые примеры##


Atomizer


<div class="D(f) Jc(c) Ai(c) H(100%) Fz(20vh) C(#0f0) C(#F00) Bgc(#f00) M(-10px) P(10px) Pstart(10%) Pos(a)">...</div>

.D\(f\) {  display: flex;}.Jc\(c\) {  justify-content: center;}.Ai\(c\) {  align-items: center;}.H\(100\%\) {  height: 100%;}.Fz\(20vh\) {  font-size: 20vh;}.C\(\#0f0\) {  color: #0f0;}.Bgc\(\#f00\) {  background-color: #f00;}.M\(-10px\) {  margin: -10px;}.P\(10px\) {  padding: 10px;}.Pstart\(10\%\) {  padding-left: 10%;}.Pos\(a\) {  position: absolute;}

На что я обратил внимание в этом примере с Atomizer:


  • аббревиатуры аналогичны Emmet;
  • имена свойств в нотации представлены как функции, которые всегда именуются аббревиатурами, начинающимися с верхнего регистра;
  • значения свойств стилей в нотации обязательно заключаются в скобки;
  • аббревиатура Pstart для свойства padding-left для меня неожиданна;
  • единицы измерения в нотации нельзя пропускать;
  • некоторые значения можно задавать только предустановленными аббревиатурами, такими как, например: f - flex, c - center, однако, например, такая запись работать не будет: D(flex);
  • когда я пытаюсь задавать цвет символами верхнего регистра, например, #F00 вместо, #f00, то стили не генерируются, либо генерируется какая-то петрушка

Minimalist-Notation


<div class="dF jcC aiC h f20vh c0F0 bgcF00 m-10 p10 pl10% abs">...</div>

.dF {  display: flex;}.jcC {  justify-content: center;}.aiC {  align-items: center;}.h {  height: 100%;}.f20vh {  font-size: 20vh;}.c0F0 {  color: #0f0;}.bgcF00 {  background-color: #f00;}.m-10 {  margin: -10px;}.p10 {  padding: 10px;}.pl10\% {  padding-left: 10%;}.abs {  position: absolute;}

Отличия:


  • для большинства дефолтных обработчиков аббревиатуры аналогичны Emmet, за некоторыми исключениями, которые связаны исторически с моими личными практиками, частотой использования различных свойств стилей.


    Это связано ещё с тем, что лично я узнал о существовании Emmet и Atomizer только после того, как создал первую версию MN.
    Примеры:
    f вместо fz для свойства font-size ибо размер шрифта Мы задаем очень часто,
    font вместо f для свойства font ибо Мы редко используем его непосредственно,
    abs вместо posA для свойства и значения position: absolute, хотя posA тоже можно использовать;


  • имена свойств в нотации именуются аббревиатурами в нижнем регистре;


  • значения свойств стилей в нотации начинаются с любого символа отличного от латинских букв в нижнем регистре.


    Кончено и здесь в нотации значения также можно заключать в скобки: d(F) но скобки
    в MN предназначены не для параметризации, а для группировки подстрок нотации, например,
    эти записи аналогичны: p(l10|r15) === pl10 pr15.


    Кроме того, нет смысла использовать скобки без нужды, ибо это увеличивает конечный размер кода.


  • единицы измерения не являются частью базовой нотации.


    Необходимость указания единиц измерения зависит от обработчика заданного для соответствующего имени в нотации.


    Для большинства дефолтных обработчиков указание единиц измерения являются опциональным, например, возможны вариации:
    f14px == f14,
    h100% == h,
    h10px == h10.


  • в MN также имеются предустановленные аббревиатуры для некоторых значений, такие как, например,
    F - flex, C - center хотя Мы можем использовать полные именования.
    Вы имеете возможность использовать вместо, например, этих аббревиатур:
    dF dIB jcC aiC различные вариации именований:
    dFlex dInlineBlock jcCenter aiCenter,
    d_flex d_inline-block jc_center ai_center .
    В большинстве дефолтных обработчиков запись для значений из формата camelCase
    просто трансформируется в формат kebabCase, а нижнии прочерки заменяются на пробелы;


  • для большинства дефолтных обработчиков предусмотрены значения по умолчанию, например, как Мы наблюдаем, для свойства height (h) значение по умолчанию равно 100% .
    Если Мы используем значение: h40 то получим следующее:


    .h40 {height: 40px}
    

  • Для указания цвета не требуется решетка (#).



Более того, решетка (#) является служебным символом, необходимым для полноценных селекторов, о которых Вы узнаете ниже.


Если Вы добавите решетку, то получите не то, чего, вероятно, ожидаете:


<div class="c#0F0">...</div>

.c\#0F0#0F0 {color: #000}

В некоторых случаях решетка всё же нужна, например, для свойства outline.
Тогда служебные символы в нотации нужно экранировать:


<div class="ol_thick_double_\#32a1ce">...</div>

.ol_thick_double_\\\#32a1ce {outline: thick double #32a1ce}

В MN для дефолтных обработчиков (c, bc, olc, fill, stroke, bg, bgc, temc, tdc) цвета можно задавать разными вариациями символов об этом подробнее будет ниже.


  • обработчики для аббревиатур свойств являются кастомизируемыми и подключаются по умолчанию из библиотеки minimalist-notation/presets/styles.

Вы имеете возможность полностью кастомизировать MN под свои нужды, путем создания собственных обработчиков:


// для свойcтва "padding"mn('p', (params) => {  return {    style: {      padding: (params.num || '0') + (params.unit || 'px'),    },  };});// для свойcтва "padding-left"mn('pl', (params) => {  return {    style: {      paddingLeft: (params.num || '0') + (params.unit || 'px'),    },  };});// для свойcтва "color"mn('c', (params) => {  return !params.negative && {    style: {      color: mn.utils.color(params.value || '0'),    },  };}, '^(([A-Z][a-z][A-Za-z]+):camel|([A-F0-9]+):color):value(.*)?$');

Примеры обработчиков MN можно подсмотреть в репозитории:
https://github.com/mr-amirka/minimalist-notation/presets


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




Примеры немного сложнее


Atomizer vs MN. Флаг !important


Atomizer


<div class="D(f)! C(#0f0)!">...</div>

.D\(f\)\! {  display: flex !important;}.C\(\#0f0\)\! {  color: #0f0 !important;}

Minimalist-Notation


<div class="dF-i c0F0-i">...</div>

.dF-i {  display: flex!important;}.c0F0-i {  color: #0f0!important;}

В MN для установки флага !important не используется символ !, потому-что этот служебный символ уже применяется в нотации для реверсирования подстрок.




Группировки и реверсирование подстрок (!)


Возьмем такую запись:


<div class="cF:hover>.item">...</div>

.cF\:hover\>\.item:hover .item {  color: #fff;}

Если Мы добавим символ ! после :hover, то получим следующее:


<div class="cF:hover!>.item">...</div>

.cF\:hover\!\>\.item .item:hover {  color: #fff;}

Здесь псевдоселектор hover переместился от родительского элемента к дочернему.
Этот приведенный для наглядности способ использования реверсирования в данном случае бесполезен, ибо такого же эффекта Мы можем добиться и другим способом:


<div class="cF>.item:hover">...</div>

.cF\>\.item\:hover .item:hover {  color: #fff;}

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


Допустим, что Мы верстаем какой-то простой сайт без шаблонизаторов и без React компонентов возможно, это лендинг.


Мы имеем некоторый список, в котором располагаются одинаковые дочерние элементы:


<ul class="m p dBlock">  <li class="mb5 dBlock">    <a class="c0 c0:hover tdNone p5">...</a>  </li>  <li class="mb5 dBlock">    <a class="c0 c0:hover tdNone p5">...</a>  </li>  <li class="mb5 dBlock">    <a class="c0 c0:hover tdNone p5">...</a>  </li>  ...</ul>

.m {  margin: 0;}.p {  padding: 0;}.dBlock {  display: block;}.mb5 {  margin-bottom: 5px;}.c0,.c0\:hover:hover {  color: #000;}.tdNone {  text-decoration: none;}.p5 {  padding: 5px;}

Мы понимаем, что указывать классы для каждого элемента может быть довольно утомительно, особенно если в процессе Мы будем что-то изменять.


Мы могли бы написать код гораздо короче, и таким образом, чтобы в последующем при необходимости Нам приходилось вносить меньше правок.


Рассмотрим по шагам различные способы.


Вынесем всю нотацию в родительский элемент:


<ul class="m p dBlock mb5>li dBlock>li c0>a c0>a:hover tdNone>a p5>a">  <li>    <a>...</a>  </li>  <li>    <a>...</a>  </li>  <li>    <a>...</a>  </li>  ...</ul>

Это выглядит прикольно, но если свойств и элементов будет довольно много, или если селекторы дочерних элементов будут более длинные, то получится довольно громоздко и мало читаемо.


Для примера Мы добавим ещё один уровень списка, который имеет отступ в 10 пикселей слева, а ссылки внутри него имеют подчеркивание и красный цвет.


При наведении курсора на ссылку, она становится зеленой, а при нажатии становится синей.


<ul class="  m p dBlock  mb5>li dBlock>li  p5>a tdNone>1li>1a c0>1li>1a c0>1li>1a:hover  m>ul p>ul dBlock>ul pl10>1li>1ul  tdUnderline>1li>1ul>1li>1a  cRed>1li>1ul>1li>1a  cGreen>1li>1ul>1li>1a:hover  cBlue>1li>1ul>1li>1a:active">  <li>    <a>...</a>  </li>  <li>    <a>...</a>  </li>  <li>    <a>...</a>    <ul>      <li>        <a>...</a>      </li>      ...    </ul>  </li>  ...</ul>

Число перед селектором (1) просто указывавет на строго определенную глубину вложенности элемента.


Кстати, обратите внимание: селекторы с одинаковыми значениями свойств в сгенерированном CSS коде группируются вместе что позволяет минимизировать его объём на выходе.


Думаю, этого для наглядности Нам пока хватит.


Теперь попробуем группировки:


<ul class="  (m|p|dBlock)(|>ul) (mb5|dBlock)>li  p5>a tdNone>1li>1a c0>1li>1a(|:hover)  pl10>1li>1ul  (tdUnderline|cRed)>1li>1ul>1li>1a  cGreen>1li>1ul>1li>1a:hover  cBlue>1li>1ul>1li>1a:active">  <li>    <a>...</a>  </li>  <li>    <a>...</a>  </li>  <li>    <a>...</a>    <ul>      <li>        <a>...</a>      </li>      ...    </ul>  </li>  ...</ul>

Здесь группировки Нам не сильно помогли


Вот теперь попробуем ещё и реверсирование:


<ul class="  (m|p|dBlock)(|>ul)  (mb5|dBlock)>li p5>a  (tdNone|c0(|:hover!))>1li>1a  pl10>1li>1ul  (tdUnderline|c(Red|Green:hover!|Blue:active!))>1li>1ul>1li>1a">  <li>    <a>...</a>  </li>  <li>    <a>...</a>  </li>  <li>    <a>...</a>    <ul>      <li>        <a>...</a>      </li>      ...    </ul>  </li>  ...</ul>

Забавно, не правда ли?


Хорошо. Слегка поиграем с вложенностями и заменим имена псевдоклассов и значений на краткие синонимы:


<ul class="  (m|p|dB)(|>ul)  (mb5|dB)>li  p5>a  (tdN|c0(|:h!))>2a  pl10>2ul  (tdU|c(Red|Green:h!|Blue:a!))>4a">  <li>    <a>...</a>  </li>  <li>    <a>...</a>  </li>  <li>    <a>...</a>    <ul>      <li>        <a>...</a>      </li>      ...    </ul>  </li>  ...</ul>

Всё-таки, для пущей наглядности заменю имена тегов на классы:


<ul class="  ListA  (m|p|dB)(|.ListA)  pl10>2.ListA  (mb5|dB)>.ListA__Item  (p5>|(tdN|c0(|:h!))>2|(tdU|c(Red|Green:h!|Blue:a!))>4).ListA__Link">  <li class="ListA__Item">    <a class="ListA__Link">...</a>  </li>  <li class="ListA__Item">    <a class="ListA__Link">...</a>  </li>  <li class="ListA__Item">    <a class="ListA__Link">...</a>  </li>  <li>    <a class="ListA__Link">...</a>    <ul class="ListA">      <li class="ListA__Item">        <a class="ListA__Link">...</a>      </li>      ...    </ul>  </li>  ...</ul>

Извратились Мы знатно!


Однако, рекомендую, друзья мои, этими группировками сильно не увлекаться!


Здесь у некоторых может возникнуть вопрос, как же Нам решить проблему с
неодноранговастью сгенерированных селекторов? ибо, если Мы захотим кастомизировать
отдельные элементы из этого списка, нам могут помешать грабли перекрывающих стилей.


Ответ:


Мы, например, можем просто именовать классы дочерних уровней немного иначе и не указывать в нотации глубину их вложенности, дабы селекторы всех уровней имели равный приоритет:


<ul class="  ListA  (m|p|dB)(|.ListA)  (mb5|dB)>.ListA__Item  p5>.ListA__Link  (tdN|c0(|:h!))>.ListA__Link_level1  pl10>.ListA_level2  (tdU|c(Red|Green:h!|Blue:a!))>.ListA__Link_level2  bgF88>.ListA__Item_substyle">  <li class="ListA__Item ListA__Item_level1 ListA__Item_substyle">    <a class="ListA__Link ListA__Link_level1">...</a>  </li>  <li class="ListA__Item ListA__Item_level1">    <a class="ListA__Link ListA__Link_level1">...</a>  </li>  <li class="ListA__Item ListA__Item_level1">    <a class="ListA__Link ListA__Link_level1">...</a>  </li>  <li>    <a class="ListA__Link">...</a>    <ul class="ListA ListA_level2">      <li class="ListA__Item ListA__Item_level2">        <a class="ListA__Link ListA__Link_level2">...</a>      </li>      <li class="ListA__Item ListA__Item_level2 ListA__Item_substyle">        <a class="ListA__Link ListA__Link_level2">...</a>      </li>      ...      ...    </ul>  </li>  ...</ul>

Многие могут заметить, что здесь Мы имеем возможность использовать сложные селекторы, которые потенциально порождают нежелательные сайд-эффекты с перекрытиями стилей.
Да. Это так. И это, отчасти, противоречит самой методологии Atomic CSS.


Тем не менее, есть несколько нюансов:


  • Нас никто не принуждает использовать именно такие конструкции;
  • Нас никто не ограничивает, и при необходимости Мы можем воспользоваться этими конструкциями;
  • Благодаря тому, что весь код как правило вмещается у Нас на одном экране и не разрывается контекст между разметкой и стилями, Нам гораздо проще обнаружить, "где зарыта собака" и исключить возможные грабли с перекрытиями стилей.



Atomizer vs MN. Псевдоклассы и псевдоэлементы


Чисто ради сравнения, рассмотрим доступную в Atomizer возможность использования псевдоклассов и псевдоэлементов:


<div class="Bgc(#fff):h C(blue):a C(#0f0):hover D(n)::b">...</div>

.Bgc\(\#fff\)\:h:hover {  background-color: #fff;}.C\(blue\)\:a:active {  color: blue;}.C\(\#0f0\)\:hover:hover {  color: #0f0;}.D\(n\) {  display: none;}

Мы видим, что Atomizer позволяет юзать как некоторые полные имена псевдоклассов, так и их короткие синонимы.


В документации написано, что можно испозовать псевдоэлементы.


Например: b для ::before


Но на практике, возможно, я как-то сильно тупил, и как ни пытался пробовать разные варианции, ни один пример не сработал.


Для D(n)::b я ожидал получить следующее:


.D\(n\)\:\:::before {  display: none;}

В MN же Мы можем всё тоже самое:


<div class="bgcF:h cBlue:a c0F0:hover dN::before">...</div>

.bgcF\:h:hover {  background-color: #fff;}.cBlue\:a:active {  color: blue;}.c0F0\:hover:hover {  color: #0f0;}.dN\:\:before::before {  display: none;}

Помимо этого, Мы имеем возможность задавать вообще любые псевдоклассы и севдоэлементы известные и неизвестные в CSS:


<div class="bgcF:hz cBlue::placeholder c0F0::-webkit-input-placeholder bgE:odd bt:first c:i">...</div>

.bgcF\:hz:hz {  background-color: #fff;}.cBlue\:\:placeholder::placeholder {  color: blue;}.c0F0\:\:-webkit-input-placeholder::-webkit-input-placeholder {  color: #0f0;}.bgE\:odd:nth-child(2n+1) {  background: #eee;}.bt\:first:first-child {  border-top-width: 0;}.c\:i::placeholder {  color: #000;}.c\:i:-ms-input-placeholder {  color: #000;}.c\:i::-moz-placeholder {  color: #000;}.c\:i::-webkit-input-placeholder {  color: #000;}

В MN Мы можем параметризовать псевдоклассы:


<div class="c:not[.anyClass] bg0A:not[tag[attr=value].class\:pseudo] c88F4:n[13] c01:n[3n+1]">...</div>

.c\:not\[\.anyClass\]:not(.anyClass) {  color: #000;}.bg0A\:not\[tag\[attr\=value\]\.class\\\:pseudo\]:not(tag[attr=value].class:pseudo) {  background: #000;  background: rgba(0,0,0,.67);}.c88F4\:n\[13\]:nth-child(13) {  color: #88f;  color: rgba(136,136,255,.27);}.c01\:n\[3n\+1\]:nth-child(3n+1) {  color: #000;  color: rgba(0,0,0,.07);}

В MN Мы также можем указать несколько псевдоклассов подряд:


<input  type="checkbox"  class="mh20:not[.anyClass]:n[5n+2]:c:h"/>

.mh20\:not\[\.anyClass\]\:n\[5n\+2\]\:c\:h:not(.anyClass):nth-child(5n+2):checked:hover {  margin-left: 20px;  margin-right: 20px;}

В MN можно задать собственный набор синонимов для псевдоклассов.
Пример:


mn.utils.extend(mn.states, {  foo: [':active'],  bar: ['.Bar_active', '.otherSelector'],  vasya: ['[data-name=vasya]'],});

<div class="cRed:foo cGreen:bar cBlue:vasya">...</div>

.cRed\:foo:active {  color: red;}.cGreen\:bar.otherSelector,.cGreen\:bar.Bar_active {  color: green;}.cBlue\:vasya[data-name=vasya] {  color: blue;}



Atomizer vs MN. Комбинаторы


Сравним кабинаторы.


"The underscore character ( _ )" в Atomizer:


<div class="foo">  <div class="foo_D(n)"></div></div>

Аналог в MN:


<div class="foo">  <div class="dN<.foo"></div></div>

"The right angle bracket character ( > )" в Atomizer:


<div class="foo">  <div class="foo>D(n)"></div></div>

Аналог в MN:


<div class="foo">  <div class="dN<1.foo"></div></div>

"The plus sign ( + )" в Atomizer:


<div class="foo"></div><div class="foo+D(n)"></div>

Аналог в MN:


<div class="foo"></div><div class="dN<.foo+"></div>

Помимо этого в MN комбинатор "соседний брат" ( + ) можно использовать в обратном направлении:


<div class="dN+.foo"></div><div class="foo"></div>

В MN можно использовать комбинатор "общий брат" ( ~ ):


<div class="foo"></div><div class="dN<.foo~"></div><div class="dN<.foo~"></div>

.foo~ .dN\<\.foo\~ {  display: none;}

И в обратном направлении:


<div class="dN~.foo"></div><div class="foo"></div><div class="foo"></div>

.dN\~\.foo~.foo {  display: none;}



Atomizer vs MN. Контекст


В Atomizer есть функциональность, называемая Context class, которая используется в случаях, когда необходимо установить некоторое поведение стилей при изменении селектора на родительском элементе.
Пример:


<div class="foo bar any">  <div class="double">    <div class="foo_D(n) bar:h_D(n) any_D(n):h any_double_D(n)">...</div>  </div></div>

.foo .foo_D\(n\), .any_double .any_double_D\(n\) {  display: none;}.bar:hover .bar\:h_D\(n\) {  display: none;}.any .any_D\(n\)\:h:hover {  display: none;}

На что я обратил внимание в этом примере:


  • нельзя использовать последовательность из нескольких родительских классов, что я и попытался сделать в этом примере таким образом any_double_D(n);
  • оказывается, стили в конечном CSS всё же частично группируются по какому-то принципу.

В MN, как, вероятно, некоторые могли догадаться из примеров выше, можно юзать полноценные селекторы, но для начала давайте рассмотрим, каким образом можно сделать тоже самое:


<div class="foo bar any">  <div class="double">    <div class="dN<.foo dN<.bar:h dN:h<.any dN<.double<.any">...</div>  </div></div>

.foo .dN\<\.foo,.bar:hover .dN\<\.bar\:h,.any .dN\:h\<\.any:hover,.any .double .dN\<\.double\<\.any {  display: none;}

При необходимости можно задать строгую глубину вложенности:


<div class="any">  <div class="double">    <div class="dN<1.double<1.any dN<2.any">...</div>  </div></div>

.any>.double>.dN\<1\.double\<1\.any,.any>*>.dN\<2\.any {  display: none;}

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


<div class="dN>2.double">  <div class="any">    <div class="double">...</div>  </div></div>

.dN\>2\.double>*>.double {  display: none;}

Можно комбинировать родительские селекторы с дочерними:


<div class="parent">  <div class="dN<.parent>2.double">    <div class="any">      <div class="double">...</div>    </div>  </div></div>

.parent .dN\<\.parent\>2\.double>*>.double {  display: none;}

<div class="dN>.double<.any">  <div class="any">    <div class="double">...</div>  </div></div>

.dN\>\.double\<\.any .any .double {  display: none;}

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


<div class="bgF2.active[data-name=Gena]:h active" data-name="Gena">...</div><div class="dN#feedback" id="feedback">...</div><div class="o50.disable disable">...</div>

.bgF2\.active\[data-name\=Gena\]\:h.active[data-name=Gena]:hover {  background: #fff;  background: rgba(255,255,255,.13);}.dN\#feedback#feedback {  display: none;}.o50\.disable.disable {  opacity: .5;}

Отличия:


  • в нотации MN строгий порядок.
    Фрагмент строки отвечающий за значение стиля, как основная суть нотации, всегда следует вначале, и только затем начиная с какого-нибудь служебного символа следует контекст, который уточняет к чему стили имеют отношение.
    Если существует такое понятие как "Венгерская нотация", то мне чисто ради наблюдения, хочется здесь назвать такой способ записи "Тюркской нотацией", ибо в тюркских языках суть слова всегда находится вналале и только затем следует множество уточняющих суффиксов и окончаний.
    В глобальном смысле это даже предельно технически правильный способ подачи почти любой информации, заключающийся в последовательном уменьшении неопределенности.
    Пример со временем:
    2020-02-02 22:22:22 каждое следующее значение в этой последовательности практически будет бесполезно без предшествующих;
    Аналогичный пример с адресом: Germany, 14193 Berlin, Kronberger Str. 12;


  • в MN можно использовать произвольные слелекторы.





Atomizer vs MN. Вычисляемые значения


В Atomizer есть возможность использования вычисляемых значений.
Для некоторых свойств Мы можем использовать дроби:


<div class="W(1/2) P(1/3) M(1/4) Start(1/5) T(1/6) Pstart(1/7) Miw(1/8)">...</div>

.W\(1\/2\) {  width: 50%;}.P\(1\/3\) {  padding: 33.3333%;}.M\(1\/4\) {  margin: 25%;}.Start\(1\/5\) {  left: 20%;}.T\(1\/6\) {  top: 16.6667%;}.Pstart\(1\/7\) {  padding-left: 14.2857%;}.Miw\(1\/8\) {  min-width: 12.5%;}

В MN Мы также можем использовать вычисляемые значения, в том числе и дроби:


<div class="w1/2 p1/3 m1/4 sl1/5 st1/6 pl1/7 wmin1/8">...</div>

.w1\/2 {  width: 50%;}.p1\/3 {  padding: 33.33%;}.m1\/4 {  margin: 25%;}.sl1\/5 {  left: 20%;}.st1\/6 {  top: 16.66%;}.pl1\/7 {  padding-left: 14.28%;}.wmin1\/8 {  min-width: 12.5%;}

Однако в Atomizer почему-то нельзя вычесть или сложить значение с дробью.
Я проверил:


<div class="W(1/2-10) P(1/3+5)">...</div>

.W\(1\/2-10\) {  width: 50%;}

В MN Мы можем вычитать и складывать значения с дробью, и это для некоторых случаяев весьма полезная возможность.
Пример:


<div class="w1/2-10 p1/3\+5">...</div>

.w1\/2-10 {  width: calc(50% - 10px);}.p1\/3\\\+5 {  padding: calc(33.33% + 5px);}

Замечания:


  • здесь " + " это с служебный символ-комбинатор, как и в обычном CSS, поэтому он экранируется слэшем (\).



Atomizer vs MN. Установка цветов


В Atomizer для указания цвета используются шестнадцатеричные цвета из 3-х или 6-ти символов с префиксом # в качестве идентификатора значения.


Шестнадцатеричные значения для цветов должны быть написаны в нижнем регистре (т.е., #ccc, а не #CCC).


Для установки коэффициента непрозрачности к шестнадцатеричному значению необходимо добавлять точку(.) с десятичным значением.


Например:


<div class="C(#fff) Bdc(#ff0000) Bgc(#00ff00.5)">...</div>

.C\(\#fff\) {  color: #fff;}.Bdc\(\#ff0000\) {  border-color: #ff0000;}.Bgc\(\#00ff00\.5\) {  background-color: rgba(0,255,0,.5);}

В MN для указания цвета используются шестнадцатеричные цвета от 0 до 8-ми символов с коэффициентом непрозрачности включительно, но для коэффициента непрозрачности дополнительно имеется альтернативный способ: использовать точку(.) с десятичным значением.


Например:


<div class="c cFFF bcFF0000 bgc00FF00\.5 сFF00008 сFF000080 cF bgc08 bgc0\.5 bgc1234 bgc12348">...</div>

.c {  color: #000;}.cFFF {  color: #fff;}.bcFF0000 {  border-color: #f00;}.bgc00FF00\\\.5 {  background-color: #0f0;  background-color: rgba(0,255,0,.5);}.cFF00008 {  color: #f00;  color: rgba(255,0,0,.53);}.cFF000080 {  color: #f00;  color: rgba(255,0,0,.5);}.cF {  color: #fff;}.bgc08 {  background-color: #000;  background-color: rgba(0,0,0,.53);}.bgc0\\\.5 {  background-color: #000;  background-color: rgba(0,0,0,.5);}.bgc1234 {  background-color: #123;  background-color: rgba(17,34,51,.27);}.bgc12348 {  background-color: #123;  background-color: rgba(17,34,51,.28);}

Замечания:


  • здесь " . " это с служебный символ, с помощью которого указываются классы, как и в обычном CSS, поэтому он экранируется слэшем (\).
  • Вы могли обратить внимание на то, что ко всем генерируемым цветам с коэффициентом непрозрачности дополнительно добавляется значения без альфа-канала это полифил для браузеров, которые не поддерживают коэффициент непрозрачности.
    Это поведение можно отключить в настройках MN при помощи установки опции altColor: 'off'



Градиентная цветовая заливка в MN


В MN Мы имеем два похожих пресета, которые, как известно, на практике часто могут быть взаимозаменяемыми: bgc и bg.
Пример:


<div class="bg48A">...</div><div class="bgc48A">...</div>

.bg48A {  background: #48a;}.bgc48A {  background-color: #48a;}

Однако с bg Мы также можем легко и лакончино делать градиенты, путем указания последовательности цветов через знак минуса (-):


<div class="bg0-F">...</div><div class="bgF00-0F0-00F">...</div>

.bg0-F {  background: #000;  background: linear-gradient(180deg,#000 0%,#fff 100%);}.bgF00-0F0-00F {  background: #f00;  background: linear-gradient(180deg,#f00 0%,#0f0 50%,#00f 100%);}

Имеется возможность устанвавливать направление градиента:


<div class="bg0-F_g45">...</div><div class="bg0-F_g90">...</div>

.bg0-F_g45 {  background: #000;  background: linear-gradient(225deg,#000 0%,#fff 100%);}.bg0-F_g90 {  background: #000;  background: linear-gradient(270deg,#000 0%,#fff 100%);}

Помимо линейных градиентов, Мы можем использовать радиальные градиенты:


<div class="bg0-F_r">...</div><div class="bg0-F_r_closestSide">...</div><div class="bg0-F_r_ellipse_at_top">...</div>

.bg0-F_r {  background: #000;  background: radial-gradient(circle,#000 0%,#fff 100%);}.bg0-F_r_closestSide {  background: #000;  background: radial-gradient(closest-side,#000 0%,#fff 100%);}.bg0-F_r_ellipse_at_top {  background: #000;  background: radial-gradient(ellipse at top,#000 0%,#fff 100%);}



Atomizer vs MN. Несколько значений


В Atomizer есть возможность указывать несколько значений, разделенных запятыми, когда это поддерживается соответствующими свойствами, например:


<div class="Bgp(20px,50px)">...</div>

.Bgp\(20px\,50px\) {  background-position: 20px 50px;}

С MN получить аналогичный результат можно похожим образом:


<div class="bgp20px_50px">...</div>

.bgp20px_50px {  background-position: 20px 50px;}



Atomizer vs MN. Идентификатор брейкпоинта (breakpoint identifier). Медиа-запросы


В Atomizer можно устанавливать брейкпоинт к правилу, путем добавления суффикса к записи. Брейкпоинт указывает, что это правило вступит в силу только в рамках медиа-запроса.


Значения имени и длины каждой точки останова определяются в объекте конфигурации:


{  // ...  breakPoints: {    'sm': '@media(min-width:750px)', // breakpoint 1    'md': '@media(min-width:1000px)', // breakpoint 2    'lg': '@media(min-width:1200px)', // breakpoint 3    // ...  },  // ...}

Используются эти брейкпоинты следующим образом:


<div class="W(50%)--sm W(33%)--md W(25%)--lg">...</div>

@media(min-width:750px) {  .W\(50\%\)--sm {    width: 50%;  }}@media(min-width:1000px) {  .W\(33\%\)--md {    width: 33%;  }}@media(min-width:1200px) {  .W\(25\%\)--lg {    width: 25%;  }}

В MN также можно прекрасно устанавливать брейкпоинты, путем добавления суффикса к записи:


<div class="w50%@m w33%@d w25%@d2 w1/5@ie w1/6@android cr@mouse">...</div>

@media (max-width: 992px) {  .w50\%\@m {    width: 50%;  }}@media (min-width: 992px) {  .w33\%\@d {    width: 33%;  }}@media (min-width: 1200px) {  .w25\%\@d2 {    width: 25%;  }}.ie .w1\/5\@ie {  width: 20%;}.android .w1\/6\@android {  width: 16.66%;}@media (pointer: fine) and (hover: hover) {  .cr\@mouse {    cursor: pointer;  }}

Здесь Мы имеем возможность для брейкпоинтов использовать как медиа-запросы, так и родительские селекторы.


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


Также возможность использования родительских селекторов в качестве брейкпоинтов, вероятно, могла бы пригодиться Нам для организации каких-нибудь контекстов или пространств имен.


Пример конфигурирования брейкпоинтов:


module.exports = (mn) => {  const {media} = mn;  // media-queries  media.m = {    query: '(max-width: 992px)',    priority: 0,  };  media.m2 = {    query: '(max-width: 768px)',    priority: 1,  };  media.d = {    query: '(min-width: 992px)',    priority: 2,  };  media.d2 = {    query: '(min-width: 1200px)',    priority: 3,  };  media.mouse = {    query: '(pointer: fine) and (hover: hover)',    priority: 4,  };  // ...  // user agents  media.mozilla = {    selector: '.mozilla'  };  media.webkit = {    selector: '.webkit'  };  media.ie = {    selector: '.ie'  };  media.iphone = {    selector: '.iphone'  };  media.android = {    selector: '.android'  };  // ...};

Если Мы используем в нотации брейкпонт, который нигде не предустановлен, то в CSS получим значение медиа-запроса, которое непосредственно указали в записи:


<div class="w50%@print w50%@any">...</div>

@media print {  .w50\%\@print {    width: 50%;  }}@media any {  .w50\%\@any {    width: 50%;  }}

Также помимо предустанавливаемых брейкпоинтов в нотации MN можно использовать
выражения:


<div class="w50%@768 w50%@768- w50%@768-992">...</div><div class="w50%@768-992x100-200 w50%@x100-200">...</div><div class="w50%@x100 w50%@x100-">...</div>

@media (max-width: 768px) {  .w50\%\@768 {    width: 50%;  }}@media (min-width: 768px) {  .w50\%\@768- {    width: 50%;  }}@media (min-width: 768px) and (max-width: 992px) {  .w50\%\@768-992 {    width: 50%;  }}@media (min-width: 768px) and (max-width: 992px) and (min-height: 100px) and (max-height: 200px) {  .w50\%\@768-992x100-200 {    width: 50%;  }}@media (min-height: 100px) {  .w50\%\@x100- {    width: 50%;  }}@media (min-height: 100px) and (max-height: 200px) {  .w50\%\@x100-200 {    width: 50%;  }}@media (max-height: 100px) {  .w50\%\@x100 {    width: 50%;  }}

В выражениях брейкпонтов Мы можем указывать приоритет медиа-запроса, по которому каскадные блоки отсортировываются в конечном CSS:


<div class="w50%@768-992^5 w50%@768^1 w50%@992^3">...</div>

@media (max-width: 768px) {  .w50\%\@768\^1 {    width: 50%;  }}@media (max-width: 992px) {  .w50\%\@992\^3 {    width: 50%;  }}@media (min-width: 768px) and (max-width: 992px) {  .w50\%\@768-992\^5 {    width: 50%;  }}



Minimalist Notation. Управление приоритетами стилей


В MN имеется специальная удобная возможность управления приоритетами стилей. Мы можем повысить приоритет стилей путем добавления суффикса * со значением приоритета в конец записи нотации, например:


<div class="cF*2 c0*3 cF00.active*2">...</div>

.cF\*2.cF\*2 {  color: #fff;}.c0\*3.c0\*3.c0\*3 {  color: #000;}.cF00\.active\*2.cF00\.active\*2.active {  color: #f00;}

Таким образом, приоритет или, другими словами, специфичность стилей увлеличивается за счёт повторения в каскаде генерируемого CSS комбинации класса с самим собой столько раз, сколько Мы указываем в нотации.




Minimalist Notation. Селектор подстроки


С MN можно позволить себе сокращать имена классов в нотации.


Иногда достаточно только фрагмента имени:


<div class="SomeBlock">  <div class="bgF00>1.*_active">    <div class="SomeBlock__SomeElement SomeBlock__SomeElement_active">      ...    </div>    <div class="SomeBlock__SomeElement">      ...    </div>    <div class="SomeBlock__SomeElement SomeBlock__SomeElement_active">      ...    </div>  </div></div>

.bgF00\>1\.\*_active>[class*=_active] {  background: #f00;}

Например, в приложении на React Мы используем компоненты библиотеки Material-UI, которые легально кастомизируются через JSS так:


const React = require('react');const {render} = require('react-dom');const {withStyles} = require('@material-ui/core/styles');const TextField = require('@material-ui/core/TextField').default;const TextFieldGreen = withStyles({  root: {    '& label.Mui-focused': {      color: 'green',    },    '& .MuiOutlinedInput-root': {      '& fieldset': {        borderColor: 'red',      },      '&:hover fieldset': {        borderColor: 'yellow',      },      '&.Mui-focused fieldset': {        borderColor: 'green',      },    },  },})(TextField);function App() {  return (    <TextFieldGreen      label="Label"      required      defaultValue="Value"    />  );}

С помощью MN ради кастомизации элементов Нам придется заморачиваться меньше:


const React = require('react');const {render} = require('react-dom');const TextField = require('@material-ui/core/TextField').default;function TextFieldGreen(props) {  return (    <TextField      {...props}      className={`        cGreen>label.*-focused        bcRed>.*OutlinedInput-root>fieldset        bcYellow>.*OutlinedInput-root:h>fieldset        bcGreen>.*OutlinedInput-root.*-focused>fieldset      ` + (props.className || '')}    />  );}function App() {  return (    <TextFieldGreen      label="Label"      required      defaultValue="Value"    />  );}

Если Нам понадобится кастомизировать значительно большее количество атрибутов, то подход JSS будет разительно более громоздким, чем подход MN.


Так в Нашем случае выглядит сгенерированный CSS:


.cGreen\>label\.\*-focused label[class*=-focused] {  color: green;}.bcRed\>\.\*OutlinedInput-root\>fieldset [class*=OutlinedInput-root] fieldset {  border-color: red;}.bcYellow\>\.\*OutlinedInput-root\:h\>fieldset [class*=OutlinedInput-root]:hover fieldset {  border-color: yellow;}.bcGreen\>\.\*OutlinedInput-root\.\*-focused\>fieldset [class*=OutlinedInput-root][class*=-focused] fieldset {  border-color: green;}

Если возникает необходимость, селекторы подстрок можно использовать в странных и диковинных случаях:


<ul class="cRed>#*menu-item-">  <li id="menu-item-1">...</li>  <li id="menu-item-2">...</li>  <li id="menu-item-3">...</li>  <li id="menu-item-4">...</li>  ...</ul>

.cRed\>\#\*menu-item- [id*=menu-item-] {  color: red;}



Заключение


Как можно видеть, MN больше ориентирован на методологию Atomic / Functional CSS.


Сейчас в ходу Scoped styles, JSS, PostCSS с BEM. Возможно и MN станет популярным где-то в свои 2050-е годы.


После MN Вам уже не захочется возвращаться к прежнему, и использование каких-либо иных классических способов покажется довольно утомительным и нелепым занятием. Ваши плечи будут тяжелеть от просьб написать CSS руками, ибо это будет также странно, как носить от ручья воду в бидонах, имея при этом под носом чистую воду из крана хотя, конечно, подобные расточительные глупости вполне себе в норме для Нашего общества, но тем не менее...




Ссылки


Библиотека MN


MN get started example

Подробнее..

Категории

Последние комментарии

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru