Less.js: Salvando seletor em uma variável

Criado em 20 abr. 2017  ·  50Comentários  ·  Fonte: less/less.js

Temos esta solução:

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

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

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

Proponho adicionar um recurso: escrever <strong i="9">@r</strong>: &; vez de <strong i="11">@r</strong>: ~".selector"; para obter o seletor atual e salvá-lo em qualquer variável.

Exemplos:

// 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

Todos 50 comentários

Curiosamente, eu tinha certeza absoluta de que esse pedido já existia. Aparentemente não é.
(Embora obviamente a ideia tenha aparecido em muitos tíquetes antes: # 1174, https://github.com/less/less.js/issues/1075#issuecomment-16891103 etc.)
Então deixe estar, eu acho.


A propósito, apenas no caso (e para coletar alguns casos de uso para pensar em possíveis conflitos impl./sintaxe):
Como você vai usar? Suspeito que em muitos casos não funcionará da maneira que você espera por causa da avaliação preguiçosa. Por exemplo:

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

vai resultar em:

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

Porque @r valor é realmente avaliado dentro de a b (ou seja, onde é usado - não no ponto em que você o define).
(Portanto, suspeito que certos casos de uso podem realmente exigir alguma outra construção de linguagem para isso - não apenas uma variável. E muitos outros casos de uso relacionados foram considerados antes como um assunto de # 1075).

em muitos casos, não funcionará da maneira que você espera por causa da avaliação preguiçosa
Suspeito que certos casos de uso podem realmente exigir alguma outra construção de linguagem para isso - não apenas uma variável

Você precisaria dessa construção de linguagem especial para capturar o contexto do seletor no ponto em que ele é definido, não no ponto em que é chamado pela avaliação da variável à qual está atribuído. A avaliação deve apenas emitir o contexto que foi capturado no site de definição.

Não é muito diferente de procurar variáveis ​​por fechamento, mas sim; exigirá uma construção de linguagem especial e não uma função.

@rjgotten

Sim, acho que estivemos discutindo alguma selector pseudo-função anteriormente (pseudo porque uma análise de função regular não pode lidar com todos aqueles combinadores específicos do seletor de qualquer maneira) e então porque é pseudo (ou seja, um tipo dedicado como Url ) não seria um problema fazê-lo puxar seu contexto de definição (se bem me lembro os DRs fazem exatamente isso).
Então, algo como <strong i="10">@foo</strong>: selector(&); poderia funcionar, eu acho. Embora então surja um próximo problema menor:

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

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

Portanto, possivelmente pode exigir outro operador / palavra-chave diferente de & . (Ou talvez apenas uma pseudo-função dedicada, por exemplo, current-selector() ... Hmm, agora isso me traz a ideia de codificar um tipo PseudoFunction genérico para não poluir a API de cada pequeno produto, ooch! :).

Eu sei que há uma hesitação geral em adicionar coisas novas à linguagem, mas um especificador de seletor pode ser útil. Eu gosto de | , embora faça parte da sintaxe do seletor CSS @namespace . No entanto, não parece que | tem permissão para _iniciar_ um seletor, então ele não deve entrar em conflito. Estou usando porque me lembra o "valor absoluto" do Math, que parece vagamente apropriado, e porque é simples. Apenas um pensamento para inspirar uma conversa.

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

(Na verdade, poderia ser usado para designar que _qualquer_ var deve ser processado imediatamente e armazenado, ou o que quer que seja? Mas parece que está _way_ over-scoping.)

é normal & ou saved-context-& ?

Eu diria que o contexto do seletor deve ser capturado no site em que a pseudo função selector() é chamada e & deve ser avaliada dentro desse contexto e o resultado final deve ser atribuído a este novo tipo de Selector nó de árvore.

Quando _qualquer_ variável contendo um tipo Selector de nó de árvore é interpolada em um seletor, como é o caso com o uso de @{var} no exemplo, o seletor resultante deve ser construído da mesma maneira como quando um interpolador & está presente no seletor, ou seja; não se junte e prefixe com os seletores de um nível de aninhamento acima.

O raciocínio por trás disso é que ambos são seletores capturados: selector() é um seletor capturado pelo usuário, enquanto & é o seletor 'pai' sempre presente e capturado.

Então, se um usuário requer a interpolação de um nó Selector capturado junto com o contexto do seletor _current_, ele pode ser explícito sobre isso. Por exemplo, & @{var} { ... }

No fechamento

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

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

deve gerar

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

Enquanto

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

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

deve gerar

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

Hmm, @{var} vs. & @{var} parece bastante artificial, mas não é assim que essas coisas funcionam no Less. ... { & div ... e ... { div ... sempre foram afirmações iguais. Além disso, sem contar isso, o que devo fazer se precisar de a b x, #y a b .z com x, #y * .z definido em outro lugar?

Não sou fã de uma construção semelhante a uma função para seletores. Eu apóio ser capaz de referenciar, modificar ou transportar (atribuir a variável e reutilizar) seletores herdados.

Só para ter certeza, porém, quanto disso é uma variação de # 1075 (direcionando seletores pais) ou em possível conflito com https://github.com/less/less-meta/issues/16#issuecomment -292679320 (atribuindo um único seletor para uma variável)? Ou isso é diferente de aliasing mixins porque esta é uma lista de seletores e não um único seletor avaliado (ou mixin), e a saída é a lista de seletores e não o conjunto de regras avaliado? Estou assumindo que esse recurso é diferente; Só quero ter certeza de que tudo isso está se movendo na mesma direção.

@ matthew-dean
Na verdade, trata-se de capturar a lista de seletores real, não de capturar o conjunto de regras avaliado e enviar essa lista para uso posterior.

Pode-se imaginar uma função como extract(list,index) a ser atualizada para poder também extrair componentes do seletor de uma lista de seletores e melhorias semelhantes para facilitar o trabalho com seletores, de forma que os usuários possam facilmente manipulá-los de maneiras interessantes. Por exemplo, para componentes que seguem certos esquemas de nomenclatura, como BEM.

Por exemplo, dado um mixin

.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;
    }
  }
}

O seguinte menos

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

gera CSS

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

Sass, afaik, tem isso há muito tempo e existem inúmeros exemplos dessa técnica sendo usada de forma muito inteligente. Em fábricas de código, como no meu exemplo, ou para outros fins.

Quanto a:

possível conflito com less / less-meta # 16 (comentário) (atribuindo um único seletor a uma variável)

Pessoalmente, assumo o seguinte comportamento:
Valores do seletor "triviais" (por exemplo, .mixin , .ns.mixin , #foo .bar , baz etc, felizmente isso cobre tudo que pode ser usado / definido como mixin / função ) são atribuídos a uma variável (ou passados ​​como parâmetros para função) diretamente . Ou seja, na verdade já temos isso:

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

^ Isso (essencialmente) não tem @var(...) ou @var[...] extratos
(Em geral, a convenção lógica seria esquecer que os identificadores mixin são (representados internamente como) seletores, mas sempre pensar neles como identificadores apenas com ponto ou # prefixo e coisas como .ns > .mixin para desaparecer eventualmente como redundante e inútil :)

Considerando que um seletor complexo ou "real" requer selector pseudo função devido à ambigüidade de sintaxe / analisador. Ou seja, coisas como:

  • <strong i="29">@var</strong>:foo>bar <- seletor e (potencialmente) uma expressão lógica
  • <strong i="32">@var</strong>:.1+.2; <- expressão aritmática e seletor Less válido
    (etc. Bem, basta lembrar de todos os símbolos do seletor específico - quase todos os conflitos com algo em um contexto de análise de valor, e isso fica ainda mais dramático quando os valores acima são potencialmente passados ​​para uma função / mixin como parâmetros no local, por exemplo, o seguinte é simplesmente impossível para apoiar sem selector() :
    less: some-function(abc, selector(#foo .is :not(> bar)[baz="qux"], abc), selector(bla), 42); // ^ remove `selector()` and try to parse

Não sou fã de uma construção semelhante a uma função para seletores.

Em resumo, a pseudo função selector é apenas necessária para eliminar qualquer conflito de sintaxe e semântica atual e potencial de uma vez por todas. Então, eu duvido que realmente tenhamos muitas opções aqui (contextos de análise de valor e seletor apenas precisam ser separados de alguma forma).


(Tudo acima não significa que um valor retornado por selector() não pode ser usado como uma entidade chamável, por exemplo, @var() , provavelmente - mas isso seria apenas desnecessário / inútil, então mal vale a pena irmão).

@rjgotten

Pode-se imaginar uma função como extract(list,index) a ser atualizada para poder também extrair o seletor

Claro que poderíamos ajustar funções para trabalhar com strings assumindo que tal string pode conter algum seletor, mas isso significa que cada função (não apenas extract ) deve ser atualizada / ajustada / modificada. A abordagem oposta seria mais eficiente / menos onerosa. Ou seja, é uma função de conversão selector-string->values dedicada OU até mesmo retornar a estrutura adequada de nós diretamente por selector (em ambos os casos, a parte mais complicada é como empacotar / desempacotar combinadores seletores a cada uso -caso pode preferir uma representação diferente).

(Observe que o próprio recurso de interpolação do seletor ainda tem que converter @{var} para um formato apropriado no final de qualquer maneira, então não importa realmente o formato do valor dessa var - seja se for string, anônimo ou qualquer outro estrutura de nós - a maior parte dos truques de conversão permanece a mesma).

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

Para ser honesto, isso parece uma reencarnação de "JavaScript embutido e hackery do tipo LessHat", não pode proibir, mas irá anunciar agressivamente contra.
(Sem contar que o exemplo é muito infeliz <- conte as linhas) Eu prefiro sugerir alguma coisa less-plugin-bem-selectors (onde você pode simplesmente ter uma função get-block-name , btw. Mesmo sem o & feature) em vez de tais regexes feias (a abordagem "Usando um pré-processador CSS como um processador de texto arbitrário" acabará perdendo no final para coisas do tipo PostCSS).

E voltando a & vs. context-saving-& , até agora não tenho ideias melhores do que um sinalizador dedicado para a função, por exemplo, selector(..., lazy or not) , ou mesmo dois funções separadas. Ou usando other-than-&-keyword (por exemplo, ). Simplesmente não consigo ver nenhum método seguro para resolver automaticamente a ambigüidade do ponto de avaliação.

Prefiro sugerir alguma coisa less-plugin-bem-selectors

Absolutamente. A extração baseada em regex era apenas para fornecer um exemplo que não envolvia funções personalizadas. ;)

Não sou fã de uma construção semelhante a uma função para seletores.

Além disso, se você quer apenas dizer como parece ... Poderia ser alguma outra construção, é claro, por exemplo, ⁞#foo:not(.bar)⁞ , mas você sabe que já esgotamos os símbolos grátis. Portanto, a sintaxe da pseudo função só é sugerida porque já temos esse conceito com url qualquer maneira (portanto, não há necessidade de pensar em coisas que um novo conceito poderia ou quebraria).

Agora, a parte divertida.

Eu criei uma implementação de current-selector (só para ver como isso poderia ser inchado, esperando que, é claro, não possa ser muito útil por causa de var lazy-Evaluation), e sabe o quê? Este exemplo básico:

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

resulta em r: div :)
Não tenho ideia de qual parte do código do compilador lida com esse comportamento específico, mas aqui está um exemplo mais avançado para ilustrar a mágica:

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
    }
}

Lá apenas as instruções [2] e [3] são chamadas duas vezes (ou seja, avaliadas de forma preguiçosa), enquanto que [1] não são (aparentemente porque o valor não contém nenhuma variável, embora mais uma vez, não sei se isso é intencional ou apenas um efeito colateral de algum cache, ou pode ser um bug feliz em meu código - por exemplo, esta linha pode desencadear esse efeito colateral para esse cache - mas então não está claro por que é afetado por variáveis ​​extras - ou seja, mais pesquisas são necessárias).


Ou seja, uma versão baseada em plug-in de context-saving-& parece ser possível (exceto que é claro que em vez de <strong i="29">@var</strong>: & você usará algo como <strong i="31">@var</strong>: current-selector() ) Embora a função não deva tem quaisquer parâmetros, caso contrário, ele será avaliado lentamente (se uma variável for passada) - isso é triste, pois inicialmente planejei quatro :).
Bastante abusivo, mas pode servir como uma solução alternativa / polyfill. Um exemplo mais real também funciona como desejado:

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;
        }
    }
}

isto é, atribuições de variáveis ​​/ chamadas de função subsequentes não afetam o ponto de avaliação da variável inicial.

@ sete fases-máx.
Adoro.

Mesmo se a avaliação preguiçosa atualmente joga uma chave no trabalho quando um argumento de parâmetro está presente, _que_ é presumivelmente algo que pode ser contornado para uma implementação 'real'.

Além disso, se você quer dizer apenas a aparência ... Pode ser alguma outra construção, é claro, por exemplo, ⁞ # foo: não (.bar) ⁞, mas você sabe que já esgotamos os símbolos livres.

É justo. Eu realmente não envolvi meu cérebro sobre isso, tanto quanto o uso, nem tenho nenhuma ideia melhor. Acho que parecia haver algo especial nisso, mas talvez não. Eu sei que houve uma discussão em algum momento sobre $() , mas acabamos nos apropriando de $ . A propósito, não seria selectors() e não selector() ? Não pode (como o & ) conter qualquer número de seletores?

E parece que selector(&) faz mais sentido do que current-selector() . Isto é: "faça uma lista de seletores a partir do objeto X, seja & ou uma string". Qualquer que seja a sintaxe final, parece que tomaria & como argumento.

E parece que selector(&) faz mais sentido do que current-selector()

São coisas diferentes. current-selector é apenas uma variante de função de & (já que o último não é suportado pelo analisador). Enquanto selector(...) é aquele patch para o analisador suportar um seletor arbitrário (incl. & ).


Quanto a selectors - bem, é. Mas, uma vez que é 99% dos casos de uso de seletor único, acho que a forma plural soaria menos evidente para a maioria dos usuários (na maioria, eles geralmente intitulam h1, h2, h3 {} como um seletor e continuam falando de menos seletor pai (mesmo se for seletor s ) :) Então por que se preocupar?

Ah ok.

@ matthew-dean
A forma plural e singular é praticamente intercambiável para qualquer pessoa, exceto os autores das especificações CSS. Na verdade, faça isso: para qualquer um, incluindo os autores das especificações, já que até as próprias especificações CSS são vítimas do uso alternado da forma singular e plural às vezes.

Muito hilariante; o termo 'seletores' no plural não é nem mesmo a forma oficial de designar um conjunto separado por vírgulas. A terminologia estritamente correta para a forma plural é, creio eu, uma _lista do seletor_.

Então você pode ver como essa referência ambígua está profundamente enraizada.

A terminologia estritamente correta para a forma plural é, acredito, uma lista de seletores.

Sim, eu também pesquisei w3c ontem, é "grupo de seletores", "uma lista de seletores" etc., nada muito estranho como "Um seletor é uma cadeia de uma ou mais sequências de seletores simples separados por combinadores" eles também tem :) Apenas a forma de "seletores" é mais usada para descrever a coisa de "tipos de seletor".

"Um seletor é uma cadeia de uma ou mais sequências de seletores simples separados por combinadores"

E para quem pensa que pode estar se referindo a listas separadas por vírgulas: não é. A forma completa dessa citação deve ser: "um seletor _complex_ é uma cadeia de uma ou mais sequências de seletores simples separados por combinadores."

As especificações CSS têm outro problema em que a forma generalizada de "seletor" é usada principalmente para se referir ao que as especificações chamam oficialmente de _seletores complexos_. Os seletores complexos são seletores simples, por exemplo, tag ; #id ; .class ; [attr] ; etc., encadeados por meio de combinadores, por exemplo, > ; + ; ~ , etc.

Algo como ul > li é chamado de seletor complexo.


AVISO o seguinte será um pouco divertido:

As especificações CSS são, infelizmente, um atoleiro de terminologia inconsistente e mal denominada. Quanto mais você recua, pior fica progressivamente. Não ajuda que muitos módulos CSS3 continuem referindo-se aos módulos CSS 2.1 ou que novos módulos CSS3 foram especificados copiando sua antiga documentação CSS 2.1 literalmente. As especificações para seletores e o modelo de formatação visual são os piores infratores; tanta terminologia ambígua, que soa semelhante ou simplesmente mal nomeada.

Tome, por exemplo, algo muito menos trivial do que ul > li , como [*|attr^="value" i] . Este último é tecnicamente classificado como um seletor simples. (Sim com certeza.)

Eu tive que tentar explicar partes da última especificação do modelo de formatação visual para um de meus colegas mais orientados para o design em um ponto, alguns anos atrás. Acho que alguns fusíveis realmente explodiram em _ambos_ nossos cérebros enquanto examinávamos as passagens que tratam do conceito de caixas de linha e isso nem era a pior parte. (Tente entrar na mágica la-la-land que é o modelo de formatação de mesa, se você tiver pouco valor para sua sanidade.)

Diversas alegrias da documentação de projetos de código aberto ...

Considere, por exemplo, algo muito menos trivial do que ul > li , como [*|attr^="value" i] . Este último é tecnicamente classificado como um seletor simples

Isso realmente faz sentido para mim, lol, só porque não usa um combinador. Segue a definição com precisão. Só porque usa muitos símbolos não o torna mais "complexo". ul > li é complexo porque envolve dois conjuntos de consultas, ou seja, consultar todos os elementos correspondentes a li e, em seguida, percorrer a árvore de cada um para determinar quais estão contidos em ul . O último testa os elementos individuais apenas uma vez. É uma consulta, portanto, é um seletor simples.

o termo 'seletores' no plural não é nem mesmo a forma oficial de designar um conjunto separado por vírgulas. A terminologia estritamente correta para a forma plural é, acredito, uma lista de seletores.

Certo, você está correto. "Seletores" são na verdade apenas os bits definidos que permitem selecionar elementos, mas ul > li > .title é um "seletor" singular. Então eu acho que selector() é, de fato, talvez mais próximo semanticamente.

@ sete fases-máx.

Acabei de encontrar outro problema menor com a função de plug-in quick-n-dirty: ele não controla o acesso de um mixin com namespace corretamente. Os namespaces são um quadro do tipo Ruleset regular e, portanto, seu nome é adicionado aos seletores.

Uma implementação real provavelmente deve abranger esse caso também.


[EDITAR]
O truque para fazê-lo funcionar é verificar se um dos quadros na pilha do contexto da função é MixinDefinition e se _ for_, pule os próximos x quadros nessa pilha, onde x é igual à quantidade de quadros na pilha de MixinDefinition .

(Basicamente; isso pula os quadros de 'encerramento' que são adicionados à pilha quando um MixinCall executa o MixinDefinition .)

Removido o rótulo "obsoleto". Este ainda é um bom assunto a ser explorado.

Talvez current-selector() não seja tão ruim. Embora, para ficar claro, seria na verdade current-selectors() . Mas isso ainda é um pouco prolixo. Acho que seria mais favorável se pudéssemos pensar em um nome de função para "capturar &" que seja mais conciso.

nome da função para "captura &" que é mais conciso.

Basta nomeá-lo &() . Conceitualmente, nada mais é do que um getter para o que está em & afinal.
Por exemplo

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

🤔
Sim, isso deve servir. Alguma objeção?

Vou tentar resumir para ver se estou entendendo o recurso proposto:

A nova função &() retorna o que & produziria no contexto atual, permitindo isso.

.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! */
    }
  }
}

E tudo isso geraria isso.

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

Porque isso é incrível e eu adoro isso.

Pensando mais nisso, acho que o mais atraente para mim (depois de uma primeira passagem; pare-me se eu estiver ficando louco) seria a possibilidade de ter um estilo de "bloco" (conjunto de regras) de componente padronizado. Basicamente, eu quase espero que em vez de um valor de string de seletor simples salvo, a função mapeie para _ " & , mas no escopo a variável foi definida em" _, o que permitiria este estilo de autoria para um componente (chamarei esse comportamento de A ):

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

Então eu poderia dizer "use @this qualquer lugar ao invés de & ".

Minha única preocupação seria o caso invertido (que chamarei de comportamento B ), mas não consigo pensar em um caso convincente em que desejaria esse comportamento. É que não consigo ver por que alguém iria querer fazer isso.

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

Porque a maneira atual de fazer isso é _muito_ mais concisa (e legível, também, uma vez que & esteja claro em seu vocabulário).

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

Existe um caso convincente (além da dificuldade de implementação) para o Comportamento B em vez do Comportamento A?

Essa é apenas uma das perguntas que acho que devem ser respondidas antes do início do trabalho.


TL; DR: Meu voto é para &() ser dinâmico, significando essencialmente _ " & , mas como se aninhado aqui em vez de mais profundo" _, em vez de retornar um _ estático "o valor de & agora. "_

@calvinjuarez Seus exemplos são um tanto confusos porque você não está escrevendo a saída esperada, então eles parecem estar no reino da teoria, mas basicamente:

.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;
}

significando essencialmente "&, mas como se aninhado aqui em vez de mais profundo", em vez de retornar um estático "o valor de & agora."

Eu realmente não entendo o que isso significa.

Outra maneira de pensar sobre isso. Isto:

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

É o equivalente a escrever:

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

@ matthew-dean

sim. Mas pense nisso através das lentes dos mixins, onde &() pegaria o contexto do seletor do chamador do mixin.

Ele permite escrever componentes baseados em mixin onde os próprios autores podem decidir livremente sobre a raiz do nome da classe de uma maneira natural. Ex: dado

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

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

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

os mixins usados ​​lá podiam ler a classe via &() e incorporá-la em sua saída de maneira apropriada. Por exemplo, o seletor capturado para a segunda e terceira regras pode ter a sintaxe BEM decomposta para obter a classe de bloco base, que pode ser usada para gerar substituições para seletores de elemento aninhados.

Aquilo é; ele poderia ser usado para gerar um seletor como .my-button--wide > .my-button__text , sem a necessidade de passar nenhum nome de seletor como parâmetro. Apenas a partir do contexto do seletor de chamada sozinho.


_Fábricas de componentes_ baseadas em Mixin, como esta, evitam muitos dos problemas do tipo tudo ou nada do nosso jeito ou da estrada que você tem ao usar estruturas de estilo. Eles permitem que você registre a estrutura, mas escolha granularmente quais componentes você deseja realmente incorporar e sob quais nomes.

@rjgotten

os mixins usados ​​lá podiam ler a classe via & () e trabalhar em sua saída de forma apropriada. Por exemplo, o seletor capturado para a segunda e terceira regras pode ter a sintaxe BEM decomposta para obter a classe de bloco base, que pode ser usada para gerar substituições para seletores de elemento aninhados.

Sim, eu entendo. Provavelmente é mais útil em mixins. Eu definitivamente obtenho a utilidade de &() ao usar o nome do seletor direto. Meu objetivo era apenas tentar esclarecer o valor de &() no exemplo dado.

Para ir mais longe, acho que é uma boa solução sintática e, pessoalmente, daria a mínima para seguir em frente com a implementação de &() , se alguém quisesse assumi-la.

@ matthew-dean

Seus exemplos são um tanto confusos porque você não está escrevendo a saída esperada

Opa, desculpas. Vou reformular corretamente. Acho que &() seria um recurso mais forte se o Less aqui compilasse com o CSS abaixo.

.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 */
}

Se <strong i="15">@this</strong>:&(); se comportar exatamente como <strong i="17">@this</strong>:.component; neste caso, estamos relegando este recurso para utilidade _apenas_ dentro dos mixins, mas acho que tem mais a oferecer.

significando essencialmente "&, mas como se aninhado aqui em vez de mais profundo", em vez de retornar um estático "o valor de & agora."

Eu realmente não entendo o que isso significa.

Isso significa que acho que .thing{ & {} } e .thing{ <strong i="11">@amp</strong>:&(); @{amp} {} } devem produzir a mesma saída.

Isso significa, de forma mais prática, que você não precisa escrever um mixin para fazer um BEM fácil, mas pode defini-lo inline. Voltando a um dos meus exemplos mais antigos:

_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! */
}

O benefício: você não precisa perguntar à sua equipe se eles querem dizer & ou @{this} . Você acabou de dizer "Basta usar @{this} qualquer lugar."

Isso tornaria uma definição de mixin de fábrica de componentes mais consistente internamente também.

_hypothetical-button-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;
      }
    }
  }
}
// ...

_estilos hipotéticos.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;
}

Isso significa que acho que .thing {& {}} e .thing { @amp : & (); @ {amp} {}} deve produzir a mesma saída.

Sim, acho que estamos dizendo as mesmas coisas, mas deixe-me confirmar com este exemplo. É assim que vejo esse recurso em comparação com & .

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

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

Enquanto:

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

Produziria:

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

@calvinjuarez Acho que fiquei confuso porque acho que ninguém estava sugerindo algo diferente do seu exemplo. &() seria essencialmente como this.selectors.toCSS() avaliado naquele local ( não realmente, mas apenas para ilustração ... na verdade, essa pode ser a maneira mais rápida de fazer isso). E então inserir aquela string em outros lugares para ser reavaliada como seletores.

@ matthew-dean
Seria realmente _mais_ incrível se expusesse a lista de seletores como uma lista real de seletores, incluindo o comportamento especial para expandir seletores com base em todos os membros da lista.

Tem por exemplo

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

  @{this} {
    c : d;  
  }
}

saída

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

assim como o nativo & faria.

Sim, isso é exatamente o que faria. No 3.5, quaisquer variáveis ​​avaliadas em seletores fazem com que toda a lista de seletores seja analisada novamente como uma nova lista de seletores. Então, sim, isso funcionaria conforme o esperado. Na verdade, é muito fácil por causa de alguns RPs que fiz recentemente.

Em 7 de julho de 2018, às 10:34, rjgotten [email protected] escreveu:

@ matthew-dean
Na verdade, seria ainda mais incrível se expusesse a lista de seletores como uma lista real de seletores, incluindo o comportamento especial para expandir seletores com base em todos os membros da lista.

Tem por exemplo

.a, .b {
@ isto : & ();

@{isto} {
CD;
}
}
saída

.a .a,
.a .b,
.b. .uma,
.a .b {
CD
}
assim como o nativo & faria.

-
Você está recebendo isso porque foi mencionado.
Responda a este e-mail diretamente, visualize-o no GitHub ou ignore a conversa.

.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;
}

O extra .component é contra o que estou argumentando. Estou sugerindo que deve funcionar assim:

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; }

Parece que o recurso está indo em uma direção diferente. Só queria esclarecer minha posição.

Estou sugerindo que deve funcionar assim:

Ou seja, se houver um token de substituição em um seletor que é uma _lista de seletores_ em vez de uma _string_ simples, então o token de substituição age da mesma forma como se & fosse especificado e ele _desabilita_ o encadeamento de seletor normal que resulta do aninhamento.

Se &() gerasse um tipo de nó que o tornasse identificável como uma lista de seletores real, esse comportamento seria comparativamente fácil de alcançar, eu acho.

De fato, se fosse para gerar um tipo de nó dedicado, isso também poderia auxiliar na criação de funções de plugin para _manipular_ a lista de seletores capturada, mais tarde.

Para mim, isso soa como fazer com que & () trabalhe demais ao mesmo tempo. Se você quiser salvar seletores em uma variável, isso é uma coisa, mas fazer com que essa variável desabilite o encadeamento de seletores por causa de seu _content_ não seria claro na sintaxe. Essa variável pode vir de qualquer lugar (por exemplo, passada de um mixin) e a lista do seletor pode ser gerada por atribuição de variável simples. Ou seja, não está claro a partir do uso da variável que um comportamento de encadeamento diferente aconteceria com base no conteúdo da variável.

Acho que se você quiser desativar o encadeamento, terá que especificar que deseja substituir o implícito e por outro valor, como (perdoe a formatação, estou no meu telefone) -

.component {
@var : & ();
& (@ var) _child {} // ou alguma sintaxe de “substituição de &”
}

Então eu entendo porque o resultado é desejável, mas, IMO, não podemos simplesmente "mudar" o comportamento de mesclagem de variáveis ​​com base na origem da lista de seletores. Isso requer dois recursos diferentes.

ooh ... Na verdade eu gosto da coisa &(...) ...

Ha, realmente? Você não acha que haveria confusão semântica de &() (capturar seletores de &) e &(@arg) (substituir & por seletores)?

Você pode querer considerar não misturá-los, já que alguém pode querer substituir & por um seletor vazio para essencialmente descartá-lo. (Para colocar uma criança na raiz.) Embora eu ache que talvez possa ser &(“”) .child?

Não sei, isso merece algum pensamento / consideração.

Além disso, conforme observado no tópico “seletores pais devem ter alvos”, há casos de uso para substituir partes específicas do seletor herdado (ou inteiramente), então pensando nisso, acho que esses devem ser rastreados como dois problemas separados. Este problema deve ser apenas sobre a captura e

Só para fechar este círculo, aqui foi onde mencionei alterar & no local com uma construção semelhante a uma função. - https://github.com/less/less.js/issues/1075#issuecomment -397697714

Então, eu prefiro que a discussão sobre "como / se alterar & herança" permaneça na discussão dos seletores pai, e esta discussão é sobre se <strong i="9">@var</strong>: &() é ou não apropriado para capturar a - coloque o seletor & em uma variável. O que, na minha mente, ainda parece bom, apesar da outra discussão. Não tenho certeza se há uma oportunidade de fazer as duas coisas ou não.

Estou tentando fazer isso

.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+_: @&;
    }
}

mas isso não funcionará até que seja implementado

Esta página foi útil?
0 / 5 - 0 avaliações