Less.js: Enregistrer le sélecteur dans une variable

Créé le 20 avr. 2017  ·  50Commentaires  ·  Source: less/less.js

Nous avons cette solution :

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

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

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

Je propose d'ajouter une fonctionnalité : écrire <strong i="9">@r</strong>: &; au lieu de <strong i="11">@r</strong>: ~".selector"; pour récupérer le sélecteur courant et le sauvegarder dans n'importe quelle variable.

Exemples:

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

Tous les 50 commentaires

Curieusement, j'étais absolument sûr qu'une telle demande existe déjà. Apparemment non.
(Bien que l'idée soit manifestement apparue dans de nombreux tickets auparavant : #1174, https://github.com/less/less.js/issues/1075#issuecomment-16891103 etc.)
Alors laissez-le être je suppose.


D'ailleurs, juste au cas où (et pour collecter quelques cas d'utilisation pour penser à d'éventuels conflits d'impl./syntaxe) :
Comment allez-vous l'utiliser? Je soupçonne que dans de nombreux cas, cela ne fonctionnera pas comme prévu à cause de l'évaluation paresseuse. Par exemple:

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

aura pour résultat:

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

Parce que la @r est vraiment évaluée à l'intérieur de a b (c'est-à-dire là où elle est utilisée - pas au point où vous la définissez).
(Je soupçonne donc que certains cas d'utilisation peuvent en fait nécessiter une autre construction de langage pour cela - pas seulement une variable. Et de nombreux autres cas d'utilisation connexes ont déjà été considérés comme un sujet de #1075).

dans de nombreux cas, cela ne fonctionnera pas comme prévu à cause de l'évaluation paresseuse
Je soupçonne que certains cas d'utilisation peuvent en fait nécessiter une autre construction de langage pour cela - pas seulement une variable

Vous auriez besoin de cette construction de langage spéciale pour capturer le contexte du sélecteur au point où il est défini, et non au point où il est appelé par l'évaluation de la variable à laquelle il est affecté. L'évaluation doit simplement émettre le contexte qui a été capturé sur le site de définition.

Pas très différent de la recherche de variables par fermeture, mais oui ; cela nécessitera une construction de langage spéciale et non une fonction.

@rjget

Oui, je suppose que nous avons discuté selector pseudo-fonction Url ) ce ne serait pas un problème de faire en sorte qu'il récupère son contexte de définition (si je me souviens bien, les DR font exactement comme ça).
Donc quelque chose comme <strong i="10">@foo</strong>: selector(&); pourrait faire un tour, je suppose. Bien qu'un autre problème mineur se pose alors :

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

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

Cela peut donc nécessiter un autre opérateur/mot-clé & . (Ou peut-être juste une pseudo-fonction dédiée, par exemple current-selector() ... Hmm, maintenant cela m'amène à l'idée de coder un type générique PseudoFunction pour ne pas polluer l'API de chaque petit goody, ouf ! :).

Je sais qu'il y a une hésitation générale à ajouter de nouvelles choses à la langue, mais un spécificateur de sélecteur pourrait être utile. J'aime | , bien que cela fasse partie de la syntaxe du sélecteur CSS @namespace . Cependant, il ne semble pas que | soit autorisé à _démarrer_ un sélecteur, il ne devrait donc pas entrer en conflit. Je l'utilise parce que cela me rappelle la "valeur absolue" de Math qui semble vaguement appropriée, et parce que c'est simple. Juste une pensée pour inspirer la conversation.

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

(En fait, il pourrait être utilisé pour désigner que _tout_ var doit être traité et stocké immédiatement, ou autre chose ?

est-ce régulier & ou saved-context-& ?

Je dirais que le contexte du sélecteur doit être capturé sur le site, la pseudo-fonction selector() est appelée et & doit être évalué dans _ce_ contexte et le résultat final doit être affecté à ce nouveau type de Selector nœud d'arbre.

Lorsque _n'importe quelle_ variable contenant un type Selector de nœud d'arbre est interpolée dans un sélecteur, comme c'est le cas avec l'utilisation de @{var} dans l'exemple, le sélecteur résultant doit être construit de la même manière comme lorsqu'un interpolateur & est présent dans le sélecteur, c'est-à-dire ; ne pas joindre et préfixer avec les sélecteurs d'un niveau d'imbrication au-dessus.

Le raisonnement derrière cela est que les deux sont des sélecteurs capturés : selector() est un sélecteur capturé par l'utilisateur, tandis que & est le sélecteur 'parent' toujours présent et capturé.

Ensuite, si un utilisateur requiert l'interpolation d'un nœud Selector capturé avec le contexte du sélecteur _current_, il peut être explicite à ce sujet. Par exemple & @{var} { ... }

En terminant

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

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

devrait générer

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

Tandis que

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

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

devrait générer

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

Hmm, @{var} contre & @{var} semble assez artificiel, ce n'est tout simplement pas ainsi que ces choses fonctionnent dans Less. ... { & div ... et ... { div ... étaient toujours des énoncés égaux. De plus, sans compter cela, que dois-je faire si j'ai besoin de a b x, #y a b .z avec x, #y * .z défini ailleurs ?

Je ne suis pas fan d'une construction de type fonction pour les sélecteurs. Je suis favorable à la possibilité de référencer, de modifier ou de transporter (affecter à une variable et réutiliser) des sélecteurs hérités.

Juste pour être sûr, cependant, dans quelle mesure il s'agit d'une variation sur #1075 (ciblage des sélecteurs parents) ou en conflit possible avec https://github.com/less/less-meta/issues/16#issuecomment -292679320 (affectation un seul sélecteur à une variable) ? Ou est-ce différent de l'aliasing mixins car il s'agit d'une liste de sélecteurs et non d'un seul sélecteur évalué (ou mixin), et la sortie est la liste de sélecteurs et non l'ensemble de règles évalué ? Je suppose que cette fonctionnalité est différente ; Je veux juste m'assurer que tout va dans le même sens.

@matthew-dean
Il s'agit en effet de capturer la liste de sélecteurs réelle, pas de capturer l'ensemble de règles évalué, et de sortir ladite liste pour une utilisation ultérieure.

On pourrait imaginer une fonction comme extract(list,index) à mettre à jour pour pouvoir également extraire des composants de sélecteur à partir d'une liste de sélecteurs et des améliorations similaires pour faciliter le travail avec les sélecteurs, de sorte que les utilisateurs puissent facilement les manipuler de manière intéressante. Par exemple, pour les composants qui suivent certains schémas de nommage tels que BEM.

Par exemple, étant donné un 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;
    }
  }
}

Les suivants Moins

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

génère du CSS

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

Sass l'a, si je ne m'abuse, depuis longtemps et il existe de nombreux exemples d'utilisation très intelligente de cette technique. Dans des usines de code comme dans mon exemple, ou à d'autres fins.

Pour ce qui est de:

conflit possible avec less/less-meta#16 (commentaire) (affectation d'un seul sélecteur à une variable)

Personnellement, je suppose le comportement suivant :
Valeurs de sélecteur "triviales" (par exemple .mixin , .ns.mixin , #foo .bar , baz etc, heureusement cela couvre tout ce qui peut être utilisé/défini comme mixin/function ) sont affectés à une variable (ou passés en paramètre à la fonction) directement . C'est-à-dire que nous avons déjà ceci:

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

^ Cela n'a (essentiellement) rien à voir avec les sélecteurs - ces valeurs sont (tentativement d'être) converties en un format de sélecteur (pour rechercher un mixin) uniquement lorsque nous essayons de les appeler/évaluer avec @var(...) ou @var[...] relevés
(En général, la convention logique serait d'oublier que les identificateurs mixin sont (représentés en interne comme) des sélecteurs, mais toujours de les considérer comme des identificateurs avec juste un point ou # préfixe .ns > .mixin à disparaître finalement comme redondant et inutile :)

Alors qu'un sélecteur complexe ou "réel" nécessite selector pseudo fonction

  • <strong i="29">@var</strong>:foo>bar <- sélecteur et (potentiellement) une expression logique
  • <strong i="32">@var</strong>:.1+.2; <- expression arithmétique et sélecteur Less valide
    (etc. rappelez-vous simplement tous les symboles de sélecteur spécifiques - presque tous sont en conflit avec quelque chose dans un contexte d'analyse de valeur, et cela devient encore plus dramatique lorsque les valeurs ci-dessus sont potentiellement transmises à une fonction/mixin en tant que paramètres en place, par exemple ce qui suit est tout simplement impossible à supporter sans selector() :
    less: some-function(abc, selector(#foo .is :not(> bar)[baz="qux"], abc), selector(bla), 42); // ^ remove `selector()` and try to parse

Je ne suis pas fan d'une construction de type fonction pour les sélecteurs.

En résumé, la pseudo fonction selector est juste nécessaire pour éliminer une fois pour toutes les conflits de syntaxe et de sémantique actuels et potentiels. Je doute donc que nous ayons vraiment trop d'options ici (les contextes d'analyse de valeur et de sélecteur doivent simplement être séparés d'une manière ou d'une autre).


(Tout ce qui précède ne signifie pas qu'une valeur renvoyée par selector() ne peut pas être utilisée comme entité appelable, par exemple @var() , cela pourrait probablement - mais ce serait tout simplement inutile/inutile, donc ça vaut à peine la peine de embêter).

@rjget

On pourrait imaginer une fonction comme extract(list,index) à mettre à jour pour pouvoir aussi extraire le sélecteur

Bien sûr, nous pourrions ajuster les fonctions pour qu'elles fonctionnent avec des chaînes en supposant qu'une telle chaîne peut contenir un sélecteur, mais cela signifie que chacune de ces fonctions (pas seulement extract ) doit être mise à jour/ajustée/modifiée. L'approche inverse serait plus efficace / moins contraignante. C'est-à-dire qu'il s'agit soit d'une fonction de conversion dédiée selector-string->values , OU même de renvoyer la structure appropriée des nœuds directement par selector (dans les deux cas, la partie la plus délicate est de savoir comment emballer/décompresser les combinateurs de sélecteurs à chaque utilisation -cas peut préférer une représentation différente).

(Notez que la fonction d'interpolation du sélecteur elle-même doit toujours convertir @{var} dans un format approprié à la fin de toute façon, donc peu importe le format dans lequel la valeur de cette var entre - que ce soit une chaîne, anonyme ou autre structure des nœuds - la plupart des astuces de conversion restent les mêmes).

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

Pour être honnête, cela ressemble à une réincarnation du "piratage JavaScript en ligne et de type LessHat", ne peut pas interdire mais fera une publicité agressive contre.
(Sans compter que l'exemple est assez malheureux <- comptez les lignes) Je préférerais suggérer quelque chose de less-plugin-bem-selectors (où vous pouvez simplement avoir une fonction get-block-name , d'ailleurs même sans le & ) au lieu de telles regex laides (l'approche "Utiliser un préprocesseur CSS comme traitement de texte arbitraire" finira par se perdre dans des trucs de type PostCSS).

Et pour revenir à & vs context-saving-& , jusqu'à présent, je crains de n'avoir aucune idée meilleure qu'un indicateur dédié à la fonction, par exemple selector(..., lazy or not) , ou même deux fonctions distinctes. Ou en utilisant other-than-&-keyword (par exemple ). Je ne vois tout simplement aucune méthode sûre pour résoudre automatiquement l'ambiguïté du point d'évaluation.

Je préfère suggérer quelque chose de less-plugin-bem-selectors

Absolument. L'extraction basée sur les expressions régulières était juste pour fournir un exemple qui n'impliquait pas de fonctions personnalisées. ;)

Je ne suis pas fan d'une construction de type fonction pour les sélecteurs.

Aussi, si vous voulez seulement dire à quoi ça ressemble ... Il pourrait s'agir d'une autre construction bien sûr, par exemple ⁞#foo:not(.bar)⁞ , mais vous savez que nous sommes déjà à court de symboles gratuits. Ainsi, la syntaxe de la pseudo fonction n'est suggérée que parce que nous avons déjà un tel concept avec url toute façon (donc pas besoin de penser à des choses qu'un nouveau concept pourrait ou va casser).

Maintenant, la partie amusante.

J'ai créé une implémentation rapide et sale de la fonction current-selector (juste pour voir à quel point cela pourrait être gonflé, en m'attendant bien sûr à ce que cela ne soit pas très utile à cause de var lazy-evaluation), et vous savez quoi ? Cet exemple basique :

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

donne r: div :)
Aucune idée exacte de la partie du code du compilateur qui gère ce comportement particulier, mais voici un exemple plus avancé pour illustrer la magie :

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

Il seulement [2] et [3] déclarations sont appelés deux fois (c. -à- fait-évalué paresseux), tandis que les [1] n'est pas (apparemment parce que la valeur ne contient pas de variables, bien que encore une fois, je ne sais pas si c'est intentionnel ou juste un effet secondaire d'une mise en cache, ou cela pourrait être un bogue chanceux dans mon code - par exemple, cette ligne peut déclencher un tel effet secondaire pour cette mise en cache - mais alors ce n'est pas clair pourquoi il est affecté par des variables supplémentaires - c'est-à-dire que davantage de recherches sont nécessaires).


C'est-à-dire qu'une version basée sur un plugin du context-saving-& semble être possible (sauf que bien sûr au lieu de <strong i="29">@var</strong>: & vous utiliserez quelque chose comme <strong i="31">@var</strong>: current-selector() ) Bien que la fonction ne devrait pas avoir des paramètres, sinon il est évalué paresseux (si une variable est transmise) - c'est triste car j'avais initialement prévu qu'il en aurait quatre :).
Assez abusif mais pourrait servir de solution de contournement/polyfill. Un exemple plus réel fonctionne également comme vous le souhaitez :

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

c'est-à-dire que les affectations de variables/appels de fonction ultérieurs n'affectent pas le point d'évaluation de la variable initiale.

@sept-phases-max
Aimer.

Même si l'évaluation paresseuse jette actuellement une clé dans les travaux lorsqu'un argument de paramètre est présent, _that_ est probablement quelque chose qui peut être contourné pour une implémentation «réelle».

Aussi, si vous voulez seulement dire à quoi ça ressemble... Il pourrait s'agir d'une autre construction bien sûr, par exemple ⁞# foo:not (.bar)⁞, mais vous savez que nous sommes déjà à court de symboles libres.

Assez juste. Je n'ai pas vraiment réfléchi à ce sujet en ce qui concerne l'utilisation et je n'ai pas de meilleures idées. Je suppose qu'il semblait quelque chose de spécial à ce sujet, mais peut-être pas. Je sais qu'il y a eu une discussion à un moment donné sur $() , mais nous avons fini par nous approprier $ . Au fait, ne serait-ce pas selectors() et non selector() ? Ne peut-il pas (comme le & ) contenir un nombre quelconque de sélecteurs ?

Et il semble que selector(&) plus de sens que current-selector() . C'est-à-dire : "créer une liste de sélection à partir d'un objet X, que ce soit & ou une chaîne". Quelle que soit la syntaxe finale, il semble que cela prendrait & comme argument.

Et il semble que selector(&) plus de sens que current-selector()

Ce sont des choses différentes. current-selector n'est qu'une variante de fonction de & (puisque cette dernière n'est pas prise en charge par l'analyseur). Alors que selector(...) est ce correctif permettant à l'analyseur de prendre en charge un sélecteur arbitraire (incl. & ).


Quant à selectors - eh bien, ça l'est. Mais comme il s'agit de 99% des cas d'utilisation à sélecteur unique, je suppose qu'une forme plurielle semblerait moins évidente pour la plupart des utilisateurs (dans la plupart, ils intitulent généralement h1, h2, h3 {} tant que sélecteur et continuent de parler de Moins de sélecteur parent (même si elle s du sélecteur) :) Alors , pourquoi la peine?

Ah ok.

@matthew-dean
La forme au pluriel et au singulier est à peu près interchangeable pour n'importe qui, sauf pour les auteurs de spécifications CSS. En fait, faites cela : pour tous, y compris les auteurs de spécifications, car même les spécifications CSS elles-mêmes sont parfois la proie d'une utilisation intervertie du singulier et du pluriel.

Assez hilarant ; le terme pluriel « sélecteurs » n'est même pas la manière officielle de désigner un ensemble séparé par des virgules. La terminologie strictement correcte pour la forme plurielle est, je crois, une _liste de sélection_.

Vous pouvez donc en quelque sorte voir à quel point cette référence ambiguë est profondément enracinée.

La terminologie strictement correcte pour la forme plurielle est, je crois, une liste de sélection.

Ouais, j'ai aussi fait une recherche w3c hier, c'est "groupe de sélecteurs", "une liste de sélecteurs" etc. avoir là :) Juste la forme "sélecteurs" est principalement utilisée ici pour décrire la chose "types de sélecteurs".

"Un sélecteur est une chaîne d'une ou plusieurs séquences de sélecteurs simples séparés par des combinateurs"

Et pour tous ceux qui pensent que cela pourrait faire référence à des listes séparées par des virgules : ce n'est pas le cas. La forme complète de cette citation devrait être : "un sélecteur _complexe_ est une chaîne d'une ou plusieurs séquences de sélecteurs simples séparés par des combinateurs."

Les spécifications CSS ont un autre problème où la forme généralisée de "sélecteur" est principalement utilisée pour faire référence à ce que les spécifications appellent officiellement _sélecteurs complexes_. Les sélecteurs complexes sont des sélecteurs simples, par exemple tag ; #id ; .class ; [attr] ; etc. , chaîné via des combinateurs, par exemple > ; + ; ~ , etc.

Quelque chose comme ul > li est appelé un sélecteur complexe.


ATTENTION, ce qui suit sera un peu un coup de gueule :

Les spécifications CSS sont malheureusement un bourbier de terminologie incohérente et mal nommée. Plus on recule, plus ça empire progressivement. Cela n'aide pas que des tas de modules CSS3 continuent de se référer aux modules CSS 2.1 ou que de nouveaux modules CSS3 aient été spécifiés en copiant textuellement leur ancienne documentation CSS 2.1. Les spécifications des sélecteurs et le modèle de formatage visuel sont cependant les pires contrevenants ; tant de terminologie ambiguë, à consonance similaire ou simple et mal nommée.

Prenez par exemple quelque chose de bien moins trivial que ul > li , comme [*|attr^="value" i] . Ce dernier est techniquement classé comme un simple sélecteur. (Oui vraiment.)

Il y a quelques années, j'ai dû essayer d'expliquer certaines parties de la dernière spécification du modèle de formatage visuel à l'un de mes collègues les plus axés sur la conception. Je pense que quelques fusibles ont en fait sauté dans _les deux_ nos cerveaux pendant que nous examinions les passages qui traitent du concept de boîtes de ligne et ce n'était même pas le pire. (Essayez de marcher dans le la-la-land magique qui est le modèle de formatage de table, si vous avez peu de valeur pour votre santé mentale.)

Les joies multiples de la documentation des projets open source...

Prenez par exemple quelque chose de bien moins trivial que ul > li , comme [*|attr^="value" i] . Ce dernier est techniquement classé comme un simple sélecteur

Cela a du sens pour moi, lol, juste parce qu'il n'utilise pas de combinateur. Il suit précisément la définition. Ce n'est pas parce qu'il utilise beaucoup de symboles qu'il est plus "complexe". ul > li est complexe car il implique deux ensembles de requêtes, c'est-à-dire rechercher tous les éléments correspondant à li , puis parcourir l'arbre à partir de chacun pour déterminer lesquels sont contenus avec un ul . Ce dernier ne teste qu'une seule fois les éléments individuels. C'est une requête donc c'est un simple sélecteur.

le terme pluriel « sélecteurs » n'est même pas la manière officielle de désigner un ensemble séparé par des virgules. La terminologie strictement correcte pour la forme plurielle est, je crois, une liste de sélection.

Exact, vous avez raison. Les "sélecteurs" ne sont en réalité que les bits définis qui vous permettent de sélectionner des éléments, mais ul > li > .title est un "sélecteur" au singulier. Donc je suppose que selector() est, en fait, peut-être plus proche sémantiquement.

@sept-phases-max

Je viens de rencontrer un autre problème mineur avec la fonction de plugin quick-n-dirty : il ne gère pas correctement l'accès à partir d'un mixin avec espace de noms. Les espaces de noms sont un cadre de type Ruleset normal et donc leur nom est ajouté dans les sélecteurs.

Une véritable implémentation devrait probablement couvrir ce cas également.


[ÉDITER]
L'astuce pour le faire fonctionner est de vérifier si l'un des cadres de la pile du contexte de la fonction est un MixinDefinition et s'il _is_, ignorez les prochains x cadres sur cette pile, où x est égal au nombre d'images sur la pile du MixinDefinition .

(Fondamentalement, cela ignore les cadres de « fermeture » ​​qui sont ajoutés dans la pile lorsqu'un MixinCall exécute le MixinDefinition .)

Suppression de l'étiquette « vicié ». C'est encore une bonne question à explorer.

Peut-être que current-selector() n'est pas si mal. Bien que, pour être clair, ce serait en fait current-selectors() . Mais c'est encore un peu verbeux. Je pense que je serais plus en faveur si nous pouvions penser à un nom de fonction pour "capturer &" qui soit plus concis.

nom de la fonction pour "capturer &" qui est plus concis.

Nommez-le simplement &() . Ce n'est conceptuellement rien de plus qu'un getter pour ce qu'il y a dans & après tout.
Par exemple

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

??
Ouais, ça devrait aller. Des objections?

Je vais essayer de résumer pour voir si je comprends bien la fonctionnalité proposée :

La nouvelle fonction &() renvoie ce que & produirait dans le contexte actuel, en tenant compte de cela.

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

Et que tout produirait ceci.

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

Parce que c'est incroyable, et j'adore ça.

En y réfléchissant davantage, je pense que le plus convaincant pour moi (après un premier passage; arrêtez-moi si je deviens trop fou) serait la possibilité d'avoir un style de "bloc" (règle) de composant standardisé. Fondamentalement, j'espérais presque qu'au lieu d'une simple valeur de chaîne de sélection enregistrée, la fonction serait mappée sur _" & , mais dans la portée la variable a été définie dans"_, ce qui permettrait ce style de création pour un composant (j'appellerai ce comportement A ):

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

Ensuite, je pourrais dire "utiliser @this partout au lieu de & ".

Ma seule préoccupation serait le cas flip (que j'appellerai le comportement B ), mais je ne peux pas penser à un cas convaincant où je voudrais ce comportement. C'est que je ne vois pas pourquoi quelqu'un voudrait faire ça.

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

Parce que la façon actuelle d'y parvenir est _beaucoup_ plus concise (et lisible, aussi, une fois que & est clair dans votre vocabulaire).

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

Existe-t-il des arguments convaincants (à part la difficulté de mise en œuvre) pour le comportement B par rapport au comportement A ?

Ce n'est là qu'une des questions auxquelles je pense qu'il faut répondre avant le début des travaux.


TL;DR : Mon vote est pour que &() soit dynamique, ce qui signifie essentiellement _" & , mais comme s'il était imbriqué ici au lieu de plus profond"_, plutôt que de renvoyer un statique _"la valeur de & ce moment."_

@calvinjuarez Vos exemples sont quelque peu déroutants car vous

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

signifiant essentiellement "&, mais comme s'il était imbriqué ici au lieu de plus profond", plutôt que de renvoyer un statique "la valeur de & en ce moment".

Je ne comprends vraiment pas ce que cela signifie.

Une autre façon de penser à cela. Cette:

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

Est l'équivalent d'écrire :

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

@matthew-dean

Oui. Mais pensez-y à travers le prisme des mixins, où &() saisirait le contexte du sélecteur de l'appelant mixin.

Il permet d'écrire des composants basés sur mixin où les auteurs eux-mêmes peuvent librement décider de la racine du nom de classe d'une manière naturelle. par exemple donné

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

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

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

les mixins utilisés là-bas pourraient lire la classe via &() et l'intégrer dans leur sortie de manière appropriée. Par exemple, le sélecteur capturé pour les deuxième et troisième règles pourrait avoir la syntaxe BEM décomposée pour obtenir la classe de bloc de base, qui pourrait être utilisée pour générer des remplacements pour les sélecteurs d'éléments imbriqués.

C'est-à-dire; il pourrait être utilisé pour générer un sélecteur comme .my-button--wide > .my-button__text , sans avoir besoin de passer des noms de sélecteurs comme paramètres. Uniquement à partir du contexte du sélecteur d'appelé.


Les _usines de composants_ basées sur Mixin comme celle-ci évitent bon nombre des problèmes de tout ou rien sur notre chemin ou sur l'autoroute que vous rencontrez avec l'utilisation de frameworks de style. Ils vous permettent d'enregistrer le framework, mais de choisir de manière granulaire les composants que vous souhaitez réellement incorporer et sous quel nom.

@rjget

les mixins utilisés là-bas pourraient lire la classe via &() et l'intégrer dans leur sortie de manière appropriée. Par exemple, le sélecteur capturé pour les deuxième et troisième règles pourrait avoir la syntaxe BEM décomposée pour obtenir la classe de bloc de base, qui pourrait être utilisée pour générer des remplacements pour les sélecteurs d'éléments imbriqués.

Oui, je comprends. C'est probablement le plus utile dans les mixins. J'obtiens définitivement l'utilité de &() en utilisant le nom du sélecteur direct. Mon propos était juste d'essayer de clarifier la valeur de &() dans l'exemple donné.

Pour aller plus loin, je pense que c'est une bonne solution syntaxique, et je donnerais personnellement un pour aller de l'avant avec l'implémentation de &() , si quelqu'un voulait s'en charger.

@matthew-dean

Vos exemples sont quelque peu déroutants car vous n'écrivez pas le résultat attendu

Oups, excuses. Je vais le reformuler correctement. J'ai l'impression que &() serait une fonctionnalité plus puissante si le Less ici était compilé dans le CSS ci-dessous.

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

Si <strong i="15">@this</strong>:&(); se comporte exactement comme <strong i="17">@this</strong>:.component; dans ce cas, nous reléguons cette fonctionnalité à l'utilitaire _uniquement_ dans les mixins, mais je pense qu'elle a plus à offrir.

signifiant essentiellement "&, mais comme s'il était imbriqué ici au lieu de plus profond", plutôt que de renvoyer un statique "la valeur de & en ce moment".

Je ne comprends vraiment pas ce que cela signifie.

Cela signifie que je pense que .thing{ & {} } et .thing{ <strong i="11">@amp</strong>:&(); @{amp} {} } devraient produire la même sortie.

Cela signifie, plus concrètement, que vous n'avez pas besoin d'écrire un mixin pour faire du BEM facile, mais que vous pouvez le définir en ligne. Pour revenir à l'un de mes anciens exemples :

_composant.moins_

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

??

_composant.css_

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

L'avantage : Vous n'avez pas à demander à votre équipe si elle veut dire & ou @{this} . Vous dites simplement "Utilisez simplement @{this} partout".

Cela rendrait également une définition de mixin d'usine de composants plus cohérente en interne.

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

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

Cela signifie que je pense que .thing{ & {} } et .thing{ @amp :&(); @{amp} {} } devrait produire la même sortie.

Oui, je pense que nous disons les mêmes choses mais permettez-moi de confirmer avec cet exemple. C'est ainsi que je vois cette fonctionnalité par rapport au & .

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

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

Tandis que:

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

Produirait :

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

@calvinjuarez Je suppose que j'étais confus parce que je pense que personne ne suggérait quelque chose de différent de votre exemple. &() serait essentiellement comme this.selectors.toCSS() évalué à cet endroit ( pas vraiment, mais juste à titre d'illustration .... en fait, cela pourrait être le moyen le plus rapide de le faire). Et puis en insérant cette chaîne à d'autres endroits pour être réévaluée en tant que sélecteurs.

@matthew-dean
Ce serait même _plus_ génial si cela exposait la liste des sélecteurs en tant que liste réelle de sélecteurs, y compris le comportement spécial pour développer les sélecteurs en fonction de tous les membres de la liste.

Avoir par exemple

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

  @{this} {
    c : d;  
  }
}

sortir

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

tout comme les & natifs le feraient.

Oui, c'est exactement ce qu'il ferait. Dans 3.5, toutes les variables évaluées dans les sélecteurs entraînent la réanalyse de la liste de sélecteurs entière en tant que nouvelle liste de sélecteurs. Alors oui, cela fonctionnerait comme prévu. C'est en fait assez facile à cause de quelques relations publiques récentes que j'ai faites.

Le 7 juillet 2018, à 10h34, rjgotten [email protected] a écrit :

@matthew-dean
Ce serait en fait encore plus génial si cela exposait la liste de sélecteurs en tant que liste réelle de sélecteurs, y compris le comportement spécial pour développer les sélecteurs en fonction de tous les membres de la liste.

Avoir par exemple

.un B {
@ceci : &();

@{cette} {
c : d ;
}
}
sortir

.a .a,
.un B,
.b. .une,
.un B {
c : d
}
tout comme le natif et le ferait.

-
Vous recevez ceci parce que vous avez été mentionné.
Répondez directement à cet e-mail, affichez-le sur GitHub ou coupez le fil de discussion.

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

Le .component supplémentaire est ce contre quoi je m'oppose. Je suggère que cela devrait fonctionner comme ceci:

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

Il semble que la fonctionnalité aille dans une direction différente cependant. Je voulais juste clarifier ma position.

Je suggère que cela devrait fonctionner comme ceci:

C'est-à-dire que s'il y a un jeton de substitution dans un sélecteur qui est une _liste de sélection_ au lieu d'une simple _chaîne_, alors le jeton de substitution agit de la même manière que si & était spécifié et il _désactive_ l'enchaînement normal des sélecteurs qui résulte de l'imbrication.

Si &() produisait un type de nœud qui le rend identifiable en tant que liste de sélecteurs réelle, ce comportement serait relativement facile à réaliser, je pense.

En fait, s'il devait générer un type de nœud dédié, cela pourrait également aider à la création de fonctions de plugin pour _manipuler_ la liste de sélection capturée, plus tard.

Pour moi, cela ressemble à faire faire trop de travail à &() à la fois. Si vous voulez qu'il enregistre les sélecteurs dans une variable, c'est une chose, mais que cette variable désactive le chaînage des sélecteurs en raison de son _contenu_ ne serait pas clair dans la syntaxe. Cette variable pourrait provenir de n'importe où (par exemple, passée d'un mixin) et la liste de sélection pourrait être générée par simple affectation de variable. C'est-à-dire qu'il n'est pas clair d'après l'utilisation des variables qu'un comportement de chaînage différent se produirait en fonction du contenu de la variable.

Je pense que si vous vouliez désactiver le chaînage, vous devrez spécifier que vous souhaitez remplacer l'implicite & par une autre valeur, comme (pardonnez le formatage, je suis sur mon téléphone) -

.composant {
@var : &();
&(@var)_child {} // ou une telle syntaxe de « remplacement de & »
}

Je comprends donc pourquoi le résultat est souhaitable, mais à l'OMI, nous ne pouvons pas simplement « commuter par magie » le comportement de fusion de variables en fonction de l'origine de la liste de sélection. Cela nécessite deux fonctionnalités différentes.

ooh... J'aime bien le truc de &(...) ...

Ah, vraiment ? Vous ne pensez pas qu'il y aurait une confusion sémantique entre &() (capturez les sélecteurs à partir de &) et &(@arg) (remplacez & par les sélecteurs) ?

Vous voudrez peut-être envisager de ne pas les mélanger, car quelqu'un pourrait vouloir remplacer & par un sélecteur vide afin de l'éliminer essentiellement. (Pour placer un enfant à la racine.) Bien que je suppose que cela pourrait être &(“”) .child?

Je ne sais pas, cela mérite réflexion/considération.

De plus, comme indiqué dans le fil de discussion « les sélecteurs parents devraient avoir des cibles », il existe des cas d'utilisation pour remplacer des parties spécifiques du sélecteur hérité (ou entièrement), donc en pensant à cela, je pense que ceux-ci devraient être suivis comme deux problèmes distincts. Ce problème ne devrait concerner que la capture et

Juste pour fermer ce cercle, voici où j'ai mentionné la modification de & sur place avec une construction de type fonction. - https://github.com/less/less.js/issues/1075#issuecomment-397697714

Donc, je préférerais que la discussion sur "comment/si modifier l'héritage de & " reste dans le fil des sélecteurs parent, et ce fil est de savoir si <strong i="9">@var</strong>: &() est approprié ou non pour capturer l'in -placez le sélecteur & sur une variable. Ce qui, dans mon esprit, semble toujours correct, malgré l'autre fil. Je ne sais pas s'il est possible de faire les deux ou non.

j'essaye de faire ça

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

mais cela ne fonctionnera pas tant que cela ne sera pas mis en œuvre

Cette page vous a été utile?
0 / 5 - 0 notes