Less.js: Сохранение селектора в переменную

Созданный на 20 апр. 2017  ·  50Комментарии  ·  Источник: less/less.js

У нас есть такое решение:

// LESS
.selector {
    <strong i="6">@r</strong>: ~'.selector';

    &--mode {
        @{r}__block {
            prop: value;
         }
    }
}

// CSS
.selector--mode .selector__block {
  prop: value;
}

Предлагаю добавить функцию: написать <strong i="9">@r</strong>: &; вместо <strong i="11">@r</strong>: ~".selector"; чтобы получить текущий селектор и сохранить его в любой переменной.

Примеры:

// LESS
.selector {
  <strong i="15">@r</strong>: &; // .selector
}

.selector {
  &__inner {
    <strong i="16">@r</strong>: &; // .selector__inner
  }
}

.selector {
  &--modification &__inner {
    <strong i="17">@r</strong>: &; // .selector--modification .selector__inner
  }
}
feature request medium priority needs decision research needed

Все 50 Комментарий

Любопытно, что я был абсолютно уверен, что такой запрос уже существует. Судя по всему, это не так.
(Хотя очевидно, что эта идея и раньше появлялась во многих билетах: # 1174, https://github.com/less/less.js/issues/1075#issuecomment-16891103 и т. Д.)
Так что пусть будет так, я думаю.


Кстати, на всякий случай (и чтобы собрать несколько примеров использования, чтобы подумать о возможных конфликтах импл. / Синтаксиса):
Как вы собираетесь его использовать? Я подозреваю, что во многих случаях это не сработает так, как вы ожидаете, из-за ленивой оценки. Например:

a {
    <strong i="11">@r</strong>: &;
    b {
        something: @r;
    }
}

приведет к:

a b {
    something: a b; // not a!
}

Потому что значение @r действительно оценивается внутри a b (т.е. там, где оно используется, а не в той точке, в которой вы его определяете).
(Так что я подозреваю, что в некоторых случаях использования для этого может потребоваться какая-то другая языковая конструкция, а не просто переменная. И многие другие связанные варианты использования ранее рассматривались как тема # 1075).

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

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

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

@rjgotten

Да, я предполагаю, что мы обсуждали некоторую selector ранее (псевдо, потому что обычный синтаксический анализ функции в любом случае не может обрабатывать все эти комбинаторы, специфичные для селектора), а затем потому, что это псевдофункция (т.е. выделенный тип, такой как Url ) было бы не проблема заставить его вытащить контекст своего определения внутри (если я правильно помню, DRs делают именно так).
Думаю, что-то вроде <strong i="10">@foo</strong>: selector(&); может помочь. Однако тогда возникает следующая небольшая проблема:

a {
    <strong i="13">@var</strong>: selector(x, #y & .z);

    b {
        @{var} { // ? is it regular & or "saved-context-&" ?
            // ...
        }
    }
}

Так что, возможно, может потребоваться иное, чем & operator / keyword. (Или, может быть, просто выделенная псевдофункция, например current-selector() ... Хм, теперь это подводит меня к идее кодирования универсального типа PseudoFunction чтобы не загрязнять API всеми крошечными вещами, ох! :).

Я знаю, что многие не решаются добавлять что-то новое в язык, но спецификатор селектора может оказаться полезным. Мне нравится | , хотя это часть синтаксиса селектора CSS @namespace . Однако не похоже, что | разрешено _запустить_ селектор, поэтому он не должен конфликтовать. Я использую его, потому что он напоминает мне об «абсолютном значении» Math, что кажется неопределенно подходящим, и потому что это просто. Просто мысль, вдохновляющая на разговор.

a {
  <strong i="10">@var</strong>: |x, #y & .z|; // starting w/ `|` means selector, in current context, ended w/ another `|`
  b {
    @{var} {
      //...
    }
  }
}

(Фактически, это могло быть использовано для обозначения того, что _any_ var должны быть немедленно обработаны и сохранены, или что-то еще? Но это похоже на _way_ завышение области видимости.)

это обычный & или saved-context-& ?

Я бы сказал, что контекст селектора должен быть захвачен на сайте, на котором вызывается псевдофункция selector() и & следует оценивать в контексте _that_, и конечный результат должен быть назначен этому новому типу узла дерева Selector .

Когда _любая_ переменная, содержащая узел дерева типа Selector интерполируется в селектор, как в случае с использованием @{var} в примере, результирующий селектор должен быть построен таким же образом как если бы в селекторе присутствует интерполятор & , т.е. не присоединяйтесь к селекторам с префиксом на один уровень вложенности.

Причина в том, что оба являются захваченными селекторами: selector() - это захваченный пользователем, тогда как & - всегда присутствующий и фиксируемый «родительский» селектор.

Затем, если пользователю требуется интерполяция захваченного узла Selector вместе с контекстом селектора _current_, он может указать это явно. Например, & @{var} { ... }

В заключение

a {
    <strong i="24">@var</strong>: selector(x, #y & .z);

    b {
        @{var} { ... }
    }
}

должен генерировать

x, #y a .z { ... }

В то время как

a {
    <strong i="31">@var</strong>: selector(x, #y & .z);

    b {
        & @{var} { ... }
    }
}

должен генерировать

a b x,
a b #y a .z { ... }

Хм, @{var} vs. & @{var} выглядит довольно искусственно, это просто не то, как эти вещи работают в Less. ... { & div ... и ... { div ... всегда были равными операторами. Кроме того, даже не считая этого, что мне делать, если мне нужно a b x, #y a b .z с x, #y * .z определенным в другом месте?

Я не поклонник функционально-подобной конструкции для селекторов. Однако я поддерживаю возможность ссылаться, изменять или переносить (назначать переменной и повторно использовать) унаследованные селекторы.

Однако просто чтобы убедиться, насколько это вариант # 1075 (таргетинг на родительские селекторы) или возможный конфликт с https://github.com/less/less-meta/issues/16#issuecomment -292679320 (назначение один селектор для переменной)? Или это отличается от миксинов с псевдонимом, потому что это список селекторов, а не один оцениваемый селектор (или миксин), и на выходе получается список селекторов, а не оцениваемый набор правил? Я предполагаю, что эта функция отличается; Я просто хочу убедиться, что все это движется в одном направлении.

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

Можно представить себе такую ​​функцию, как extract(list,index) которая будет обновлена, чтобы иметь возможность также извлекать компоненты селектора из списка селекторов и аналогичные улучшения для облегчения работы с селекторами, чтобы пользователи могли легко манипулировать ими интересными способами. Например, для компонентов, которые следуют определенным схемам именования, таким как БЭМ.

Например, учитывая миксин

.my-bem-component(<strong i="10">@a</strong>, @b) {
  // Component will only ever be constructed on the first selector in
  // a list, for simplicity.
  <strong i="11">@selectors</strong> : selector(&);
  <strong i="12">@selector</strong>  : extract(<strong i="13">@selectors</strong>, 1);

  // Generate a clean block name, cleared of modifiers.
  // Grabs e.g. "bar" from ".foo > .bar--baz"
  @block-name : replace(<strong i="14">@selector</strong>, "\.([^\.\s]+)--\S+$", "$1" );

  // Generate the modifier name and generate different CSS for
  // BEM classes that have one.
  // Grabs e.g. "baz" in ".foo > .bar--baz"
  @mod-name : replace(<strong i="15">@selector</strong>, "\.+--(\S+)$", "$1" );

  .generate-block();
  // When @mod-name matches <strong i="16">@selector</strong>, no replacement has
  // occured and we are infact in the situation where we have no
  // BEM modifier and generate the 'base' component.
  .generate-block() when (@mod-name = "@{selector}") {
    @{selector} {
      prop-a : @a;
    }
    @{selector}__element {
      prop-b : @b;
    }
  }

  .generate-block() when (default()) {
    @{selector} {
      prop-a : @a;
    }
    @{selector} > .@{block}__element {
      prop-b : @b;
    }
  }
}

Следующие Меньше

.block {
  .my-bem-component(foo, bar);
}
.block--caps {
  .my-bem-component(FOO, BAR);
}

генерирует CSS

.block {
  prop-a : foo;
}
.block__element {
 prop-b : bar;
}
.block--caps {
  prop-a : FOO;
}
.block--caps > .block__element {
  prop-b : BAR;
}

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

Что касается:

возможный конфликт с less / less-meta # 16 (комментарий) (назначение одного селектора переменной)

Лично я предполагаю следующее поведение:
«Тривиальные» значения селектора (например, .mixin , .ns.mixin , #foo .bar , baz т. Д., К счастью, это охватывает все, что можно использовать / определить как миксин / функция ) назначаются переменной (или передаются как параметры функции) напрямую . Т.е. на самом деле это у нас уже есть:

<strong i="15">@var</strong>: .ns.mixin; // OK, its just Anonymous value (representing an arbitrary identifier) 
function(.mixin); // error: TODO 

^ Это (по сути) не имеет @var(...) или @var[...] заявления
(В общем случае логическим соглашением было бы забыть, что идентификаторы миксинов являются (внутренне представлены как) селекторами, но всегда думать о них как об идентификаторах только с точкой или префиксом # и такими вещами, как .ns > .mixin to со временем исчезнут как ненужные и бесполезные :)

В то время как сложные или «настоящие» селекторы требуют псевдофункции selector из-за неоднозначности синтаксиса / парсера. Т.е. такие вещи как:

  • <strong i="29">@var</strong>:foo>bar <- селектор и (потенциально) логическое выражение
  • <strong i="32">@var</strong>:.1+.2; <- арифметическое выражение и допустимый селектор
    (и т. д. хорошо, просто вспомните все конкретные символы селектора - почти каждый конфликтует с чем-то в контексте синтаксического анализа значений, и это становится еще более драматичным, когда указанные выше значения потенциально передаются функции / миксину в качестве параметров на месте, например, следующее просто невозможно для поддержки без selector() :
    less: some-function(abc, selector(#foo .is :not(> bar)[baz="qux"], abc), selector(bla), 42); // ^ remove `selector()` and try to parse

Я не поклонник функционально-подобной конструкции для селекторов.

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


(Все вышеперечисленное не означает, что значение, возвращаемое selector() не может использоваться в качестве вызываемого объекта, например, @var() , возможно, но это было бы просто ненужным / бесполезным, поэтому вряд ли стоит беспокоить).

@rjgotten

Можно представить себе такую ​​функцию, как extract(list,index) которая будет обновлена, чтобы иметь возможность также извлекать селектор

Конечно, мы могли бы настроить функции для работы со строками, предполагая, что такая строка может содержать какой-либо селектор, но это означает, что каждая такая функция (а не только extract ) должна быть обновлена ​​/ настроена / изменена. Противоположный подход был бы более эффективным / менее обременительным. Т.е. это либо выделенная функция преобразования selector-string->values , ИЛИ даже возврат правильной структуры узлов напрямую с помощью selector (в любом случае самая сложная часть заключается в том, как упаковывать / распаковывать комбинаторы селекторов при каждом использовании -кейс может предпочесть другое представление).

(Обратите внимание, что сама функция интерполяции селектора все равно должна преобразовать @{var} в правильный формат в конце концов, поэтому на самом деле не имеет значения, в каком формате входит значение этой переменной - будь то строка, анонимность или что-то еще структура узлов - большая часть хитростей преобразования остается прежней).

@block-name : replace(<strong i="17">@selector</strong>, "\.([^\.\s]+)--\S+$", "$1" );

Честно говоря, это похоже на реинкарнацию «встроенного JavaScript и хакерства, подобного LessHat», не может запретить, но будет агрессивно выступать против.
(Не считая того, что пример довольно неудачный <- подсчитайте строки) Я бы предпочел предложить какую-нибудь вещь less-plugin-bem-selectors (где вы можете просто иметь функцию get-block-name , кстати. Даже без & feature) вместо таких уродливых регулярных выражений (подход «Использование препроцессора CSS в качестве произвольного текстового процессора» в конечном итоге сильно проиграет PostCSS-подобным вещам).

И возвращаясь к & против context-saving-& , пока, боюсь, у меня нет идей лучше, чем специальный флаг для функции, например selector(..., lazy or not) , или даже два отдельные функции. Или используя other-than-&-keyword (например, ). Просто не могу найти безопасного метода для автоматического разрешения неоднозначности точки оценки.

Я бы предпочел предложить какую-нибудь less-plugin-bem-selectors вещь

Абсолютно. Извлечение на основе регулярных выражений было просто для того, чтобы предоставить пример, не связанный с пользовательскими функциями. ;)

Я не поклонник функционально-подобной конструкции для селекторов.

Кроме того, если вы имеете в виду только то, как это выглядит ... Конечно, это может быть какая-то другая конструкция, например ⁞#foo:not(.bar)⁞ , но вы знаете, что у нас уже закончились бесплатные символы. Таким образом, синтаксис псевдофункции предлагается только потому, что у нас уже есть такая концепция с url любом случае (поэтому нет необходимости думать о том, что новая концепция может или сломается).

А теперь самое интересное.

Я создал быструю и грязную реализацию плагина функции current-selector (просто чтобы увидеть, насколько это может быть раздувание, ожидая, что, конечно, это не может быть очень полезно из-за var lazy-Assessment), и знаете что? Этот базовый пример:

div {
    <strong i="9">@x</strong>: current-selector();
    span {
        r: @x; // -> div
    }
}

приводит к r: div :)
Не знаю точно, какая часть кода компилятора обрабатывает это конкретное поведение, но вот более сложный пример, иллюстрирующий волшебство:

div {
    <strong i="15">@x</strong>: current-selector();     // [1]
    <strong i="16">@y</strong>: current-selector() @v;  // [2]
    <strong i="17">@z</strong>: current-selector(@v);   // [3]
    <strong i="18">@v</strong>: whatever;
    span {
        1: @x; // div
        2: @y; // div span
        3: @z; // div span
        4: current-selector();  // [4] div span
    }
}

Там только операторы [2] и [3] вызываются дважды (т.е. фактически лениво вычисляются), а [1] - нет (очевидно, потому что значение не содержит никаких переменных, хотя опять же, я не знаю, было ли это намеренным или просто побочным эффектом некоторого кеширования, или это может быть удачная ошибка в моем коде - например, эта строка может вызвать такой побочный эффект для этого кеширования - но тогда это не ясно почему на него влияют дополнительные переменные - т. е. необходимы дополнительные исследования).


То есть, версия context-saving-& на основе плагина кажется возможной (за исключением того, что, конечно, вместо <strong i="29">@var</strong>: & вы будете использовать что-то вроде <strong i="31">@var</strong>: current-selector() ), хотя функция не должна иметь какие-либо параметры, иначе он будет вычисляться лениво (если передается переменная) - это печально, так как я изначально планировал, что их будет четыре :).
Довольно оскорбительно, но может служить обходным решением / полифиллом. Более реальный пример также работает по желанию:

div#zoo {
    <strong i="35">@x</strong>: current-selector();
    span {
        <strong i="36">@y</strong>: replace(<strong i="37">@x</strong>, div, body);
        r: @y; // OK, body#zoo
        @{y} { 
        // ^ not very useful this way (except maybe bem stuff) since you can't remove div
            color: red;
        }
    }
}

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

@ семь фаз-макс
Любить это.

Даже если ленивое вычисление в настоящее время бросает вызов, когда присутствует аргумент параметра, _that_, по-видимому, можно обойти для «реальной» реализации.

Кроме того, если вы имеете в виду только то, как это выглядит ... Конечно, это может быть какая-то другая конструкция, например ⁞ # foo: not (.bar) ⁞, но вы знаете, что у нас уже закончились свободные символы.

Справедливо. Я не особо разбирался в этом с точки зрения использования, и у меня нет лучших идей. Думаю, в этом было что-то особенное, но, может, и нет. Я знаю, что в какой-то момент была дискуссия о $() , но в итоге мы присвоили $ . Кстати, разве это не будет selectors() а не selector() ? Разве он (как и & ) не может содержать любое количество селекторов?

И похоже, что selector(&) имеет больше смысла, чем current-selector() . То есть: «составить список селекторов из объекта X, будь то & или строка». Каким бы ни был окончательный синтаксис, кажется, что в качестве аргумента он принимает & .

И похоже, что selector(&) имеет больше смысла, чем current-selector()

Это разные вещи. current-selector - это просто функциональный вариант & (поскольку последний не поддерживается парсером). В то время как selector(...) - это патч для парсера, поддерживающий произвольный селектор (включая & ).


Насчет selectors - ну так и есть. Но поскольку это 99% случаев использования одного селектора, я полагаю, что форма множественного числа будет казаться менее очевидной для большинства пользователей (в большинстве случаев они обычно называют h1, h2, h3 {} как селектор и продолжают говорить о меньшем родительском селекторе (даже если это селектор s ) :) Так зачем?

Ах хорошо.

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

Довольно весело; термин «селекторы» во множественном числе даже не является официальным способом обозначения набора, разделенного запятыми. Я считаю, что строго правильная терминология для формы множественного числа - это _selector list_.

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

Я считаю, что строго правильная терминология для формы множественного числа - это список селекторов.

Да, вчера я также искал w3c, это «группа селекторов», «список селекторов» и т. Д., Ничего особенного, как странное «Селектор - это цепочка из одной или нескольких последовательностей простых селекторов, разделенных комбинаторами», они также есть там :) Просто форма "селекторы" там в основном используется для описания вещи "типы селекторов".

«Селектор - это цепочка из одной или нескольких последовательностей простых селекторов, разделенных комбинаторами»

И для тех, кто думает, что это может относиться к спискам, разделенным запятыми: это не так. Полная форма этой цитаты должна быть такой: «_complex_ селектор - это цепочка из одной или нескольких последовательностей простых селекторов, разделенных комбинаторами».

У спецификаций CSS есть еще одна проблема, когда обобщенная форма «селектора» используется в основном для обозначения того, что в спецификациях официально называется комплексными селекторами. Сложные селекторы - это простые селекторы, например tag ; #id ; .class ; [attr] ; и т. д., связанные через комбинаторы, например > ; + ; ~ и т. Д.

Что-то вроде ul > li называется сложным селектором.


ВНИМАНИЕ, следующее будет напыщенной речью:

К сожалению, спецификации CSS - это трясина непоследовательной и плохо названной терминологии. Чем дальше вы идете назад, тем хуже становится. Не помогает то, что множество модулей CSS3 продолжают ссылаться на модули CSS 2.1 или что новые модули CSS3 были определены путем дословного копирования их старой документации CSS 2.1. Тем не менее, спецификации для селекторов и модель визуального форматирования являются худшими нарушителями; столько неоднозначной, похожей по звучанию или просто плохо названной терминологии.

Возьмем, к примеру, что-то гораздо менее тривиальное, чем ul > li , например [*|attr^="value" i] . Последний технически классифицируется как простой селектор. (Да, действительно.)

Несколько лет назад мне пришлось попытаться объяснить части последней спецификации модели визуального форматирования одному из моих коллег, более ориентированных на дизайн. Я думаю, что несколько предохранителей действительно сгорели в _об__ наших мозгах, когда мы просматривали отрывки, относящиеся к концепции линейных боксов, и это было даже не худшей частью. (Если вы не особо цените свое здравомыслие, попробуйте войти в волшебную ла-ла-страну, которая представляет собой модель форматирования таблиц.)

Многочисленные радости документации по проектам с открытым кодом ...

Возьмем, к примеру, что-то гораздо менее тривиальное, чем ul > li , например [*|attr^="value" i] . Последний технически классифицируется как простой селектор.

Для меня это действительно имеет смысл, лол, просто потому, что в нем не используется комбинатор. Это точно следует определению. Тот факт, что в нем используется много символов, не делает его более «сложным». ul > li является сложным, потому что он включает два набора запросов, то есть запрос всех элементов, соответствующих li а затем обход дерева от каждого, чтобы определить, какие из них содержатся в ul . Последний проверяет отдельные элементы только один раз. Это один запрос, так что это простой селектор.

термин «селекторы» во множественном числе даже не является официальным способом обозначения набора, разделенного запятыми. Я считаю, что строго правильная терминология для формы множественного числа - это список селекторов.

Правильно, вы правы. «Селекторы» - это на самом деле просто определенные биты, которые позволяют вам выбирать элементы, но ul > li > .title - это единственное число «селектор». Так что я думаю, что selector() на самом деле, возможно, семантически ближе.

@ семь фаз-макс

Только что столкнулся с другой незначительной проблемой с функцией плагина quick-n-dirty: он неправильно обрабатывает доступ из миксина с пространством имен. Пространства имен представляют собой обычный фрейм типа Ruleset поэтому их имя добавляется в селекторы.

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


[РЕДАКТИРОВАТЬ]
Чтобы заставить его работать, нужно проверить, является ли один из фреймов в стеке контекста функции MixinDefinition и если он _is_, пропустить следующие x фреймы в этом стеке, где x равно количеству кадров в стеке MixinDefinition .

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

Убран ярлык "устаревший". Это все еще хороший вопрос для изучения.

Может, current-selector() не так уж и плох. Хотя, для ясности, на самом деле это будет current-selectors() . Но это все еще немного многословно. Думаю, я был бы в большей степени, если бы мы могли придумать более краткое имя функции для «захвата &».

имя функции для «захвата &», более краткое.

Просто назовите его &() . В конце концов, это концептуально не что иное, как получатель того, что находится в & .
Например

.rule {
  <strong i="11">@selectors</strong> : &();
}

🤔
Да, все должно быть хорошо. Есть возражения?

Я попытаюсь подвести итог, чтобы понять, понимаю ли я предлагаемую функцию:

Новая функция &() возвращает то, что & выводит в текущем контексте, учитывая это.

.component { // I only write "component" once!  Much concise, such DRY!
  <strong i="9">@this</strong>: &();

  /* base styles */

  &_child {
    /* styles for the child */
  }

  &-variant { // component-variant styles all together, and inside the `.component` block
    /* nothing too schmancy so far */
    @{this}_child {
      /* IT'S MAGIC! */
    }
  }
}

И все это выведет.

.component {
  /* base styles */
}
.component_child {
  /* styles for the child */
}
.component-variant {
  /* nothing too schmancy so far */
}
.component-variant .component_child {
  /* IT'S MAGIC! */
}

Потому что это потрясающе, и мне это нравится.

Если подумать об этом подробнее, я думаю, что наиболее убедительным для меня (после первого прохода; остановите меня, если я слишком чокнутый) будет возможность иметь стандартизированный компонентный "блочный" стиль (набор правил). В принципе, я почти надеюсь, что вместо простого сохраненного значения строки селектора функция будет отображаться в _ " & , но в области видимости переменная была определена в" _, что позволило бы использовать этот стиль разработки. для компонента (я назову это Поведение A ):

.component{ <strong i="8">@this</strong>:&();
  /* default styles */
  @{this}_child {
  // ↑ The crucial difference: `@{this}` here behaves _like `&`_, **NOT** like `.component`
    /* child default styles */
  }
}

Тогда я мог бы сказать «используйте везде @this вместо & ».

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

.foo { <strong i="16">@and</strong>: &();
  @{and} {
    /*stuff meant to live under selector `.foo.foo` */
  }
}

Потому что текущий способ сделать это _ намного_ более кратким (и читабельным, когда & станет ясным в вашем словаре).

.foo {
  && {
    /*stuff meant to live under selector `.foo.foo` */
  }
}

Есть ли убедительные доводы (помимо сложности реализации) в пользу поведения B по сравнению с поведением A?

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


TL; DR: Я голосую за то, чтобы &() было динамическим, что означает, по сути, _ " & , но как бы вложенное здесь, а не более глубокое" _, вместо того, чтобы возвращать статическое _ "значение & прямо сейчас. "_

@calvinjuarez Ваши примеры несколько сбивают с толку, потому что вы не пишете ожидаемый результат, поэтому они кажутся несколько теоретическими, но в основном:

.component{
  <strong i="7">@this</strong>: &();  // <strong i="8">@this</strong> is now assigned the value of `.component`
  @{this}_child { a: b; } // this variable, when evaluated, forms the selector .component_child
}
// therefore this output is:
.component .component_child {
  a: b;
}

означает, по сути, «&, но как бы вложенный здесь, а не глубже», вместо того, чтобы возвращать статическое «значение & прямо сейчас».

Я действительно не понимаю, что это значит.

Другой способ подумать об этом. Этот:

.component {
  <strong i="6">@this</strong>: &()
}

Эквивалент записи:

.component {
  <strong i="10">@this</strong>: .component;
}

@ Мэтью-Дин

да. Но подумайте об этом через призму миксинов, где &() захватывает контекст селектора вызывающего миксина.

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

.my-button {
  #buttons.base();
  #buttons.size( ... );
  #buttons.inset-icon-support( left right );
}

.my-button--wide {
  #buttons.size( ... )
}

.my-button--condensed {
  #buttons.size( ... )
}

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

Это; его можно использовать для создания селектора, такого как .my-button--wide > .my-button__text , без необходимости передавать какие-либо имена селекторов в качестве параметров. Только из контекста селектора вызываемого абонента.


Подобные "фабрики компонентов" на основе миксинов позволяют избежать многих проблем типа "все или ничего", которые возникают при использовании фреймворков стилей. Они позволяют вам зарегистрировать фреймворк, но детально выбрать, какие компоненты вы хотите фактически включить и под каким именем.

@rjgotten

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

Ага, я понял. Вероятно, это наиболее полезно в миксинах. Я определенно получаю полезность &() используя имя прямого селектора. Я хотел просто попытаться прояснить значение &() в данном примере.

Чтобы пойти дальше, я думаю, что это хорошее синтаксическое решение, и я бы лично дал 👍 продвижению вперед с реализацией &() , если кто-то захочет этим заняться.

@ Мэтью-Дин

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

Упс, извинения. Я переформулирую это правильно. Я чувствую, что &() была бы более сильной функцией, если бы здесь Less был скомпилирован с приведенным ниже CSS.

.component { <strong i="10">@this</strong>:&();
  /* default styles */
  @{this}_child {
  // ↑ The crucial difference: `@{this}` here behaves _like `&`_, **NOT** like `.component`
  // (since it's in the same rule block and scope level).
    /* child default styles */
  }
}
.component {
  /* default styles */
}
.component_child {
  /* child default styles */
}

Если <strong i="15">@this</strong>:&(); в этом случае ведет себя так же, как <strong i="17">@this</strong>:.component; , мы перекладываем эту функцию на служебную _only_ внутри миксинов, но я думаю, что она может предложить больше.

означает, по сути, «&, но как бы вложенный здесь, а не глубже», вместо того, чтобы возвращать статическое «значение & прямо сейчас».

Я действительно не понимаю, что это значит.

Это означает, что я думаю, что .thing{ & {} } и .thing{ <strong i="11">@amp</strong>:&(); @{amp} {} } должны давать одинаковый результат.

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

_component.less_

.component { // I only write "component" once!  Much concise, such DRY!
  <strong i="16">@this</strong>: &();

  /* base styles */

  @{this}_child {
    /* styles for the child */
  }

  @{this}-variant { // component-variant styles all together, and inside the `.component` block
    /* nothing too schmancy so far */
    @{this}_child {
      /* IT'S MAGIC! */
    }
  }
}

↓↓↓

_component.css_

.component {
  /* base styles */
}
.component_child {
  /* styles for the child */
}
.component-variant {
  /* nothing too schmancy so far */
}
.component-variant .component_child {
  /* IT'S MAGIC! */
}

Преимущество: вам не нужно спрашивать свою команду, имеют ли они в виду & или @{this} . Вы просто говорите: «Просто используйте @{this} везде».

Это фактически сделало бы определение миксина фабрики компонентов более внутренне согласованным.

_гипотетическая-кнопка-mixin.less_

#button () {
  .size(large) { <strong i="7">@button</strong>: &();
    @{button} { // same scope, so it behaves _exactly_ like `&`.
      font-size: 1.8rem;
    }
    @{button}-primary { // same scope, so it behaves _exactly_ like `&`.
      border-width: 5px;
      @{button}_icon { // nested scope, behaves like the parent selector at the mixin call (.btn).
        height: 1.8rem;
        width:  1.8rem;
      }
    }
  }
}
// ...

_гипотетические-стили.less_

.btn {
  #button.size(large);
}

_hypothetical-styles.css_

.btn {
  font-size: 1.8rem;
}
.btn-primary {
  border-width: 5px;
}
.btn-primary .btn_icon {
  height: 1.8rem;
  width:  1.8rem;
}

Это означает, что я думаю, что .thing {& {}} и .thing { @amp : & (); @ {amp} {}} должен дать такой же результат.

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

.mixin() {
  <strong i="10">@this</strong>: &();
  .a {
    .b @{this} { c: d; }
  }
}
.component {
  .mixin();
}

// outputs:
.component .a .b .component {
  c: d;
}

В то время как:

.mixin() {
  .a {
    .b & { c: d; }
  }
}

Произведет:

.b .component .a {
  c: d;
}

@calvinjuarez Думаю, я был сбит с толку, потому что я думаю, что никто не предлагал что-то иное, чем ваш пример. &() сути будет похоже на this.selectors.toCSS() eval'd в этом месте ( не совсем, а просто для иллюстрации ... на самом деле, это может быть самый быстрый способ сделать это). А затем вставив эту строку в другие места, чтобы ее повторно вычислить в качестве селекторов.

@ Мэтью-Дин
На самом деле было бы даже _more_ круто, если бы он отображал список селекторов как фактический список селекторов, включая специальное поведение для раскрытия селекторов на основе всех членов списка.

Например,

.a, .b {
  <strong i="8">@this</strong> : &();

  @{this} {
    c : d;  
  }
}

вывод

.a .a,
.a .b,
.b. .a,
.a .b {
  c : d
}

точно так же, как родной & .

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

7 июля 2018 г. в 10:34 rjgotten [email protected] написал:

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

Например,

.a, .b {
@ это : & ();

@{это} {
компакт диск;
}
}
вывод

.a .a,
.a .b,
.b. .a,
.a .b {
компакт диск
}
прямо как родной & бы.

-
Вы получаете это, потому что вас упомянули.
Ответьте на это письмо напрямую, просмотрите его на GitHub или отключите обсуждение.

.component{
 <strong i="6">@this</strong>: &();  // <strong i="7">@this</strong> is now assigned the value of `.component`
 @{this}_child { a: b; } // this variable, when evaluated, forms the selector .component_child
}
// therefore this output is:
.component .component_child {
 a: b;
}

Я возражаю против лишних .component . Я предполагаю, что это должно работать так:

less .component{ <strong i="12">@this</strong>: &(); // <strong i="13">@this</strong> is now assigned the value of `.component < &` @{this}_child { a: b; } // this variable evaluates like `&_child` } // therefore this output is: .component_child { // < Note: `.component_child` !== `.component .component_child` a: b; }

Однако похоже, что эта функция идет в другом направлении. Просто хотел прояснить свою позицию.

Я предполагаю, что это должно работать так:

То есть, если в селекторе есть токен подстановки, который является _selector list_, а не простой _string_, то токен подстановки действует так же, как если бы был указан & и он _отключает_ обычное объединение селекторов, являющееся результатом вложенности.

Если бы &() выводил тип узла, который позволял бы идентифицировать его как фактический список селекторов, я думаю, этого поведения было бы сравнительно легко.

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

Для меня это звучит так, будто & () одновременно выполняет слишком много работы. Если вы хотите сохранить селекторы в переменной, это одно, но если бы эта переменная отключила цепочку селекторов из-за ее _content_, было бы неясно в синтаксисе. Эта переменная может поступать откуда угодно (например, передаваться из миксина), а список селекторов может быть сгенерирован простым присваиванием переменной. То есть, из использования переменной не ясно, может ли происходить другое поведение цепочки в зависимости от содержимого переменной.

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

.компонент {
@var : & ();
& (@ var) _child {} // или подобная «замена &» синтаксиса
}

Итак, я понимаю, почему результат желателен, но ИМО, мы не можем просто «волшебное переключение» поведения слияния переменных в зависимости от того, откуда берется список селекторов. Для этого требуются две разные функции.

ох ... Мне вообще нравится &(...) штука ...

Ха, правда? Вы не думаете, что возникнет семантическая путаница &() (селекторы захвата из &) и &(@arg) (заменить & селекторами)?

Возможно, вы захотите не смешивать их, поскольку кто-то может захотеть заменить & пустым селектором, чтобы по существу отказаться от него. (Чтобы поместить дочерний элемент в корень.) Хотя я предполагаю, что это может быть &(“”) .child?

Я не знаю, это заслуживает некоторого размышления / рассмотрения.

Кроме того, как отмечалось в потоке «родительские селекторы должны иметь цели», существуют варианты использования для замены определенных частей унаследованного селектора (или полностью), поэтому, думая об этом, я думаю, что их следует отслеживать как две отдельные проблемы. Эта проблема должна касаться только захвата &

Чтобы замкнуть этот круг, здесь я упомянул об изменении & на месте с помощью функционально-подобной конструкции. - https://github.com/less/less.js/issues/1075#issuecomment -397697714

Итак, я бы предпочел, чтобы обсуждение того, «как / нужно ли изменять наследование & », оставалось в потоке родительских селекторов, и этот поток касается того, подходит ли <strong i="9">@var</strong>: &() для захвата внутри -заменить селектор & на переменную. Что, на мой взгляд, все еще кажется нормальным, несмотря на другую тему. Я не уверен, есть ли возможность сделать и то, и другое.

Я пытаюсь сделать это

.html, .css, .js, .php, .mysql, .jquery, .txt, .java {
    <strong i="6">@html</strong>: '\f2d0';
    <strong i="7">@css</strong>: '\f034';
    <strong i="8">@js</strong>: '\f121';
    <strong i="9">@php</strong>: '\f120';
    <strong i="10">@mysql</strong>: '\f1c0';
    <strong i="11">@jquery</strong>: '\f78c';
    <strong i="12">@java</strong>: '\f11b';
    <strong i="13">@txt</strong>: '\f15c';
    &:before {
        content+_: @&;
    }
}

но это не сработает, пока это не будет реализовано

Была ли эта страница полезной?
0 / 5 - 0 рейтинги