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

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

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

Источник: habr.com
К списку статей
Опубликовано: 12.07.2020 14:15:44
0

Сейчас читают

Комментариев (0)
Имя
Электронная почта

Css

Javascript

Atomic css

Functional css

Inline styles 2.0

Mn

Preprocessor

Css zero

Responsive

Adaptive

Категории

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

  • Имя: Макс
    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