Less.js: Guardando el selector en una variable

Creado en 20 abr. 2017  ·  50Comentarios  ·  Fuente: less/less.js

Tenemos esta solución:

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

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

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

Propongo agregar una función: escribir <strong i="9">@r</strong>: &; lugar de <strong i="11">@r</strong>: ~".selector"; para obtener el selector actual y guardarlo en cualquier variable.

Ejemplos:

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

Curiosamente, estaba absolutamente seguro de que tal solicitud ya existe. Aparentemente no lo es.
(Aunque, obviamente, la idea apareció en muchas entradas antes: # 1174, https://github.com/less/less.js/issues/1075#issuecomment-16891103, etc.)
Así que déjalo ser, supongo.


Por cierto, por si acaso (y para recopilar algunos casos de uso para pensar en posibles conflictos impl./sintaxis):
¿Cómo vas a usarlo? Sospecho que en muchos casos no funcionará de la manera esperada debido a la evaluación diferida. P.ej:

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

resultará en:

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

Porque el @r se evalúa realmente dentro de a b (es decir, dónde se usa, no en el punto en el que lo define).
(Así que sospecho que ciertos casos de uso pueden requerir alguna otra construcción de lenguaje para esto, no solo una variable. Y muchos otros casos de uso relacionados se consideraron antes como un tema de # 1075).

en muchos casos, no funcionará de la manera esperada debido a la evaluación diferida
Sospecho que ciertos casos de uso pueden requerir alguna otra construcción de lenguaje para esto, no solo una variable

Necesitaría esa construcción de lenguaje especial para capturar el contexto del selector en el punto en el que está definido, no en el punto en el que se llama mediante la evaluación de la variable a la que está asignado. La evaluación debería simplemente emitir el contexto que se capturó en el sitio de definición.

No es muy diferente de buscar variables por cierre, pero sí; requerirá una construcción de lenguaje especial y no una función.

@rjgotten

Sí, supongo que hemos estado discutiendo alguna pseudo-función selector anteriormente (pseudo porque un análisis de función regular no puede manejar todos los combinadores específicos del selector de todos modos) y luego porque es pseudo (es decir, un tipo dedicado como Url ) no sería un problema hacer que extraiga su contexto de definición dentro (si recuerdo correctamente, los DR hacen exactamente lo mismo).
Entonces, algo como <strong i="10">@foo</strong>: selector(&); podría hacer un truco, supongo. Aunque luego surge un siguiente problema menor:

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

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

Por lo tanto, posiblemente requiera otro operador / palabra clave de & . (O tal vez solo una pseudo-función dedicada, por ejemplo, current-selector() ... Hmm, eso me lleva a la idea de codificar un tipo PseudoFunction genérico para no contaminar la API de cada pequeño detalle, ¡ay! :).

Sé que hay una vacilación general para agregar cosas nuevas al idioma, pero un especificador de selector podría ser útil. Me gusta | , aunque es parte de la sintaxis del selector de | pueda _ iniciar_ un selector, por lo que no debería entrar en conflicto. Lo estoy usando porque me recuerda el "valor absoluto" de Math, que parece vagamente apropiado, y porque es simple. Solo un pensamiento para inspirar conversación.

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

(De hecho, ¿podría usarse para designar que _cualquier_var debería procesarse de inmediato y almacenarse, o lo que sea? Pero eso se siente como si fuera un _way_ over-scoping.)

¿Es normal & o saved-context-& ?

Yo diría que el contexto del selector debe capturarse en el sitio donde se llama la pseudo-función selector() y & debe evaluarse dentro de _ ese_ contexto y el resultado final debe asignarse a este nuevo tipo del nodo de árbol Selector .

Cuando _cualquier_ variable que contenga un Selector tipo de nodo de árbol se interpola en un selector, como es el caso del uso de @{var} en el ejemplo, el selector resultante debe construirse de la misma manera como cuando un interpolador & está presente en el selector, es decir; no se una y prefija con los selectores de un nivel de anidamiento hacia arriba.

El razonamiento detrás de esto es que ambos son selectores capturados: selector() es uno capturado por el usuario, mientras que & es el selector 'padre' siempre presente y capturado.

Entonces, si un usuario requiere la interpolación de un nodo Selector capturado junto con el contexto del selector _current_, puede ser explícito al respecto. Por ejemplo, & @{var} { ... }

Para concluir

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

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

debería generar

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

Mientras que

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

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

debería generar

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

Hmm, @{var} frente a & @{var} parece bastante artificial, simplemente no es así como funcionan estas cosas en Less. ... { & div ... y ... { div ... siempre fueron declaraciones iguales. Además, sin contar esto, ¿qué debo hacer si necesito a b x, #y a b .z con x, #y * .z definido en otro lugar?

No soy fanático de una construcción similar a una función para los selectores. Sin embargo, apoyo la posibilidad de hacer referencia, modificar o transportar (asignar a variables y reutilizar) selectores heredados.

Sin embargo, solo para asegurarnos de qué parte de esto es una variación del n. ° 1075 (dirigidos a selectores principales) o en posible conflicto con https://github.com/less/less-meta/issues/16#issuecomment -292679320 (asignando un solo selector a una variable)? ¿O es esto diferente a los mixins de alias porque se trata de una lista de selectores y no de un solo selector evaluado (o mixin), y la salida es la lista de selectores y no el conjunto de reglas evaluado? Supongo que esta característica es diferente; Solo quiero asegurarme de que todos estos se muevan en la misma dirección.

@ matthew-dean
De hecho, se trata de capturar la lista de selectores real, no de capturar el conjunto de reglas evaluado y generar dicha lista para su uso posterior.

Uno podría imaginar una función como extract(list,index) que se actualizará para poder extraer también los componentes del selector de una lista de selectores y mejoras similares para facilitar el trabajo con los selectores, de modo que los usuarios puedan manipularlos fácilmente de formas interesantes. Por ejemplo, para componentes que siguen ciertos esquemas de nomenclatura como BEM.

Por ejemplo, dado 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;
    }
  }
}

Los siguientes Less

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

genera CSS

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

Sass, afaik, ha tenido esto durante mucho tiempo y hay numerosos ejemplos de esta técnica que se está utilizando de manera muy inteligente. En fábricas de código como en mi ejemplo, o para otros fines.

Como para:

posible conflicto con less / less-meta # 16 (comentario) (asignando un solo selector a una variable)

Personalmente asumo el siguiente comportamiento:
Valores de selector "triviales" (por ejemplo, .mixin , .ns.mixin , #foo .bar , baz etc, afortunadamente esto cubre todo lo que se puede usar / definir como mixin / function ) se asignan a una variable (o se pasan como parámetros para funcionar) directamente . Es decir, ya tenemos esto:

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

^ Esto no tiene (esencialmente) nada que ver con los selectores en absoluto: estos valores se (intentan) convertir a un formato de selector (para buscar un mixin) solo cuando intentamos llamarlos / evaluarlos con @var(...) o @var[...] declaraciones
(En general, la convención lógica sería olvidar que los identificadores mixin son (representados internamente como) selectores, pero siempre pensar en ellos como identificadores con solo un punto o # prefijo .ns > .mixin para desvanecerse eventualmente como redundante e inútil :)

Mientras que los selectores complejos o "reales" requieren una pseudo función selector debido a la ambigüedad de sintaxis / analizador. Es decir, cosas como:

  • <strong i="29">@var</strong>:foo>bar <- selector y (potencialmente) una expresión lógica
  • <strong i="32">@var</strong>:.1+.2; <- expresión aritmética y selector Less válido
    (etc., simplemente recuerde todos los símbolos de selector específicos; casi todos los conflictos con algo en un contexto de análisis de valores, y esto se vuelve aún más dramático cuando los valores anteriores se pasan potencialmente a una función / mezcla como parámetros en su lugar, por ejemplo, lo siguiente es simplemente imposible para apoyar sin selector() :
    less: some-function(abc, selector(#foo .is :not(> bar)[baz="qux"], abc), selector(bla), 42); // ^ remove `selector()` and try to parse

No soy fanático de una construcción similar a una función para los selectores.

En resumen, la pseudo función selector solo es necesaria para eliminar cualquier conflicto de sintaxis y semántica actual y potencial de una vez por todas. Así que dudo que realmente tengamos demasiadas opciones aquí (los contextos de análisis de valor y selector solo deben separarse de alguna manera).


(Todo lo anterior no significa que un valor devuelto por selector() no pueda usarse como una entidad invocable, por ejemplo, @var() , probablemente podría, pero eso sería simplemente innecesario / inútil, por lo que apenas vale la pena molestar).

@rjgotten

Uno podría imaginar una función como extract(list,index) para actualizarse para poder extraer también el selector

Claro que podríamos ajustar las funciones para que funcionen con cadenas asumiendo que dicha cadena puede contener algún selector, pero eso significa que todas esas funciones (no solo extract ) deben actualizarse / ajustarse / modificarse. El enfoque opuesto sería más eficiente / menos oneroso. Es decir, es una función de conversión selector-string->values dedicada, O incluso devolver la estructura adecuada de los nodos directamente por selector (en cualquier caso, la parte más complicada es cómo empaquetar / desempaquetar combinadores selectores en cada uso -el caso puede preferir una representación diferente).

(Tenga en cuenta que la función de interpolación del selector en sí misma todavía tiene que convertir @{var} a un formato adecuado al final de todos modos, por lo que realmente no importa en qué formato viene el valor de esa var, ya sea si es una cadena, anónimo o lo que sea estructura de los nodos: la mayor parte de los trucos de conversión siguen siendo los mismos).

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

Para ser honesto, esto parece una reencarnación de "JavaScript en línea y piratería tipo LessHat", no se puede prohibir pero se anunciará agresivamente.
(Sin contar que el ejemplo es bastante desafortunado <- cuente las líneas) Preferiría sugerir algo less-plugin-bem-selectors (donde simplemente puede tener una función get-block-name , por cierto. Incluso sin el & característica) en lugar de expresiones regulares tan desagradables (el enfoque de "Usar un preprocesador CSS como un procesador de texto arbitrario" eventualmente perderá mucho al final en cosas similares a PostCSS).

Y volviendo a & vs context-saving-& , hasta ahora me temo que no tengo mejores ideas que una bandera dedicada para la función, por ejemplo, selector(..., lazy or not) , o incluso dos funciones separadas. O usando other-than-&-keyword (por ejemplo, ). Simplemente no puedo ver ningún método seguro para resolver automáticamente la ambigüedad del punto de evaluación.

Prefiero sugerir algo less-plugin-bem-selectors

Absolutamente. La extracción basada en expresiones regulares fue solo para proporcionar un ejemplo que no involucraba funciones personalizadas. ;)

No soy fanático de una construcción similar a una función para los selectores.

Además, si solo te refieres a cómo se ve ... Podría ser otra construcción, por ejemplo, por ejemplo, ⁞#foo:not(.bar)⁞ , pero sabes que ya nos hemos quedado sin símbolos gratuitos. Entonces, la sintaxis de la pseudo función solo se sugiere porque ya tenemos dicho concepto con url todos modos (por lo tanto, no es necesario pensar en cosas que un nuevo concepto podría o romperá).

Ahora, la parte divertida.

Creé una implementación de current-selector (solo para ver qué tan hinchado podría ser, esperando que, por supuesto, no pueda ser muy útil debido a var lazy-Evaluation), y ¿sabes qué? Este ejemplo básico:

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

resultados en r: div :)
No tengo idea exactamente de qué parte del código del compilador maneja este comportamiento en particular, pero aquí hay un ejemplo más avanzado para ilustrar la magia:

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

Allí solo las declaraciones [2] y [3] se llaman dos veces (es decir, en realidad evaluadas de forma perezosa), mientras que [1] no (aparentemente porque el valor no contiene ninguna variable, aunque una vez más, no sé si esto es intencional o solo un efecto secundario de algún almacenamiento en caché, o podría ser un error afortunado en mi código; por ejemplo, esta línea puede desencadenar tal efecto secundario para este almacenamiento en caché , pero entonces no está claro por qué se ve afectado por variables adicionales, es decir, se necesita más investigación).


Es decir, una versión basada en un complemento de context-saving-& parece ser posible (excepto que, por supuesto, en lugar de <strong i="29">@var</strong>: & usará algo como <strong i="31">@var</strong>: current-selector() ), aunque la función no debería tiene algún parámetro, de lo contrario, se evalúa de forma diferida (si se pasa una variable); esto es triste ya que inicialmente planeé que tuviera cuatro :).
Bastante abusivo, pero podría servir como solución / polyfill. Un ejemplo más real también funciona como se desee:

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

es decir, las asignaciones de variables / llamadas de funciones posteriores no afectan el punto de evaluación de la variable inicial.

@ siete-fases-max
Me encanta.

Incluso si la evaluación perezosa actualmente arroja una llave en las obras cuando un argumento de parámetro está presente, _eso_ es presumiblemente algo que se puede solucionar para una implementación 'real'.

Además, si solo te refieres a cómo se ve ... Podría ser otra construcción, por ejemplo, por ejemplo, ⁞ # foo: not (.bar) ⁞, pero sabes que ya nos hemos quedado sin símbolos libres.

Lo suficientemente justo. Realmente no he envuelto mi cerebro sobre esto en cuanto al uso ni tengo mejores ideas. Supongo que parecía haber algo especial en esto, pero tal vez no. Sé que hubo una discusión en algún momento sobre $() , pero terminamos apropiándonos de $ . Por cierto, ¿no sería selectors() y no selector() ? ¿No puede (como el & ) contener cualquier número de selectores?

Y parece que selector(&) tiene más sentido que current-selector() . Es decir: "hacer una lista de selección a partir del objeto X, ya sea & o una cadena". Cualquiera que sea la sintaxis final, parece que tomaría & como argumento.

Y parece que selector(&) tiene más sentido que current-selector()

Son cosas diferentes. current-selector es solo una variante de función de & (ya que el analizador no admite esta última). Mientras que selector(...) es ese parche para que el analizador admita un selector arbitrario (incluido & ).


En cuanto a selectors , bueno, lo es. Pero dado que es el 99% de los casos de uso de un solo selector, supongo que una forma plural sonaría menos evidente para la mayoría de los usuarios (en la mayoría, por lo general, titulan h1, h2, h3 {} como selector y siguen hablando de Less selector principal (incluso si es selector s ) :) Entonces, ¿por qué molestarse?

Ah, vale.

@ matthew-dean
La forma plural y singular es prácticamente intercambiable para cualquiera, excepto para los autores de especificaciones de CSS. De hecho, haga eso: para cualquiera, incluidos los autores de las especificaciones, ya que incluso las propias especificaciones CSS son presa del uso intercambiado de la forma singular y plural a veces.

Muy graciosamente; el término plural 'selectores' ni siquiera es la forma oficial de designar un conjunto separado por comas. La terminología estrictamente correcta para la forma plural es, creo, una _lista de selectores_.

Así que puedes ver cuán profundamente arraigada está realmente esta referencia ambigua.

La terminología estrictamente correcta para la forma plural es, creo, una lista de selección.

Sí, también busqué en w3c ayer, es "grupo de selectores", "una lista de selectores", etc., nada tan sofisticado como raro "Un selector es una cadena de una o más secuencias de selectores simples separados por combinadores" también have there :) Sólo la forma de "selectores" se usa principalmente allí para describir lo de "tipos de selectores".

"Un selector es una cadena de una o más secuencias de selectores simples separados por combinadores"

Y para cualquiera que piense que podría estar refiriéndose a listas separadas por comas: no lo es. La forma completa de esa cita debería ser: "un selector _complejo_ es una cadena de una o más secuencias de selectores simples separados por combinadores".

Las especificaciones CSS tienen otro problema donde la forma generalizada de "selector" se usa principalmente para referirse a lo que las especificaciones llaman oficialmente _ selectores complejos_. Los selectores complejos son selectores simples, por ejemplo, tag ; #id ; .class ; [attr] ; etc., encadenado a través de combinadores, por ejemplo, > ; + ; ~ , etc.

Algo como ul > li se llama selector complejo.


ADVERTENCIA lo siguiente será una perorata:

Las especificaciones de CSS son, lamentablemente, un lodazal de terminología inconsistente y mal nombrada. Cuanto más retrocede, peor se pone progresivamente. No ayuda que muchos módulos CSS3 sigan refiriéndose a los módulos CSS 2.1 o que los nuevos módulos CSS3 se hayan especificado copiando su antigua documentación CSS 2.1 textualmente. Sin embargo, las especificaciones para los selectores y el modelo de formato visual son los peores infractores; tanta terminología ambigua, que suena similar o que no tiene un nombre sencillo.

Tomemos, por ejemplo, algo mucho menos trivial que ul > li , como [*|attr^="value" i] . Este último se clasifica técnicamente como un selector simple. (Sí, en serio.)

También tuve que intentar explicar partes de la última especificación del modelo de formato visual a uno de mis colegas más orientados al diseño en un momento, hace unos años. Creo que algunos fusibles se fundieron en _ambos_ nuestros cerebros mientras repasábamos los pasajes que tratan el concepto de cajas de línea y eso no fue ni siquiera la peor parte. (Intente adentrarse en el mágico la-la-land que es el modelo de formato de tabla, si tiene poco valor para su cordura).

Diversos placeres de la documentación de proyectos de código abierto ...

Tomemos, por ejemplo, algo mucho menos trivial que ul > li , como [*|attr^="value" i] . Este último se clasifica técnicamente como un selector simple

Eso realmente tiene sentido para mí, jajaja, solo porque no usa un combinador. Sigue la definición con precisión. El hecho de que utilice muchos símbolos no lo hace más "complejo". ul > li es complejo porque implica dos conjuntos de consultas, es decir, consultar todos los elementos que coinciden con li y luego recorrer el árbol de cada uno para determinar cuáles están contenidos en un ul . Este último solo prueba elementos individuales una vez. Es una consulta, por lo que es un selector simple.

el término plural 'selectores' ni siquiera es la forma oficial de designar un conjunto separado por comas. La terminología estrictamente correcta para la forma plural es, creo, una lista de selección.

Correcto, tienes razón. Los "selectores" son en realidad los bits definidos que le permiten seleccionar elementos, pero ul > li > .title es un "selector" singular. Así que supongo que selector() está, de hecho, más cerca semánticamente.

@ siete-fases-max

Acabo de encontrar otro problema menor con la función del complemento quick-n-dirty: no maneja el acceso desde una mezcla de espacio de nombres correctamente. Los espacios de nombres son un marco de tipo Ruleset regular y, por lo tanto, su nombre se agrega a los selectores.

Una implementación real probablemente debería cubrir ese caso también.


[EDITAR]
El truco para que funcione es comprobar si uno de los fotogramas en la pila del contexto de la función es un MixinDefinition y, si lo es, omita los siguientes x fotogramas en esa pila, donde x es igual a la cantidad de marcos en la pila de MixinDefinition .

(Básicamente, esto omite los marcos de 'cierre' que se agregan a la pila cuando un MixinCall ejecuta el MixinDefinition .)

Se eliminó la etiqueta "obsoleta". Este sigue siendo un buen tema para explorar.

Quizás current-selector() no sea tan malo. Aunque, para ser claros, en realidad sería current-selectors() . Pero eso sigue siendo un poco detallado. Creo que estaría más a favor si pudiéramos pensar en un nombre de función para "capturar &" que sea más conciso.

nombre de función para "capturar &" que es más conciso.

Solo llámalo &() . Conceptualmente, no es más que un captador de lo que hay en & después de todo.
P.ej

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

🤔
Sí, eso debería estar bien. ¿Alguna objeción?

Intentaré resumir para ver si entiendo la función propuesta:

La nueva función &() devuelve lo que generaría & en el contexto actual, teniendo en cuenta esto.

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

Y que todo saldría así.

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

Porque eso es asombroso y me encanta.

Pensando más en esto, creo que lo más convincente para mí (después de un primer paso; deténgame si me estoy volviendo demasiado loco) sería la posibilidad de tener un estilo de "bloque" de componentes estandarizado (conjunto de reglas). Básicamente, casi espero que en lugar de guardar un valor de cadena de selector simple, la función se asigne a _ " & , pero en el alcance la variable se definió en" _, lo que permitiría este estilo de creación para un componente (llamaré a este comportamiento A ):

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

Entonces podría decir "use @this todas partes en lugar de & ".

Mi única preocupación sería el caso plegable (que llamaré Comportamiento B ), pero no puedo pensar en un caso convincente en el que quiera ese comportamiento. Es decir, no veo por qué alguien querría hacer esto.

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

Porque la forma actual de lograrlo es _mucho_ más concisa (y también legible, una vez que & está claro en su vocabulario).

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

¿Existe un caso convincente (además de la dificultad de implementación) para el comportamiento B sobre el comportamiento A?

Esta es solo una de esas preguntas que creo que deberían responderse antes de que comience el trabajo.


TL; DR: Mi voto es que &() sea ​​dinámico, lo que significa esencialmente _ " & , pero como si estuviera anidado aquí en lugar de más profundo" _, en lugar de devolver un _ "estático el valor de & ahora mismo. "_

@calvinjuarez Tus ejemplos son algo confusos porque no estás escribiendo el resultado esperado, por lo que parecen algo en el ámbito de lo teórico, pero básicamente:

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

que significa esencialmente "&, pero como si estuviera anidado aquí en lugar de más profundo", en lugar de devolver un "el valor de & ahora mismo" estático.

Realmente no entiendo lo que esto significa.

Otra forma de pensar en esto. Esta:

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

Es el equivalente a escribir:

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

@ matthew-dean

Si. Pero piénselo a través de la lente de los mixins, donde &() tomaría el contexto del selector de llamadas del mixin.

Permite escribir componentes basados ​​en mixin donde los propios autores pueden decidir libremente la raíz del nombre de clase de forma natural. Por ejemplo, dado

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

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

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

los mixins usados ​​allí podrían leer la clase a través de &() y trabajarla en su salida de manera apropiada. Por ejemplo, el selector capturado para la segunda y tercera reglas podría tener la sintaxis BEM descompuesta para obtener la clase de bloque base, que podría usarse para generar anulaciones para selectores de elementos anidados.

Es decir; podría usarse para generar un selector como .my-button--wide > .my-button__text , sin necesidad de pasar ningún nombre de selector como parámetro. Solo desde el contexto del selector de destinatarios.


Las _fábricas de componentes_ basadas en Mixin como esta evitan muchos de los problemas de todo o nada en nuestro camino o en la carretera que surgen al usar marcos de estilo. Le permiten registrar el marco, pero elegir de forma granular qué componentes desea incorporar realmente y con qué nombre.

@rjgotten

los mixins usados ​​allí podrían leer la clase a través de & () y trabajar en su salida de manera apropiada. Por ejemplo, el selector capturado para la segunda y tercera reglas podría tener la sintaxis BEM descompuesta para obtener la clase de bloque base, que podría usarse para generar anulaciones para selectores de elementos anidados.

Sí, lo entiendo. Probablemente sea más útil en mixins. Definitivamente obtengo la utilidad de &() usando el nombre del selector directo. Mi punto era simplemente tratar de aclarar el valor de &() en el ejemplo dado.

Para ir más allá, creo que es una buena solución sintáctica, y personalmente le daría un 👍 a seguir adelante con la implementación de &() , si alguien quisiera hacerlo.

@ matthew-dean

Sus ejemplos son algo confusos porque no está escribiendo el resultado esperado

Ups, disculpas. Lo reformularé correctamente. Siento que &() sería una característica más fuerte si Less aquí se compilara con el CSS a continuación.

.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>:&(); comporta como <strong i="17">@this</strong>:.component; en este caso, relegaremos esta función a la utilidad _sólo_ dentro de mixins, pero creo que tiene más que ofrecer.

que significa esencialmente "&, pero como si estuviera anidado aquí en lugar de más profundo", en lugar de devolver un "el valor de & ahora mismo" estático.

Realmente no entiendo lo que esto significa.

Significa que creo que .thing{ & {} } y .thing{ <strong i="11">@amp</strong>:&(); @{amp} {} } deberían producir el mismo resultado.

Significa, de manera más práctica, que no tiene que escribir un mixin para hacer BEM fácil, pero puede definirlo en línea. Volviendo a uno de mis ejemplos más antiguos:

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

El beneficio: no tiene que preguntarle a su equipo si se refieren a & o @{this} . Simplemente diga "Solo use @{this} todas partes".

En realidad, también haría que la definición de mezcla de una fábrica de componentes fuera más coherente internamente.

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

Significa que creo que .thing {& {}} y .thing { @amp : & (); @ {amp} {}} debería producir el mismo resultado.

Sí, creo que estamos diciendo lo mismo, pero permítanme confirmar con este ejemplo. Así es como veo esta función frente a la de & .

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

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

Mientras que:

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

Produciría:

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

@calvinjuarez Supongo que estaba confundido porque creo que nadie estaba sugiriendo algo diferente a tu ejemplo. &() esencialmente sería como this.selectors.toCSS() eval'd en esa ubicación ( no realmente, pero solo como ilustración ... en realidad, esa podría ser la forma más rápida de hacerlo). Y luego insertando esa cadena en otros lugares para ser reevaluada como selectores.

@ matthew-dean
En realidad, sería aún más impresionante si expondría la lista de selectores como una lista real de selectores, incluido el comportamiento especial para expandir los selectores en función de todos los miembros de la lista.

Tener por ejemplo

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

  @{this} {
    c : d;  
  }
}

producción

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

tal como lo haría el & nativo.

Sí, eso es exactamente lo que haría. En 3.5, cualquier variable evaluada en los selectores hace que toda la lista de selectores se vuelva a analizar como una nueva lista de selectores. Entonces sí, eso funcionaría como se esperaba. En realidad, es bastante fácil debido a algunas relaciones públicas que hice recientemente.

El 7 de julio de 2018, a las 10:34 a.m., rjgotten [email protected] escribió:

@ matthew-dean
En realidad, sería aún más asombroso si mostrara la lista de selectores como una lista real de selectores, incluido el comportamiento especial para expandir los selectores en función de todos los miembros de la lista.

Tener por ejemplo

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

@{esta} {
CD;
}
}
producción

.a .a,
.a .b,
.B. .a,
.a .b {
CD
}
al igual que los nativos y lo haría.

-
Recibes esto porque te mencionaron.
Responda a este correo electrónico directamente, véalo en GitHub o silencia el hilo.

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

El .component extra es contra lo que estoy discutiendo. Sugiero que debería funcionar así:

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

Sin embargo, parece que la función va en una dirección diferente. Solo quería aclarar mi posición.

Sugiero que debería funcionar así:

Es decir, si hay un token de sustitución en un selector que es una _lista de selectores_ en lugar de una _string_ simple, entonces el token de sustitución actúa de la misma manera que si se especificara & y _deshabilita_ el encadenamiento normal del selector que resulta del anidamiento.

Si &() generara un tipo de nodo que lo hiciera identificable como una lista de selectores real, ese comportamiento sería comparativamente fácil de lograr, creo.

De hecho, si fuera a generar un tipo de nodo dedicado, eso también podría ayudar a la creación de funciones de complemento para _manipular_ la lista de selectores capturados, más adelante.

Para mí, eso suena a hacer que & () trabaje demasiado a la vez. Si desea que guarde los selectores en una variable, eso es una cosa, pero que esa variable desactive el encadenamiento de selectores debido a su _contenido_ no sería claro en la sintaxis. Esa variable podría provenir de cualquier lugar (por ejemplo, pasada de un mixin) y la lista de selectores podría generarse mediante una simple asignación de variable. Es decir, no está claro a partir del uso de variables que se produzca un comportamiento de encadenamiento diferente en función del contenido de la variable.

Creo que si quisiera deshabilitar el encadenamiento, tendría que especificar que desea reemplazar el implícito y con otro valor, como (perdone el formateo, estoy en mi teléfono) -

.componente {
@var : & ();
& (@ var) _child {} // o alguna sintaxis de "reemplazo de &"
}

Entonces entiendo por qué el resultado es deseable, pero en mi opinión, no podemos simplemente el comportamiento de fusión de variables de "interruptor mágico" en función de dónde proviene la lista de selectores. Esto requiere dos características diferentes.

ooh ... de hecho me gusta la cosa &(...) ...

¿De verdad? ¿No cree que habría una confusión semántica de &() (capturar selectores de &) y &(@arg) (reemplazar & con selectores)?

Es posible que desee considerar no mezclarlos, ya que alguien podría querer reemplazar & con un selector vacío para descartarlo esencialmente. (Para colocar un niño en la raíz). Aunque supongo que tal vez podría ser &(“”) .child?

No sé, merece un poco de reflexión / consideración.

Además, como se indica en el hilo "los selectores principales deben tener objetivos", hay casos de uso para reemplazar partes específicas del selector heredado (o por completo), por lo que, pensando en eso, creo que deben rastrearse como dos problemas separados. Este problema debería ser solo sobre capturar y

Solo para cerrar este círculo, aquí es donde mencioné alterar & in situ con una construcción similar a una función. - https://github.com/less/less.js/issues/1075#issuecomment -397697714

Por lo tanto, preferiría que la discusión sobre "cómo / si alterar & herencia" permanezca en el hilo de los selectores principales, y este hilo trata sobre si <strong i="9">@var</strong>: &() es apropiado o no para capturar el -coloca el selector & en una variable. Lo cual, en mi opinión, todavía parece estar bien, a pesar del otro hilo. No estoy seguro de si existe la oportunidad de hacer ambas cosas o no.

Estoy tratando de hacer esto

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

pero eso no funcionará hasta que esto se implemente

¿Fue útil esta página
0 / 5 - 0 calificaciones