Less.js: Os seletores principais devem ter destinos

Criado em 13 dez. 2012  ·  118Comentários  ·  Fonte: less/less.js

Ao criar uma regra de seletor de pai, tudo antes de & é anexado ao escopo mais externo.

O recurso pode ser bastante aprimorado ao permitir a "segmentação pai", onde você pode aplicar o seletor pai a um pai específico (no caso de você ter seletores profundamente aninhados).

A sintaxe para este recurso é provavelmente o maior obstáculo, então eu adoraria iniciar uma discussão sobre as possibilidades.

feature request medium priority needs decision

Comentários muito úteis

Eu vou reabrir isso. Vimos variações dessa ideia (como #1154), e sinto que há uma possibilidade de solução.

Ou seja, há momentos em que as pessoas têm uma pilha lógica de elementos, mas não querem necessariamente herdar a pilha inteira em sua saída.

Além disso, há momentos em que as pessoas querem herdar ALGUMAS da pilha, mas não todas.

Acho que todos podemos concordar que não queremos sintaxe confusa, mas gostaria de ver uma variedade de ideias. Como exploramos aqui, a segmentação por nome parece problemática. Mas também podemos segmentar por nível:

.main-content {
    .button {
        .button-icon {
            background-image: @button-icon;
            &{2}:hover { background-image: @button-icon-hover; }
            &{2}.focus { background-image: @button-icon-focus; }
            .ie8 &{3} { background-image: @button-icon-ie8; }  // In this case, &{3} is the same as & because it goes to top
        }
    }
}

Basicamente, "suba" a árvore de herança para o nível que queremos herdar/anexar aos seletores atuais.

Ou, algo como, talvez "quebrar" a herança e começar de novo, sem ter que mover a classe para fora do bloco. não sei, tipo:

.grandparent {
  .parent {
    /.child {   // Ordered logically, but outputs cleaner CSS
      background: white;
    }
  }
  background: blue;
}

ou, pegando emprestado do exemplo principal:

.grandparent {
  .parent {
    &{0}.child {   // inherit NONE of the parents
      background: white;
    }
  }
  background: blue;
}

Ambos emitindo:

.grandparent {
  background: blue;
}
.child {
  background: white;
}

Pensamentos?

Todos 118 comentários

Exemplo de uso:

.main-content {
    .button {
        .button-icon {
            background-image: @button-icon;
            (.button):hover { background-image: @button-icon-hover; }
            (.button).focus { background-image: @button-icon-focus; }
            .ie8 (.main-content) { background-image: @button-icon-ie8; }
        }
    }
}

Este pode ser um exemplo artificial, mas tenho vários cenários do mundo real em que essa sintaxe seria um salva-vidas.

Há uma variedade de soluções em LESS para lidar com isso. Você pode atribuir variáveis ​​e usá-las como parte de cadeias de seletores (novo no 1.3.1, eu acho). O & não é realmente um seletor pai no sentido CSS4 do termo. Ele literalmente apenas anexa os seletores herdados onde quer que você os coloque.

Eu geralmente acabo escrevendo esses blocos de código assim:

.main-content {
    .ie8 & { background-image: @button-icon-ie8; }
    .button {
        &:hover { background-image: @button-icon-hover; }
        &.focus { background-image: @button-icon-focus; }
        .button-icon {
            background-image: @button-icon;
        }
    }
}

Eu faço a mesma coisa -- duplico meus blocos aninhados com as substituições. Em um cenário do mundo real, isso resulta em uma quantidade incontrolável de duplicação.
Para sua informação, no seu exemplo, o background-image precisa ser aplicado ao .button-icon , para que você tenha muito mais duplicação.

Você pode explicar "atribuir variáveis ​​e usá-las como parte de cadeias de seletores"?

Provavelmente estou errado sobre essa citação, então provavelmente não deveria tentar explicá-la. Ou seja, eu não tentei pessoalmente.

Então, parece que o que você quer fazer é modificar um seletor na cadeia herdada. Como isso funcionaria neste caso?

.button {
.main-content {
    .button {
        .main-content {
            .button-icon {
                background-image: @button-icon;
                (.button):hover { background-image: @button-icon-hover; }
                (.button).focus { background-image: @button-icon-focus; }
                .ie8 (.main-content) { background-image: @button-icon-ie8; }
            }
        }
    }
}
}

É CSS confuso, mas é CSS perfeitamente válido.

Esse é um bom exemplo... se o "destino pai" corresponder a vários itens, gostaríamos de escolher apenas um. Escolher o "mais próximo" é minha primeira reação. Mas acho que esse seria um caso extremo.

Até agora, rabisquei várias tentativas de inventar uma sintaxe que eu gosto... e o parêntese até agora é o meu favorito. Parece legível e definitivamente chama sua atenção para destacar que este não é um seletor normal.

O único problema - isso interfere em alguma regra de seletor CSS existente? Olhando para o lesser, vejo que um elemento seletor pode corresponder /\([^()@]\)/ , o que significa que já está sendo analisado corretamente. Não sei se esses parênteses são válidos.

Acabei de perceber que a sintaxe de parênteses se parece quase exatamente com uma definição de mixin ... com exceção da classe dot . . Então talvez não seja uma boa ideia. Comentários?

Seu caso de uso se parece com o que é discutido em #965 .. o que você acha?

Tendo em mente que & já é bastante poderoso e estamos trazendo :extend() em 1.4.0, parece-me que a única coisa que falta é poder chamar um mixin que adiciona seletores ao seu cadeia de seletores, então, se decidirmos adicionar essa funcionalidade, ela deve ser o mais simples possível.

Sim, sinto que, infelizmente, a lógica fica um pouco confusa e, como @agatronic , pode haver outras maneiras de preencher o que você deseja no futuro.

Eu concordo. Essa supercomplicação é resultado de uma estrutura LESS muito complicada, e o tempo provavelmente seria melhor gasto na simplificação do código LESS em vez de introduzir uma sintaxe muito complicada.

Eu vou reabrir isso. Vimos variações dessa ideia (como #1154), e sinto que há uma possibilidade de solução.

Ou seja, há momentos em que as pessoas têm uma pilha lógica de elementos, mas não querem necessariamente herdar a pilha inteira em sua saída.

Além disso, há momentos em que as pessoas querem herdar ALGUMAS da pilha, mas não todas.

Acho que todos podemos concordar que não queremos sintaxe confusa, mas gostaria de ver uma variedade de ideias. Como exploramos aqui, a segmentação por nome parece problemática. Mas também podemos segmentar por nível:

.main-content {
    .button {
        .button-icon {
            background-image: @button-icon;
            &{2}:hover { background-image: @button-icon-hover; }
            &{2}.focus { background-image: @button-icon-focus; }
            .ie8 &{3} { background-image: @button-icon-ie8; }  // In this case, &{3} is the same as & because it goes to top
        }
    }
}

Basicamente, "suba" a árvore de herança para o nível que queremos herdar/anexar aos seletores atuais.

Ou, algo como, talvez "quebrar" a herança e começar de novo, sem ter que mover a classe para fora do bloco. não sei, tipo:

.grandparent {
  .parent {
    /.child {   // Ordered logically, but outputs cleaner CSS
      background: white;
    }
  }
  background: blue;
}

ou, pegando emprestado do exemplo principal:

.grandparent {
  .parent {
    &{0}.child {   // inherit NONE of the parents
      background: white;
    }
  }
  background: blue;
}

Ambos emitindo:

.grandparent {
  background: blue;
}
.child {
  background: white;
}

Pensamentos?

Eu gosto disso. Eu prefiro minha sugestão de &1 ou @Soviut &(1) . Acho que provavelmente esse é o meu vencedor atual.

Um pensamento.. A solução de Matthews não permite que você tenha um mixin (com herança desconhecida) e apenas trabalhe dentro de seus seletores atuais (como em #1158). É muito complicado ter &(2..n) .var &(1) ? ou você poderia fazer & .var &(1) e os primeiros & seriam todos os seletores ainda não escolhidos. alternativamente, deve-se colocar as partes do seletor que você não usa no início, a menos que você use \ ?

Uma pergunta: por que &(1) e não &{1} ? O último é semelhante à sintaxe de variável inline, enquanto os parênteses parecem uma operação matemática. Ou um mixin, e não é semelhante a nenhum. É mais como uma referência.

Como isso quebraria mixins? Não entendendo isso.

em um seletor você tem muitas pseudo classes usando colchetes e então você tem substituição de variável que empresta sua sintaxe do mais detalhado ~"@{var}" então para mim os colchetes normais funcionam melhor (especialmente se devemos permitir &(2..n) ).. mas tendo dito que não tenho uma forte preferência entre ( e { .. Estou mais interessado no acima .. como aumentar 1 nível de herança verus sair do seletor atual.

Estou surpreso que ninguém tenha mencionado como atingir pais específicos (imediatos) quando mais de um está presente. Aqui está algum CSS que eu gostaria de chegar:

/* regular css */
.foo, .bar {
    margin: 0 auto;
    line-height: 1.2;
}
.bar {
    line-height: 2;  /* override */
}

Infelizmente, eu realmente tenho que escrevê-lo assim em menos sintaxe também. Seria bom segmentar .bar no primeiro bloco. Talvez algo como:

/* LESS css */
.foo, .bar {
    margin: 0 auto;
    line-height: 1.2;

    &(2) {
        line-height: 2;
    }
}

Em seguida, os ancestrais podem ser acessados ​​com combinadores e adicionais (eu gosto da ideia de "segmentação por nível"):

/* LESS css */
.mommy {
    .foo, .bar {
        margin: 0 auto;
        line-height: 1.2;

        &(2) {
            line-height: 2;
        }

        /* same results for &&(1) */
        &&.mommyClass {
            color: #000;
        }
    }
}

@Smolations que surgiram em uma edição diferente.

Pensamos que isso poderia ser feito usando guardas em rulsets css combinados com a capacidade de testar seletores pai na condição de guarda. mas é bom trazê-lo à tona.

Ah, eu entendo o que você quer dizer. Eu só não vi esse tópico porque o assunto não me chamou a atenção (você não saberia onde eu poderia encontrar essa discussão, não é? =] ).

Eu acho que sempre que você pode casar várias funcionalidades com uma sintaxe unificada, você contribui para a intuitividade do produto final. Mesmo se eu _hackeado_ essa funcionalidade usando guards, e assumindo que a ideia deste thread seja implementada em qualquer uma das formas sugeridas, alcançar o resultado desejado no meu exemplo exigiria o uso de duas sintaxes separadas. Minha sugestão tenta usar a sintaxe já familiar do e comercial.

Se minha solicitação (a capacidade de acessar um seletor pai específico) não for implementada no futuro, ainda gostaria de ver uma solução para o problema deste segmento que usa o e comercial porque já é significativo ao acessar a árvore genealógica do seletor LESS. =]

aqui https://github.com/cloudhead/less.js/issues/1174

para cada recurso, gostamos de ter certeza de que ele tem valor agregado real. se torna menos difícil de entender, isso não é bom e se torna menos difícil de aprender, também não é bom. Então, eu apoio principalmente a funcionalidade simples neste post (mas não o suficiente para torná-la de alta prioridade - infelizmente, há coisas mais importantes), mas estou realmente cauteloso sobre o quão complexo deve se tornar. Se combinarmos 2 recursos existentes que foram solicitados e como um produto secundário permitir que você faça o que quiser, sem tornar os seletores mais complicados, acho que é melhor, a menos que seus casos de uso sejam gerais o suficiente para que uma funcionalidade especial seja adicionada porque eles têm muito valor agregado.

vamos ver se podemos reescrever seu último exemplo...

.mommy {
   .foo, .bar {
       margin: 0 auto;
       line-height: 1.2;
   }
   .bar {
       line-height: 2;
   }
   .mommyClass {
       color: #000;
   }
}

e digamos que queremos não ter que escrever o seletor .bar duas vezes.

.mommy {
   .foo {
       margin: 0 auto;
       line-height: 1.2;
   }
   .bar:extend(.mommy .foo) {
       line-height: 2;
   }
   .mommyClass {
       color: #000;
   }
}

Com esses exemplos, fica bem fácil entender qual será o resultado css.. com o seu, não é, sem aprender um pouco mais..

O que precisamos para nos convencer das partes mais complicadas desta proposta são casos de uso reais que não podem ser feitos de outra forma.

note - para implementar as opções de sintaxe de extensão, precisaremos adicionar uma regra que o básico da solicitação original.. por exemplo, para escapar do aninhamento atual. Não temos que expô-lo, mas podemos também. Nós realmente precisamos de alvos pais específicos?

Para "escapar", eu estava pensando em $ &(0) >| ou algo assim. senso.

Inicialmente, consideramos muitas abordagens sintáticas para esse recurso no Sass, mas no final decidimos fazer algo muito mais simples porque o número de casos de uso era muito grande:

Estamos expondo & ao SassScript como uma lista separada por vírgula de valores separados por espaço. Então toda a manipulação dos seletores pode ser feita no "espaço do usuário" simplesmente manipulando seletores com funções Sass.

Por exemplo:

.foo, .bar > a { first: nth(&, 1); second-combinator: nth(nth(&,2),2) }

geraria:

.foo, .bar > a { first: ".foo"; second-combinator: ">"}

Teremos esse recurso no Sass 3.3. Suspeito que também enviaremos algumas funções de manipulação de seletor padrão e esperaremos para ver o que a comunidade desenvolve antes de padronizar mais.

@chriseppstein , legal, eu realmente gosto da flexibilidade dessa abordagem. obrigada

@jonschlinkert :) & é um recurso que Less adotou do Sass; Eu acho que a comunidade dev é melhor servida se ambos continuarem a trabalhar de forma semelhante.

@chriseppstein Isso é muito legal, gosto de como & age como uma variável, na qual você pode executar funções. Torna este conceito muito mais fácil de entender e ler.

então, presumivelmente, você atribui um seletor a uma variável e, se precisar disso em um seletor, usa a variável .. Eu gosto que não complique ainda mais a lógica do seletor

<strong i="7">@a</strong>:~".c";
@{a}.b {
   & + & {
      .d(nth(&, 1));
   } 
}

tome o exemplo acima .. Fazemos isso

  1. ligue para .d
  2. avaliar @{a}.b
  3. malhar & + &

Isso foi parcialmente justificado porque costumava ser o caso de chamar mixins poderia puxar o escopo atual (algo que não fazemos mais).

As etapas 1 e 2 são feitas em uma etapa e a 3 em outra.

Isso também é feito porque até que todos os mixins tenham sido chamados, você não pode trabalhar em todos os seletores de conjuntos de regras.

Eu acho que para implementar isso você teria que ter um conceito de se um conjunto de regras estava em um estado de mixagem ou não e, no momento em que ele sai desse estado (ou no início da avaliação, se nunca foi misturado), nós elaboramos o seletores. Acho que isso funcionaria. Então poderíamos obter os caminhos no momento da avaliação.

O problema com essa abordagem é a extensão. Isso teria que ser aplicado à medida que você avança - novamente no momento em que processamos o AST para extensões.

Outra solução seria continuar a avançar para o modelo de visitante, mas permitir que os visitantes executem várias vezes ou então sejam dependentes cruzados ou algo assim. hmm.

Vou ter que pensar sobre isso.

Como ele interagiria com o recurso "return mixins" https://github.com/cloudhead/less.js/issues/73 ?

Qual seria o resultado desta operação:

.some-class {
  #unlock-this {
    .mixin() {
      first: nth(&, 1); 
    }
  }

  .foo, .bar > a { 
    #unlock-this();
    .mixin();
  }
}

Pode ser tanto isso:

.some-class .foo,
.some-class .bar > a {
  first: #unlock-this;
}

ou isto:

.some-class .foo,
.some-class .bar > a {
  first: .some-class .foo;
}

Eu esperaria que fosse útil, para & igualar o seletor final, pois
ele faz quando usado como parte de seletores.

Parece que há algumas coisas poderosas aqui para fazer referência ao seletor herdado. Interessante.

Eu ainda gosto da ideia de um caractere de escape simples, para desligar a herança de bloco sem muito alarde. CSS Crush usa um acento circunflexo ^ . Parece simples. Que tal isso?

.this {
  .is {
    .deeply {
      .nested {
        ^.related-but-simpler-output {
          property: awesome;
        }
      }
    }
  }
}

// Outputs

.related-but-simpler-output {
  property: awesome;
}

O material nth() também é legal (para "escolher" o seletor herdado), o que não acho que entraria em conflito com o suporte a isso.

+1 para uma maneira de referenciar/segmentar um seletor pai específico usando algum tipo de sintaxe dict, como &2 ou &{2} ou &^^ ou mesmo &~2 ( essas duas últimas sugestões são inspiradas no git).

+1 para uma maneira de desativar a herança de bloco (como sugerido logo acima por @matthewdl). Essa solicitação é sonhada, pois permite manter a saída mais curta, ao mesmo tempo em que aproveita blocos (e variáveis) com escopo durante o pré-processamento.

Acredito que esses dois recursos (seletor pai de destino e herança de bloco de escape) seriam realmente úteis para quem está tentando escrever CSS seguindo a metodologia BEM .

Estamos expondo & ao SassScript como uma lista separada por vírgulas de valores separados por espaço.

Eu não concordo que isso seja necessário ou mesmo intuitivo, e pegar o combinador de um seletor não faz sentido como tendo qualquer valor no mundo real. Além disso, às vezes os valores não são separados por espaço, então não tenho certeza se resolve esse problema.

Isso é simples, mas não tem separação de espaço.

.one {
  &.two {       & inherited value is == ".one"  
    &.three {   & inherited value is == ".one.two".
       &1:hover { }  // Outputs .one.two.three:hover { } &1 always == & 
       &2:active { }  // Outputs .one.two:active { }
    }
  }
}

A maioria das pessoas aqui falou sobre fazer referência a um nível de bloco específico, que parece mais rápido de decifrar do que a separação por espaço e as listas aninhadas.

.parent1, .parent2 > .immediate-child {
  &.child1, .child2 {
    .box, .getting-complicated {
      // &2 is easy to understand here if it refers to "&.child1, .child2", but...
     nth(nth(nth(&,4),1),2) { } // or whatever it would be to breakdown lists of lists of lists
    }
  }
}

Eu entendo que é poderoso. Mas é realmente mais fácil? Ou necessário?

nth(nth(nth(&,4),1),2) { } // ou o que quer que seja para quebrar listas de listas de listas

Lol Entendo seu ponto, mas não poderíamos mostrar exemplos de código para fazer esse mesmo ponto com praticamente todos os recursos do Less.js? Muita abstração é um obstáculo, independentemente de qual recurso você está se referindo. Mais ao ponto, na realidade, quem realmente faria isso?

Eu entendo que é poderoso. Mas é realmente mais fácil? Ou necessário?

A percepção é a realidade ;-) Ponto válido embora. seria bom ouvir mais desenvolvedores como @maniqui

Por que seriam listas de listas de listas? & representa o contexto atual. Então, no máximo, é uma lista de listas. A primeira lista representa os seletores delimitados por vírgulas, a segunda lista é apenas uma sequência de seletores e combinadores simples. (pelo menos é assim que vai funcionar no Sass).

@chriseppstein É certo que não entendo muito bem como você está usando & com nth().

Como você refatoraria isso:

.one {
  &.two, &.four {      
    &.three {  
       &1:hover { }  
       &2:active { }  // I want to return .one.two:active, .one.four:active { }
    }
  }
}

Meu ponto maior é que, embora nth() possa ser um ótimo recurso e eu entenda por que está no SASS, não tenho certeza se ele aborda diretamente o problema levantado neste thread, que é fazer referência a um nó específico da cadeia de herança. Em vez disso, parece que permite selecionar uma parte do valor herdado. ... O que PODE resolver o problema e talvez eu não entenda o uso simples de nth().

Isso parece um código frágil que você está fazendo lá.

Ok, então estamos entre frágil e complicado, embora eu não tenha certeza de como é frágil. Você está apenas pulando os blocos. Claro, você pode mover as coisas para fora de seus blocos, mas também pode fazê-lo de uma maneira que quebraria a si mesmo.

É possível que a sintaxe necessária em uma solução seja mais complicada do que refatorar para atender às suas necessidades, e é por isso que @lukeapage e @scottrippey fecharam isso em primeiro lugar. O uso mais fácil de entender parece estar escapando da herança, como em :

.one {
  .two, .four {      
    ^.three { }  // just output .three { }
  }
}

&1, &2 ainda parece muito fácil de conceituar.

Ok, aqui está o que eu gostaria de fazer com o & :

  • & se comporta como agora
  • &^1 apenas sai um nível.
  • Se você tiver listas de seletores, talvez faça referência separadamente? Como &^1[2] ou algo assim.

Então, assim

.class {
   .child1, .child2 {
      .grandparent & { }
      .after-parent-insert &^1 { }
      .child-modifier&^1 { }
      .special-child-modifier&^1[2] { }
   }
}

O que produziria isso (se houvesse coisas em cada nível)

.class { }

.class .child1,
.class .child2 { }

.grandparent .class .child1,
.grandparent .class .child2 { }

.class .after-parent-insert .child1,
.class .after-parent-insert .child2 { }

.class .child-modifier.child1,
.class .child-modifier.child2 { }

.class .special-child-modifier.child2 { }

Isso é o que eu queria, pelo menos. Eu não sei se abrange tudo o que foi discutido aqui, e talvez eu esteja totalmente errado, mas pensei em adicionar meus 2 centavos.

Quanto a escapar, eu gosto da simplicidade de ^ , se isso realmente parece importante, embora eu realmente não sinta que seja necessário. Escrevo meu menos para me mostrar relacionamentos. Aninhar e depois escapar de algo parece que quebraria isso para mim. Se eu precisar de uma variável em vários escopos, acho que apenas envolveria tudo em & { } e declararia variáveis ​​lá.

Concordo em alterar o comportamento padrão para que ele suba apenas um nível, mas seria necessário haver uma maneira de chegar à raiz em uma etapa. Talvez os valores negativos possam começar na raiz e descer na hierarquia:

&^-1

Além disso, e o caso extremo em que você deseja usar & como prefixo? A sintaxe deve ser a seguinte?

.grandparent {
    .parent {
        .child {
            & &^1 {        // <-- trying to refer to .parent
               color: blue;
            }
        }
    }
}

Nessa situação, de onde o índice começa? Originalmente, fiquei tentado a escrever &^2 mas tecnicamente o primeiro & indica que já estou lidando com o elemento .child , então só preciso subir 1.

Escrevo meu menos para me mostrar relacionamentos. Aninhar e depois escapar de algo parece que quebraria isso para mim.

Se entendi certo, definitivamente concordo que o aninhamento ajuda a mostrar relacionamentos, na maioria das vezes ajudando a manter o código curto e conciso enquanto, espero, ainda legível [1]. Por outro lado, "plano é melhor que aninhado" [2].

Embora humanos não sejam compiladores, no contexto de compilação CSS, é fácil ver que, ao aninhar muito profundo (mais de 2 níveis), (ab)usando & compila para seletores mais longos, gerando saídas mais longas .
Seletores mais longos significam, geralmente, maior especificidade ( _desnecessária_ mais alta), o que é, na maioria das vezes, indesejável. Uma alta especificidade desnecessária pode facilmente disparar
Uma saída mais longa significa, é claro, arquivos maiores. Novamente, nós humanos não somos compiladores, mas conhecemos nossa habilidade e sabemos os benefícios de ter código que compila em arquivos mais curtos.

Nós escrevemos nosso CSS em LESS para, bem, escrever _less_ e talvez, para compilar para _less_ quantidades de código.
Eu sou culpado de, às vezes, tentar ser esperto demais escrevendo meu código MENOS. Meu futuro eu geralmente me odeia, já que geralmente acabo dando um tiro no pé do meu futuro eu.

Resumindo: eu encontrei situações (particularmente, enquanto escrevia CSS seguindo as metodologias BEM/SUIT) onde o & não ajudava em nada, e ter um "seletor pai imediato" (algo como o ^ proposto

[1] O código deve ser curto/conciso?: http://stackoverflow.com/questions/952194/should-code-be-short-concise
[2] Zen do Python: http://www.python.org/dev/peps/pep-0020/

(Para ser honesto, a coisa toda me parece uma espécie de superengenharia... Ou talvez eu simplesmente não entenda claramente os possíveis casos de uso).
De qualquer forma, a "segmentação numérica dos pais" não é um pouco frágil? Veja, você faz algumas modificações em seletores externos (por exemplo, inserir ou remover um seletor) e... boom! você tem que corrigir (ou pelo menos você tem que verificar se você tem que corrigir) todos esses índices nos blocos aninhados. Apenas um pensamento...

+1 para este problema.

1575 é uma duplicata que eu criei porque o github não permite que você procure por literais & 's, e eu não sabia na época sobre a terminologia "seletor pai" e "anexador". Na verdade, vou colocar o termo 'e comercial' aqui apenas no caso de alguém procurar por ele.

Há um caso de uso / explicação de expectativas bastante destilado lá, se você quiser lê-lo.

Não tenho opiniões fortes sobre a sintaxe desse recurso. Minha expectativa é que o escopo de fechamento atual seja aquele que será mais comumente referenciado, então a sintaxe para isso deve ser concisa. Opções como &^ e &_n_ me parecem ótimas.

Só quero adicionar não queremos alterar o comportamento padrão .. & foi inventado
principalmente para adicionar :hover etc. Sem espaço.

Wrt bem Trabalho em uma aplicação web grande e complexa e temos uma regra
nunca use mais de 2 seletores. Usamos mixins, extensões e variáveis
fortemente. Eu nunca vi a necessidade de um recurso como este .. quando eu tenho
considerei isso, descobri que muitas vezes faz mais sentido refatorar.

Estou interessado em casos de uso que não são apenas ... Arggg, não quero
refatorar este bloco seletor..

Não sou contra esse recurso em princípio, mas corre o risco de adicionar um
recurso que torna as pessoas menos difíceis de seguir e manter.

Como alguém que votou e argumentou a favor de ter um "seletor pai", devo admitir que estou lutando muito para encontrar um caso de uso real e não inventado. Eu posso ter saltado no vagão "seria-bom-de-ter".

Talvez um bom exercício seja começar com alguma saída que eu gostaria de obter e ver quais são as possíveis entradas _existing_ Less que a gerariam. Em seguida, avalie coisas como "legibilidade", "concisão", "curtidão", "plano vs aninhado", etc.

/* a block (.block) */
.myblock {
  prop: value;
}

/* an element (.block__element) */
.myblock__date {
  prop: value;
}

/* an element (.block__elementB) nested inside an element (.block__elementA)
.myblock__date .myblock__year {
  prop: value;
}

/* an element (.block__elementC) nested inside an element (.block__elementB) nested inside an element (.block__elementA) 
.myblock__date .myblock__year .myblock__digit {
  prop: value;
}

/* an element (.block__elementB) present in a particular modified context (.block__elementA--modified) */
.myblock__date--end .myblock__year {
  prop: value;
}

/* idem */
.myblock__date--end .myblock__digit {
  prop: value;
}

/* an element modified (.block__elementA--modifier) present in a particular context (.block__elementD) */
.myblock__header .myblock__date--end {
  prop: value;
}

/* an element (.block__elementC) nested in a particular modified context (.block__elementA--modifier) nested in a particular context (.block__elementD)  */
.myblock__header .myblock__date--end .myblock__year {
  prop: value;
}

vou experimentar. Talvez alguém gostaria de compartilhar como eles resolveriam isso?

@maniqui

Existe algum motivo especial para você querer prefixar cada classe com ".myblock__"? Se esses elementos são descendentes do elemento raiz .myblock, então algo como .myblock .date .year .digit não seria mais consistente? E se eles não são descendentes, então não é muito fácil entender o que eles têm a ver com a classe ".myblock" (e por que eles são nomeados assim) ...
Bem, se você realmente precisa prefixar tudo com o mesmo prefixo, então:

.my-elements(~'.myblock__');

.my-elements(@-) {

    @{-}date {
        prop: value;

        @{-}year {
            prop: value;
            @{-}digit {
                prop: value;
            }
        }

        &--end { 
            @{-}year {
                prop: value;
            }

            @{-}digit {
                prop: value;
            }

            @{-}header & {
                prop: value;

                @{-}year {
                    prop: value;
                }
            }
        }
    }
}

Sim, esse código parece no mínimo estranho, mas isso ocorre apenas porque o CSS desejado é estranho (então eu realmente me pergunto qual seria o HTML correspondente).
Mas o principal problema é que este exemplo é mais sobre "processamento de string" e não muito sobre "segmentação pai"... aninhado dentro do HTML em ordem quase aleatória, então você precisa de alguma mecânica especial (como "segmentação pai") para converter essa estrutura "aleatória" em código MENOS "não tão aleatório" ... mas é para isso que serve o MENOS?


Atualização: fiz algumas pequenas alterações no código (recolhi --end ). agora é ainda mais estranho, doh!

@seven-phases-max

Essa maneira de escrever CSS é baseada nas convenções de nomenclatura de metodologias como BEM e SUIT .

Em relação à maneira como você escreveu, eu uso uma abordagem semelhante.

& { // This creates a scope for variables.
  <strong i="10">@block</strong>: myblock;

  .@{block} {
   prop: value;
  }

  .@{block}__date {
    prop: value;    
  }

  .@{block}__date .@{block}__year  {
    prop: value;
  }

  .@{block}__date .@{block}__year .@{block}__digit  {
    prop: value;
  }

  .@{block}__header .@{block}__date {
    prop: value;
  }

  .@{block}__header .@{block}__date .@{block}__year {
    prop: value;
  }  
}

(a propósito, este código não gera o CSS que perguntei no meu post anterior, este é apenas um exemplo para mostrar outra maneira de fazer escopo de variável em Less).
Concordou sobre isso não ser sobre ter um seletor pai.

Ah, eu vejo agora... Então todas essas coisas BEM não são destinadas a uma geração automática de CSS a partir de alguns modelos (usando suas ferramentas e scripts dedicados)? Bem, não importa, seu exemplo é suficiente para eu nunca considerar escrever CSS (com MENOS ou sem) manualmente usando essas convenções BEM :)

@maniqui Continuando a brincar com o seu exemplo... Acho que ainda é um exercício interessante (com o bloatprefix removido). No contexto de possíveis melhorias de legibilidade, suspeito que a chave será apenas tentar coletar as propriedades de elementos semelhantes. Por exemplo, se os elementos .year, .digit e .date tiverem propriedades semelhantes, eu terminaria com algo assim:

.date {
            &             {prop: value}
    .header &--end        {prop: value}

                   .year  {prop: value}
            &--end .year  {prop: value}
    .header &--end .year  {prop: value}

             .year .digit {prop: value}
            &--end .digit {prop: value}
}

(Usando o formulário "compacto" apenas para economizar tempo na formatação, é claro que não será tão "limpo" com várias propriedades por elemento). E este código parece ser muito semelhante ao seu último trecho. Ou seja, parece que o aninhamento é definitivamente um inimigo em situações como essa - pode tornar o código mais compacto e ajudar a remover duplicatas, mas ao mesmo tempo é provável que mate a legibilidade, a menos que o aninhamento HTML correspondente seja muito rigoroso e estruturado.

Só vou lançar um caso de uso aqui.

Eu tenho uma lista de itens que podem ser expandidos. Certos seletores filhos (aninhados) precisam de um estilo diferente quando o item é expandido.

Por exemplo, quando expandido, um seletor filho precisa ser exibido com conteúdo adicional, etc.

Eu gosto de manter as propriedades juntas onde elas diferem entre seus estados expandido e padrão para manutenção.

O problema que tenho é que preciso definir o escopo de tudo em .items para evitar que vaze para outras partes e também se eu quiser fazer uma estrutura em árvore.

A linha .is-expanded& causa o seletor items.is-expanded > .item > .item-secondary , quando o que eu realmente quero é .items > .item.is-expanded > .item-secondary .

.items {

  .item {

    // Margin/transition.
    & {
      transition: 100ms margin;
      .is-expanded& { .mvs; }
    }

    // Border radius.
    &:last-child { border-radius: 0 0 2px 2px; }
    &.is-expanded & { border-radius: 2px !important; }

    // Display.
    & > .item-secondary {
      display: none;
      .is-expanded& { display: block !important; }
    }

  }

}

Para mim, a proposta de sintaxe Less mais simples foi &1 , &2 , etc. com 1 sendo o primeiro seletor pai. Muito natural, fácil de grocar.

Então, para este caso, eu simplesmente usaria .is-expanded&2 .

Quando você quer algo como .grandparent.black .parent .child
Eu estava pensando em algo assim, mas eu gosto de ter um número como &(3)
mas então fica confuso porque ele anexa o resto do seletor atual a esse seletor? ou teria que ser como &(3).black & que aplicaria o seletor atual em que estamos? ou herdaria automaticamente? Haveria um caso em que você não gostaria que ele herdasse automaticamente? Se não quiséssemos herdar então não seria escrito no seletor .parent .child, então deveria herdar.

.grandparent {
  .parent {
    .child {
      background: white;

      &&&.black {
        background: black;
      }
    }
  }
}

&:1 é o meu favorito ( :1 aqui se comportando como um pseudo seletor). A sintaxe :extend() já segue a sintaxe padrão do pseudo-seletor definido pelo CSS, então eu sinto que uma pseudo-sintaxe se encaixaria muito bem. & é uma coisa, &:1 é um subconjunto dessa coisa, assim como a e a:hover . Por que reinventar a roda, sabe?

&(1) faz & parecer uma função ao invés de uma string seletora, e eu não gostaria apenas &1 porque se eu tiver, por exemplo, estilos de coluna que eu escolho definir como abaixo, eles teriam que ser amplamente reescritos (provavelmente exigindo alterações na minha marcação também).

.col {
  &1 { /* stuff */ } // .col1
  &2 { /* stuff */ } // .col2
  &3 { /* stuff */ } // .col3
  ...
}

&:1 representa uma ameaça muito menos significativa para as folhas de estilo atuais (não consigo pensar em nenhuma razão para que :1 esteja em uma folha de estilo, pois não é CSS válido e não pode ser usado como um gancho JS ou qualquer outra coisa) e provavelmente nunca interferirá em nenhum pseudo seletor ou elemento CSS, atual ou futuro. E, como mencionei antes, é conceitualmente consistente com outros recursos do Less.


A propósito, &[1] (sintaxe do seletor de atributos) também faria sentido. E parece uma sintaxe de array JS, o que é legal e se encaixa muito bem na ideia, eu acho. Atributos numéricos realmente não funcionam em HTML , então todos os benefícios de &:1 se aplicam a &[1] também.

ATUALIZAÇÃO: como @SomMeri mencionou, os ^ e ^^ entram em conflito com os seletores shadow DOM.

Continuei explorando isso mais depois desse comentário, e acabei com algo mais próximo do que o @scottrippey propôs, mas deixo este pedaço aqui como parte da conversa.


Acho que muito do feedback sobre fragilidade e supercomplicação com a segmentação numérica tem muita validade. Podemos, no máximo, precisar de apenas dois "modificadores" para seletores herdados, sem precisar numerar etapas na árvore. Talvez o seguinte seja mais intuitivo?

  • < - estendendo o conceito da seleção de filho CSS, um modificador pai. Quando usado com & , omite o pai imediato
  • ^ - "escapa" do contexto atual. Quando usado com & , herda apenas o pai imediato

Cada modificador altera o próximo & e apenas o próximo. Melhor demonstrado pelo exemplo.

Exemplo 1 - exemplo de @vjpr

.items {

  .item {

    & > .item-secondary {
      display: none;
      < &.is-expanded ^ & { display: block !important; } 
    }

  }

}

// results in

.items .item > .item-secondary {
  display: none;
}
.items .item.is-expanded > .item-secondary {
  display: block !important;
}

_Observação: no exemplo acima, < &.is-expanded poderia ser escrito <.is-expanded ._

Exemplo 2 - escapando da árvore

Muitas vezes as pessoas querem "estruturar" menos classes para combinar com a marcação (para tornar seus estilos autodocumentados), mas não querem produzir mais CSS aninhado.

.books {
  float: left;
  ^ .book {
    display: inline-block;
  }
}
// results in
.books {
  float: left;
}
.book {
  display: inline-block;
}

Exemplo 3 - Uso Avançado

.grandparent {
  .parent {
    .child {
      background: blue;
      < < &:hover < ^ & {  
        background: red;
      }
    }
  }
}

// results in
.grandparent .parent .child {
  background: blue;
}
.grandparent:hover .parent .child {

}

No exemplo anterior, < < seleciona .grandparent { } e < seleciona .parent { } enquanto ^ escapa de .grandparent { }. Embora este seja um exemplo mais avançado e talvez seja uma sintaxe estranha no início, sinto que o caso de uso em si é muito "mundo real". Como estou escrevendo estilos, estou descrevendo a apresentação de .child . Com base no estado de foco do contêiner avô, quero alterar essa classe .child atual. Ele pode ser refatorado na seguinte alternativa, mas na verdade pode ser mais difícil de manter porque agora estamos descrevendo .child em dois lugares diferentes e duplicando classes:

.grandparent {
  .parent {
    .child {
      background: blue;
    }
  }
  &:hover {
    .parent {
      .child {
        background: red;
      }
    }
  }
}

Portanto, embora a refatoração seja _possível_, ter direcionamento na verdade é uma abordagem DRY melhor. ( @lukeapage - esse pode ser o tipo de exemplo que você está procurando, onde a segmentação minimiza o código mais do que a refatoração pode fazer.)

Obviamente, se um usuário deseja especificar exatamente para qual elemento estamos monitorando o estado de foco, ele pode minimizar a fragilidade com um escape e descrevê-lo exatamente, para a mesma saída:

.grandparent {
  .parent {
    .child {
      background: blue;
      ^ .grandparent:hover .parent .child {  // or you could write it ^ .grandparent:hover .parent ^ & if you wanted
        background: red;
      }
    }
  }
}

Portanto, com 2 modificadores, poderíamos cobrir a maioria, se não todas as permutações de casos de uso, sem precisar de segmentação numérica precisa. Pensamentos?


_EDIT: Encontrei o que acredito ser uma solução melhor.

Percebi que uma maneira mais simples de escrever o acima poderia ser esta:

.grandparent {
  .parent {
    .child {
      background: blue;
      << &:hover ^^ & {  
        background: red;
      }
    }
  }
}

Basicamente, dada a cadeia de concatenação (&) [.grandfather][.parent][.child] , e usada com & , < remove o último da cadeia e ^ "inclui" elementos da cadeia a partir do final.

Assim:
<< & = [.grandfather] [.parent][.child]
^^ & = [.grandfather] [.parent][.child]

^ por si só removeria tudo: [.grandfather][.parent][.child]

Claro, ocorreu-me que ^ é usado como "começa com" como um seletor de atributo. Portanto, pode fazer sentido reservar isso para consumir a cadeia pela frente. Como em ^ é a raiz da árvore atual e ^^ pode ser o primeiro elemento da árvore.

O que é intuitivo para outras pessoas?


_EDIT: Encontrei o que acredito ser uma solução melhor.

@matthew-dean Os ^ e ^^ entrariam em conflito com os seletores cat ( ^^ ) e hat ( ^ ) ShadowDOM que já são suportados por less. js #1801.

@SomMeri Certo, droga, esqueci disso. O que você acha de < & para se referir ao "contexto pai para &"?


_EDIT: Você não precisa responder isso.

Eu tenho brincado mais com sintaxe, seletores e vários exemplos, e me encontrei de volta a uma sintaxe que era próxima do que @scottrippey tinha para começar. Eu comecei a escrever exemplos diferentes com $ (seletor de atributo CSS "termina com") em vez de ^ , mas começou a parecer um regex feio.

Eventualmente, com todos os diferentes seletores, descobri que provavelmente o mais fácil seria não tentar "navegar" na árvore e selecioná-la por número (o que não está claro) ou por símbolo (o que ainda pode ser difícil identificar qual pai que você está falando), mas para realmente especificar qual seletor na cadeia de seletores de & você realmente quer dizer.

.grandparent {
  .parent {
    .child {
      background: blue;
      &(.grandparent):hover {  
        background: red;
      }
    }
  }
}

Assim, como foi sugerido, & se torna como uma função que pode conter zero argumentos para concatenar a lista inteira, ou pode receber argumentos para modificar a saída da lista.

Então, de volta ao exemplo do @vjpr :

.items {
  .item {
    & > .item-secondary {
      display: none;
      &(.item).is-expanded { display: block !important; } 
    }
  }
}

Essa abordagem tem o benefício de ler de forma muito limpa, certamente lê de forma mais limpa do que meus exemplos anteriores com << e ^^ . Estou incluindo todo o contexto & , mas modificando um dos seletores na minha cadeia de seletores. Não é nada ambíguo a qual elemento pai estou me referindo ou a qual classe quero anexar a ele. Está bem ali, escrito claramente.

Quanto mais eu olho para isso, esta é a solução mais legível e menos ambígua e menos frágil para vários tokens e referências numéricas. Lê-se mais como um :extend mas para &.

Acho que @scottrippey estava certo para começar, embora eu prefira &(.selector) a apenas (.selector) para indicar um caso especial de & em vez de algo que se pareça com uma função anônima.

Eu gosto disso. Tem um sentimento intuitivo sobre isso.

Enviado do meu iPhone

Em 15 de julho de 2014, às 17h14, Matthew Dean [email protected] escreveu:

Eu tenho brincado mais com sintaxe, seletores e vários exemplos, e me encontrei de volta a uma sintaxe que era próxima do que @scottrippey tinha para começar. Eu comecei a escrever exemplos diferentes com $ (atributo CSS "termina com" seletor) em vez de ^, mas ele começou a ser lido como um regex feio.

Eventualmente, com todos os diferentes seletores, descobri que provavelmente o mais fácil seria não tentar "navegar" na árvore e selecioná-la por número (o que não está claro) ou por símbolo (o que ainda pode ser difícil identificar qual pai que você está falando), mas para realmente especificar qual seletor na cadeia de seletores de & você realmente quer dizer.

.avô {
.parent {
.filho {
fundo: azul;
&(.avós):passe o mouse {
fundo: vermelho;
}
}
}
}
Assim, como foi sugerido, & torna-se como uma função que pode conter zero argumentos para concatenar a lista inteira, ou pode receber argumentos para modificar a saída da lista.

Então, de volta ao exemplo do @vjpr :

.Itens {
.item {
& > .item-secundário {
Mostrar nenhum;
&(.item).is-expandido { display: block !important; }
}
}
}
Essa abordagem tem o benefício de ler de forma muito limpa, certamente lê de forma mais limpa do que meus exemplos anteriores com << e ^^. Estou incluindo todo o contexto&` mas modificando um dos seletores na minha cadeia de seletores. Não é nada ambíguo a qual elemento pai estou me referindo ou a qual classe quero anexar a ele. Está bem ali, escrito claramente.

Quanto mais eu olho para isso, esta é a solução mais legível e menos ambígua e menos frágil para vários tokens e referências numéricas. Lê-se mais como um :extend mas para &.

Eu acho que @scottrippey estava certo para começar, embora eu prefira &(.selector) sobre apenas (.selector) para indicar um caso especial de & em vez de algo que se parece com uma função anônima.


Responda a este e-mail diretamente ou visualize-o no GitHub.

Sim, e desculpas a @scottrippey por se afastar de sua sintaxe. Eu nem entendi o que ele quis dizer sobre a quantidade desnecessária de duplicação até que eu passei por alguns outros exemplos e depois tive minhas próprias experiências tentando resolver a mesma coisa. Realmente parece a maneira menos problemática de direcionar um pai para o estilo de filho de maneira DRY.

Na verdade, não há nada de errado em usar ^ e ^^ já que eles não são mais usados ​​para seletores ShadowDOM (substituídos por /deep/ e outros, veja #2023 - então teremos que remover coisas #1801). Há sempre uma preocupação em usar qualquer símbolo genérico dentro da definição do seletor (e mesmo & não é uma exceção :) uma vez que eles _podem_ escolher quaisquer símbolos que quiserem para CSS eventualmente (embora em algum lugar nas listas de discussão houvesse rumores de prometo nunca mais fazer isso).

Quero dizer, ainda podemos manter a sintaxe ^ e ^^ em mente (a menos que alguém realmente esteja prestes a implementar o recurso amanhã).


Eu gosto da idéia &(selector) também. O único problema que posso ver é (bem, um exemplo bastante artificial):

ul {
    li {
        ul {
            li {
                &(ul):hover a {color: red} // which one?
            }
        }
    }
}

Ah, e já tivemos essa pergunta em https://github.com/less/less.js/issues/1075#issuecomment -11350357.

Pensando no exemplo double ul mais eu acho que é realmente bom não se importar muito com isso. Como esse é um recurso sintático de açúcar em geral, não há problema em não cobrir todos os casos possíveis.
Assim:

  • &(ul) acima deve apontar para o nível superior ul
  • e &(ul li ul) para apontar para o ul aninhado (ou use a sintaxe CSS ordinal, ou seja, adora escrever cadeias CSS confusas? - obtenha seu Less bagunçado também :)).

E outro problema, atualmente o código a seguir é válido e compila conforme o esperado:

p:nth-child {
    &(2) {
        color: potato;
    }
}

Isso não vai ser quebrado? (Observe que o valor entre parênteses também pode ser @{var} então não podemos distinguir entre dois recursos por simples condição de número/não número).

Na verdade, não há nada de errado em usar ^ e ^^, já que eles não são mais usados ​​para seletores ShadowDOM

Isso é bom porque ainda é um caso de uso que eu ainda gostaria de ver suportado: "escapando" o contexto atual, que é diferente da segmentação pai.

Para o exemplo &(ul) , acho que não há problema em se referir a ambos. Nesse ponto, não precisamos salvar o desenvolvedor de si mesmo e isso é simples. ou seja, em algum momento, sugerir um refatoramento está ok. É basicamente encontrar correspondências na lista de herança. OU tratamos como extend, semelhante ao seu segundo exemplo &(ul li ul) , e você é forçado a escrever todos os seletores anteriores que correspondem a esse seletor interno: por exemplo, &(.grandparent .parent) para se referir a .parent { } em .grandparent { .parent { } } vez de apenas &(.parent) . É mais detalhado, então não tenho certeza se gosto tanto, mas... é tecnicamente menos ambíguo.

No exemplo do enésimo filho... parece bastante inventado? Tipo, eu entendo que é tecnicamente possível hoje, mas por que alguém não especificaria qual enésimo filho no próprio seletor? Existem outros exemplos com parênteses que podem realmente ser usados?

Se houver alguma ambiguidade e preocupação em quebrar alterações, uma não correspondência de um seletor na cadeia de herança pode resultar na saída de texto conforme escrito. Eu sinto que já existe algum tipo de comportamento assim em Less, mas não consigo pensar em quê.

Obrigado pelo feedback.

No exemplo do enésimo filho... parece bastante inventado?

Não é bem assim, veja este codepen (e na verdade é um extrato simplificado de um projeto real que tenho em desenvolvimento agora). Portanto, podemos considerar este exemplo como baseado em algo "não documentado", é claro, mas não podemos negar que é um código compilável por um tempo agora e é melhor não quebrá-lo.
(O código no codepen é um pouco mais complicado do que poderia ser e usa hacks sujos adicionais apenas para trabalhar o #1973).

uma não correspondência de um seletor na cadeia de herança pode resultar na saída de texto conforme escrito.

Bom lugar.

Hmm... Esta manhã também pensei em:

.book:not {
  &(.harry-potter) { }
}

No entanto, com um fallback de saída, isso funcionaria. MAS a ambiguidade _poderia_ tornar o código mais difícil de entender imediatamente por um co-mantenedor.

Em vez disso, podemos querer algo como [] , como em:

.book {
  &.harry-potter {
    .title {
      result: awesome;
      &[.harry-potter]:hover { result: not-awesome; }
    }
  }
  &:not {
    &(.harry-potter) { foo: bar; }
  }
}

// results in

.book.harry-potter .title {
  result: awesome;
}
.book.harry-potter:hover .title {
  result: not-awesome;
}
book:not(.harry-potter) {
  foo: bar;
}

Se () for potencialmente conflitante e {} for provavelmente confuso, esse é o próximo melhor suporte. Claro, seu seletor pode ter colchetes, mas neste caso, não consigo pensar em um seletor que seria passado para [] em CSS. Seletores de atributo podem se referir a classes, mas eles descartam o ponto.

Ou provavelmente há outras maneiras de segmentar que alguém pode achar mais legível, como:

.title {
    result: awesome;
    &&(.harry-potter):hover { 
      result: not-awesome; 
    }
}

Embora && exista no código, a probabilidade de &&(.selector) entrar em conflito com o código começa a diminuir drasticamente. Apenas mais uma opção.

_Como uma observação lateral, também noto neste exemplo que a segmentação pai oferece um benefício de ordenação de saída. A "substituição" pode seguir imediatamente a declaração do filho, que a refatoração não forneceria necessariamente. Outro +1 para este recurso._

[...] seria confundido com atributos seletores da mesma forma, código atualmente válido (provavelmente ainda mais amplamente usado que n-th ou not ):

a {
    &[title] { // is it selector attr or just custom parent tag?
        color: banana;
    }
}

@seven-phases-max Sugestões, então? () parece a sintaxe certa para CSS e Less para enviar um seletor para uma função, então talvez &&() seja melhor? Ou & + outro símbolo / wrapper?

Por que não apenas tratar & como um array e acessá-lo no estilo PHP array_slice()?

&[_Deslocamento_]:

  • Obtém o item em _offset_.
  • O mesmo que &[_offset_, 1].

&[_offset_, _length_]:

  • Obtém _length_ número de itens a partir de _offset_.
  • _offset_ negativo se traduz em "Comprimento inteiro - |_offset_|"
  • _length_ negativo se traduz em "Comprimento inteiro - |_length_| - |_offset_|" (Eu posso estar confundindo isso, mas você me pegou.)
  • O valor zero _offset_ significa o início da matriz.
  • O valor zero _length_ significa o resto da matriz.
  • Observe que "&[_offset_]" não é o mesmo que "&[_offset_,]".

Ou se você quiser usar funções, pode se tornar slice(&, offset[, length]) , mas adiciona muita complexidade IMO.

--- o ---

Tome isso como exemplo e marque a posição:

#Frame {
    & .boxHolder1,
    & .boxHolder2 {
        & > div {
            & > .title > span {
                // Stuff
            }

            html.no-js & > .title > span {
                // [Position 1]
            }
        }
    }
}

Agora para a posição 1, estamos em:

html.no-js #Frame .boxHolder1 > div, html.no-js #Frame .boxHolder2 > div

O que torna "&" uma matriz como esta:

    0               1           2                               3           4               5
[   "html.no-js",   "#Frame",   [".boxHolder1", ".boxHolder2"], "> div",    "> .title",     "> span"];

O que podemos fazer são estes (Por que estou dando exemplos? É apenas fatiamento de matriz!):

&[1]        =>  #Frame
&[1, 1]     =>  #Frame
&[1, 2]     =>  #Frame .boxHolder1, #Frame .boxHolder2
&[1, 3]     =>  #Frame .boxHolder1 > div, #Frame .boxHolder2 > div
&[1,]       =>  #Frame .boxHolder1 > div > .title > span, #Frame .boxHolder2 > div > .title > span
&[, 1]      =>  .html.no-js #Frame
&[-2]       =>  > .title
&[-2,]      =>  > .title > span
&[-2, 1]    =>  > .title
&[, -3]     =>  html.no-js #Frame .boxHolder1, html.no-js #Frame .boxHolder2

Além disso, com a adição de um valor especial "&", podemos obter o deslocamento e o comprimento do valor anterior de "&" no caminho atual:

Observe que chegamos à Posição 1 fazendo esta seleção:

html.no-js & > .title > span

então, quando estávamos fazendo essa seleção, "&" estava se referindo a:

#Frame .boxHolder1 > div, #Frame .boxHolder2 > div

portanto, quando "&" é usado como _offset_ ou _length_, ele se traduz na posição desse "&" na matriz do caminho atual.

// Find the value of "&" when we were selecting into Position 1
&[&, &] =>  &[1, 3] =>  #Frame .boxHolder1 > div, #Frame .boxHolder2 > div

// Find the value of "&" and what we prepended to it when we were selecting into Position 1 (This can be empty)
&[, &]  =>  &[, 4]  =>  html.no-js #Frame .boxHolder1 > div, html.no-js #Frame .boxHolder2 > div

// Find the value of "&" and what we appended to it when we were selecting into Position 1 (This can also be empty)
&[&,]   =>  &[1]    =>  #Frame .boxHolder1 > div > .title > span, #Frame .boxHolder2 > div > .title > span

Observe como o deslocamento e o comprimento podem ser trocados e modificados para "&" quando se torna negativo para mais casos de uso:

// Find what we have prepended to "&" when we were selecting into Position 1
&[, -&] =>  &[, 1]  =>  html.no-js

// Find what we have appended to "&" when we were selecting into Position 1
&[-&,]  =>  &[-2,]  =>  > .title > span // I am dying to be able to select this!

Por que eu estava morrendo de vontade de selecionar isso:

#Frame {
    & .boxHolder {
        & > div {
            & + & {
                //This selects "#Frame .boxHolder > div + #Frame .boxHolder > div" which is useless.

                margin-top: 10px;
            }

            & + &[-&,] {
                //This selects "#Frame .boxHolder > div + div" which is what we want.

                margin-top: 10px;
            }
        }
    }
}

--- o ---

Notas:

  • O uso de [] pode confundir isso com o seletor de atributo. Os atributos podem começar com "&", "-" ou um número? AFAIK, eles não podem, então o analisador não terá problemas com isso, mas os desenvolvedores podem. O uso de () pode ser mais apropriado.
  • Algumas pessoas queriam ter uma maneira de selecionar um único membro de um sindicato. Por exemplo, selecionando "h1" neste exemplo:
.myBox {
    & h1,
    & h2 {
        & > span {
            /*
                To only select ".myBox h1 > span" here, you have these "tools":

                &[, &-1]    =>  .myBox
                &[-&,]      =>  > span

                So you can:
                &[, &-1] h1 &[-&,] {
                    //Selected ".myBox h1 > span"
                }

                Or just this for the sake of simplicity by sacrificing flexibility:
                &[, &-1] h1 > span {
                    //Selected ".myBox h1 > span"
                }
            */
        }
    }
}

Não vejo razão para quebrar um sindicato. Os seletores não devem ser unidos, a menos que compartilhem todas as propriedades. Se eles compartilharem algumas propriedades e ainda tiverem diferenças, eles devem ser definidos assim:

.myBox {
    & h1,
    & h2 {
        //Shared properties
    }

    & h1 {
        //Properties unique to "& h1"
    }

    & h2 {
        //Properties unique to "& h2"
    }
}

--- o ---

Essa proposta mantém a posição variável de "&" e a estende de uma maneira que todo desenvolvedor web deve esperar que ela se comporte. Poucas linguagens suportam fatiar/substringir assim (acho que Python suporta e Ruby tem algo assim), mas toda essa sintaxe array[offset, length] será implementada tanto para PHP quanto para JavaScript em versões posteriores.

A introdução desse tipo de acesso/fatia de array também pode ser útil em outros casos:

<strong i="5">@color</strong>: rgba(12, 12, 12, 0.5);

<strong i="6">@red</strong>: red(@color);
<strong i="7">@red</strong>: @color["red"];

<strong i="8">@hue</strong>: hue(@color);
<strong i="9">@hue</strong>: @color["hue"];

<strong i="10">@color</strong>: rgba(red(@color), green(@color)*0.5, blue(@color)*0.2, alpha(@color));
@color["green"] *: 0.5;
@color["blue"] *: 0.2;

Mas é claro que essa é uma discussão para outra questão.

@matthew-dean

() parece a sintaxe certa para CSS e Less para enviar um seletor para uma função

Sim, de fato, os parênteses parecem mais naturais para CSS neste contexto. Meu +1 para isso.

@AlicanC

Os problemas da indexação numérica de seletores pai foram discutidos acima. É mais poderoso na teoria, mas é realmente útil na prática? (Ler e manter estruturas aninhadas profundas onde você precisa (literalmente!) contar níveis de aninhamento não parece ser algo fácil).

De qualquer forma, isso não significa que (eventualmente) não possamos implementar os dois modelos (por exemplo, "numérico" e "por identificador"). Nesse caso, acho legal a ideia de &(offset, length) .


<strong i="12">@red</strong>: @color["red"];

Bem, Less tenta manter a sintaxe e os operadores CSS, então [] é definitivamente um operador alienígena para operações de lista/array em Less. Para este recurso em particular (ou seja, "uma maneira genérica de obter o valor do canal de cores") uma função como color-channel(<strong i="16">@var</strong>, channel-id) seria mais respeitosa com as tradições do Less (mesmo que mais detalhada, afinal eu duvido que alguém use tais manipulações de cores _que_ muitas vezes ).

@color["green"] *: 0.5;

Less não é uma linguagem imperativa, então esse recurso é simplesmente impossível nessa forma de "redefinição de variável" (para mais informações, veja por exemplo os links que coletei ).

A indexação de arrays com () é um pouco estranha, mas as pessoas com algum background em Visual Basic vão concordar que não é um grande aborrecimento. Como as variáveis ​​começam com @ e as funções com . , haverá menos confusão do que haveria em JavaScript se ele usasse () para indexação.

Implementar arrays e fatiar arrays apenas para isso pode ser um exagero, mas eles podem realmente ajudar a melhorar a linguagem de outras maneiras. Ser capaz de contar, indexar e fatiar corretamente os argumentos da função eliminaria a necessidade de ter milhões de sobrecargas ou cores, sombras, etc. ser capaz de ser indexado poderia eliminar a necessidade de funções como color-channel() , red() , green() , etc.

Portanto, em vez de implementar uma sintaxe estranha e sobrecarregar a linguagem para resolver esse problema, essas funcionalidades de matriz podem ser implementadas e estendidas para esse problema.

Acho que estamos saindo rapidamente do tópico aqui, então apenas algumas breves observações (e se você quiser continuar a discussão, crie um novo problema/solicitação de recurso e/ou veja os links abaixo):

Indexação de array com () é um pouco estranho

A sintaxe e a semântica CSS como um todo _são_ estranhas para quem está familiarizado apenas com coisas do tipo C (JavaScript, PHP etc.).

funções com .

Não há funções em Less (exceto aquelas embutidas e elas não começam com . ).

Ser capaz de contar, indexar e fatiar corretamente os argumentos da função

Você pode contar e indexar argumentos mixin com funções de lista (e para outros recursos relacionados a arrays, veja os threads correspondentes, por exemplo, #1857, #2078, #1694, #1421 etc. etc.)

poder ser indexado poderia eliminar a necessidade de funções como color-channel() , red() , green() , etc.

Mais uma vez, é apenas uma questão de "precisamos disso com tanta frequência?" questão - a argumentação oposta também funciona: "uma função como color-channel poderia eliminar a necessidade de sintaxe especializada dedicada". ;)
O truque aqui é que as funções internas são super fáceis de adicionar ao compilador Less, enquanto alguns operadores especiais são bastante dolorosos e inchados na implementação, portanto, uma abordagem de desenvolvimento Less razoável é:
"se algum recurso é incerto para ser realmente algo obrigatório no núcleo da linguagem, é melhor ir como uma função integrada ou até mesmo um plug -in".

E para discussão de outras funções de cores, veja também #1853.

@AlicanC Eu sempre digo às pessoas quando falo sobre Less (ou diferenciando de SASS) é que CSS não presume que o autor seja um programador e familiarizado com estruturas de programação, e nem Less. O fatiamento e a referência de matrizes por indexação (ou numeração) talvez sejam mais poderosos, mas também são mais complexos do que a referência por seletor. E, enquanto eu estava originalmente defendendo isso, acho que, como @seven-phases-max disse, a referência indexada provavelmente é um exagero e não é necessária na maioria dos casos de uso.

Dito isso, também concordo que provavelmente poderíamos suportar o envio do & para as funções de lista que já suportamos (ou algo parecido), como extract(&, 3) para uma ferramenta mais precisa para quem sabe como usá-la.

Na maioria das vezes, tentamos encontrar o método mais simples para aplicar à maioria dos casos de uso, não o método mais poderoso para aplicar a todos os casos de uso, incluindo casos extremos ou teóricos. IMHO, se você deseja uma abordagem semelhante à programação para estilizar com uma sintaxe semelhante ao CSS, está disponível no SASS. Se você quer uma abordagem simples do tipo CSS que "estende" o CSS (uma espécie de CSS+), isso é menos, mas isso é um outro tópico.

@seven-phases-max
Vou parar de responder aos seus comentários sobre arrayly-stuff para não sair mais do assunto. Vou criar um problema separado (ou comentar sobre problemas relacionados) sobre eles mais tarde.

A parte não-fora do tópico é que, se realmente concordarmos em implementar a indexação de seletor, acho que isso deve ser feito de uma maneira que estejamos familiarizados e de uma maneira que todas as partes da linguagem possam se beneficiar dela.

Se decidirmos algo como &(1) para obter o último filho de um seletor, não podemos:

  1. Não faça isso de uma maneira que nos faça dizer " &(n) em Less funciona como &[&.length-n] em JavaScript." mas faça com que funcione como a indexação funciona em JavaScript,
  2. Apenas considere & como uma variável especial como @currentSelector e forneça toda essa indexação incrível para todas as variáveis,
  3. Se achar necessário, adicione:

    • Python/Ruby/PHP 6/ES 6 estilo @var(offset[, length]) fatiando,

    • o caso especial &(&, &) ,

    • indexação de chave nomeada como @myBackground("image")

(Por favor, comente o número 3 quando eu postar onde eles são relevantes.)

Considero o número 2 relevante para esta questão, uma vez que se for decidida a sua implementação, torna-se um pré-requisito para esta questão.

@matthew-dean
Compreendo. Se os líderes de projeto pensam assim, os números 2 e 3 acima nunca devem ser implementados. Mesmo o número 1 é complicado se você pensa assim. Não é como se eu tentasse desafiar toda a filosofia de uma linguagem. O que está decidido está decidido.

Como uma pessoa que fica mais entusiasmada com anúncios de operadores de fatiamento do que se formar na universidade, procurarei outros idiomas.

Obrigado por prestar atenção aos meus grandes pedaços de texto :)

Então, eu não entendi depois dessa longa conversa se podemos esperar uma extensão do comportamento de '&' ou não.......

Caso isso seja útil, aqui está um exemplo do mundo real:

.presentation > div {
  s {
    color: black;
    .dialogue & {
      color: white;
    }
  }
}

Minha expectativa era que a coisa mais interna se expandisse para .presentation > div .dialogue s ; no entanto, expandiu para .dialogue .presentation > div s . Eu tenho mais alguns exemplos como este, e acho que minha única opção é retirá-los da boa hierarquia de aninhamento que estabeleci (que é, como você pode imaginar, muito maior do que o trecho acima), e acho que isso fará o arquivo LESS é mais difícil de manter.

Não tendo lido metade dessa página, o que me ajudaria seria apenas uma forma de “subir” na hierarquia. Não tenho certeza se existe uma maneira alternativa de fazer isso em LESS.

@mwichary

Bem, existem muitos exemplos como este acima (em um caso geral, ao pedir coisas do "mundo real", está sendo mais sobre "alguns casos de uso do mundo real" que não podem ser alcançados _sem_ o recurso, não apenas alguns snippet onde se esperaria/preferia usar o recurso proposto apenas para fins de DRY e/ou açúcar sintático (não negando a importância do material DRY/synsugar - portanto, o recurso é considerado útil e marcado com "prioridade média").

Para o seu exemplo específico, há muitos métodos para obter o mesmo sem # 1075, portanto, mal adiciona algo novo ao tópico (para também responder a @ldetomi : Em resumo, já que parece que agora há algum acordo sobre a sintaxe, o recurso está apenas esperando que seu voluntário o implemente - sem voluntário -> sem recurso).

---

Quanto ao seu snippet específico, o mesmo é muito fácil de alcançar com mixins (e esse é apenas um dos vários métodos possíveis):

.presentation > div {
    .s(black);
    .dialogue  {.s(gray)}
    .monologue {.s(white)}

    .s(@color) {
        s {color: @color}
    }
}

Ou ainda assim (para diminuir a quantidade de colchetes):

.presentation > div {
    .-(           black);
    .-(dialogue,  white);
    .-(monologue, gray);
    .-(prologue,  red);
    .-(catalogue, blue);
    .-(ideologue, green);

    .-(@color) {s {color: @color}}
    .-(<strong i="15">@prefix</strong>, @color) {
        .@{prefix} {.-(@color)}
    }
}

.Como você pode ver, a única diferença é usar .s ou .- em vez de & (e o nome do mixin é independente do nome real do elemento s ) .

@seven-phases-max, obrigado. Esses exemplos parecem bastante angustiantes, no entanto - dolorosos de entender e manter, especialmente considerando que mantive a cor e uma classe apenas para simplificar (há muitas outras propriedades e classes lá, e elas não mapeiam 1:1).

Esses exemplos parecem muito angustiantes

Eles? Ou é só porque não se usa mixins ;) ? (Temo que o mesmo argumento se aplique a .dialogue &(1) quando alguém o vê pela primeira vez...).

há muito mais propriedades e classes lá, e elas não mapeiam 1:1

Nesse caso, _nesting_ é ruim e algumas pessoas (eu, por exemplo) consideram seletores "planos" mais legíveis (afinal, toda a ideia de colocar o seletor de elemento pai em seu filho é geralmente falha, não temos tais elementos de teletransporte em o HTML, não é?), por exemplo:

.presentation > div {

    s {
        color:       black;
        font-weight: bold;
    }

    .dialogue s {
        color:      white;
        font-style: italic;
    }

    .monologue s {
        color:      gray;
        background: yellow;
    }
}

Sim, s é repetido lá, mas a legibilidade vale a pena ( aqui uma vez escrevi um resumo sobre isso para um trecho muito semelhante).

+1 para este recurso. Eu quase comecei a implementá-lo até encontrar esse problema. Sortudo..
Há dois pontos para a sintaxe:

  1. Encontre o seletor pai de destino.
  2. Como inserir antes, adicionar ou anexar após o destino.

Meus pensamentos:

.table .row .cell {
    .editing &(.row) {}
    .editing &(^.row) {}
    .editing &(.row^) {}
}

cumprido:

.table .row.editing .cell {}
.table .editing .row .cell {}
.table .row .editing .cell {}

Isso pode ser desenvolvido se houver correspondência múltipla.

@supnate Por favor, veja este comentário de @matthew-dean acima (este post define brevemente a sintaxe que se parece com a que finalmente concordamos menos ou mais como a menos problemática).

Meus pensamentos:

Isso parece um movimento na direção errada, a ordem dos seletores resultantes deve ser definida pela colocação adequada do próprio & (assim como funciona com & agora) e não pelo posicionamento de ainda outro símbolo especial. Por exemplo (usando a sintaxe do comment ) o CSS resultante em seu exemplo seria obtido com algo como:

.table .row .cell {
    &(.row).editing  {} // -> .table .row.editing .cell  {}
    .editing &(.row) {} // -> .table .editing .row .cell {}
    &(.row) .editing {} // -> .table .row .editing .cell {}
}

@seven-phases-max Obrigado pela resposta, desculpe por não ter passado pela discussão anterior. No entanto, acho que há apenas uma pequena diferença entre o meu e o de @matthew-dean. Do meu lado, é importante ser intuitivo que o que faz a diferença (.edição), então onde deveria estar.

Por falar nisso. pensando no exemplo recente (mais sobre possíveis detalhes de implementação para situações extremas), aqui está outro ponto de problemas, considere o seguinte código:

.a .b .c .d .e {
    &(.d) .x &(.b) {}
}

Agora a questão é onde .c e .e pousam no seletor resultante? Honestamente, não posso chegar com nenhum posicionamento razoável (qualquer resultado pareceria muito artificial). Embora o exemplo também seja artificial, não parece um problema real, pois sempre podemos terminar com "nesse caso, o resultado é indefinido/não especificado" (por exemplo, "sem vários & referindo-se a diferentes elementos" ou algo assim).

PS Ah, pensando mais nisso, parece que não há problema em resultar em algum lixo como:

.a .b .c .d .a .x .b .c .d .e .e {} // or
.a .a .b .c .d .x .b .c .d .e .e {}

Assim como

.a .b .c .d .e {
    & .x & {}
}

compila para

.a .b .c .d .e .x .a .b .c .d .e {}

Consulte o problema nº 2433 em um tópico relacionado sobre uma sintaxe de "referência de árvore" que pode ser aplicada a propriedades locais e propriedades de seletores pai, ponto em que pode valer a pena considerar como referência a seletores pai.

Sintaxe de exemplo:

.table .row .cell {
    ${.row}.editing  {}  // .table .row.editing .cell {}
}

Apenas mais uma possibilidade.

Eu gosto dessa discussão!

Eu tentei isso mas não funciona:

.feature {
  .feature-header:hover {
    background: red;
    @saved-context: &;
    .anotherTheme {
      .special-case-one,
      .special-case-two {
        & @{saved-context} {
          background: green;
        }
      }
    }
  }
}

/* expected output */
.feature .feature-header:hover {
  background: red;
}
.anotherTheme .special-case-one .feature .feature-header:hover,
.anotherTheme .special-case-two .feature .feature-header:hover {
  background: green;
}

/* actual output */
.feature .feature-header:hover {
  background: red;
}
.feature .feature-header:hover .anotherTheme .special-case-one &,
.feature .feature-header:hover .anotherTheme .special-case-two & {
  background: green;
}

Para fazer isso funcionar, você terá que escrever:

.feature {
  .feature-header:hover {
    background: red;
    .anotherTheme .special-case-one &,
    .anotherTheme .special-case-two & {
      background: green;
    }
  }
}

Apenas meus dois centavos.

uau uau uau que incrível, então pré-processamento

Pessoal, vejam esta discussão sobre stackoverflow para outros pensamentos, especialmente a seção de comentários:

http://stackoverflow.com/questions/32777856/less-css-parent-selector-walking-up-only-two-three-x-steps?noredirect=1#comment53532878_32777856

Nele sugere-se que este padrão pode ser desejado:

    // The &(1) would be all of & minus the last one.
    // The $(0, 1) would be all of & minus all of &(1)
    &(1) > .bottom > &(0, 1) {
            bottom: 0;
    }

Pessoalmente adoro a simplicidade da proposta ctsstc :

.grandparent {
  .parent {
    .child {
      background: white;

      &&&.black {
        background: black;
      }
    }
  }
}

&&&.black

É apenas incompatível com o comportamento atual de & . Além disso, é o mesmo "problema de (re)contagem manual" mencionado anteriormente.

Implementei algo semelhante para SASS em inStyle , atualmente trabalhando em possíveis portas LESS/Stylus.

Eu enfrentei o mesmo problema no ecossistema PostCSS, acabando escrevendo um plugin getter de seletores aninhados personalizados .

A sintaxe que escolhi para subir na hierarquia de seletores aninhados é & , ^& , ^^& (...) em vez de & , && , &&& . Funciona bem e não entra em conflito com nenhum seletor/pseudo-seletor conhecido.

Como este assunto ainda está em aberto...

Até agora, tentar "selecionar e inserir" de seletores pai acaba sendo terrivelmente complexo. O "onde" torna-se rapidamente ambíguo.

Acho que a única solução viável se esse recurso acontecesse precisaria ser algo semelhante a "capturar" e "substituir" que é usado com expressões regulares, onde você define pontos de inserção (neste exemplo marcado com ? ) que você usa para manipular a saída mais tarde.

.grandparent? {
  .parent? {
    .child {
      background: blue;
      &(1, :hover) {     // all selectors, but replace 1st insertion point with ":hover"
        background: red;
      }
      &(2, .active) {     // all selectors, but replace 2nd insertion point with ".active"
        background: white;
      }
    }
  }
}

resultando em:

.grandparent .parent .child {
  background: blue;
}
.grandparent:hover .parent .child {
  background: red;
}
.grandparent .parent.active .child {
  background: white;
}

Não estou sugerindo que essa seja a sintaxe correta, mas qualquer tipo de "direcionamento" que foi tentado neste tópico, seja por índice ou "nível de escopo", ou seletor nomeado, simplesmente não funcionará sem um alvo preciso.

Com pontos de inserção, eles têm uma ordem de indexação da esquerda para a direita, de cima para baixo, que não é ambígua. Você pode ver para onde sua coisa vai e pode especificar exatamente o que é essa coisa.

Portanto, qualquer solução viável, acredito, precisará ser alguma variação disso.

O que está acontecendo qual este? Algum progresso?

Este problema foi marcado automaticamente como obsoleto porque não teve atividade recente. Será fechado se não ocorrer mais nenhuma atividade. Obrigado por suas contribuições.

Este problema foi marcado automaticamente como obsoleto porque não teve atividade recente. Será fechado se não ocorrer mais nenhuma atividade. Obrigado por suas contribuições.

@seven-phases-max FYI Alterei o stalebot para não marcar um problema como obsoleto se o problema for priorizado de alguma forma.

Já implementei essa funcionalidade localmente.

Tendo trabalhado com Sass desde que este problema foi aberto, acho que esse problema poderia ser combinado com esta proposta Less: https://github.com/less/less-meta/issues/16

Resumindo, a proposta do momento é fazer seletores simples (mixins) atribuíveis a variáveis. Eu estou querendo saber se isso não deve se tornar válido (o que Sass faz):

.grandparent {
  <strong i="8">@grandparent</strong>: &;
  .parent {
    .child {
      background: blue;
      @{grandparent}:hover & //the problem here is that `&` contains .grandparent also, ideas?
        background: red;
      }
    }
  }
}

@matthew-dean Você está dizendo que isso já existe no Sass? Caneta?

Como eu disse, basicamente implementei uma funcionalidade muito semelhante à que você está propondo, apenas como uma chamada de método:

.grandparent {
       .something {
              closest('.grandparent', { &:hover { color:red: } })

      }
}

Passou mais de uma semana nisso. O único problema agora é que eu preferiria migrar para o Stylus e descartar menos, mas agora eu teria que reimplementar essa funcionalidade, o que é um aborrecimento.

Se você se pergunta por que não envio a solução, veja aqui .

@matthew-dean Você está dizendo que isso já existe no Sass? Caneta?

Isso existe no Sass. Usei hoje:

.selector {
  $sel: &;
  @at-root :global(.platform-web) {
    <strong i="7">@include</strong> responsive-margins($sel)
  }
}

<strong i="8">@mixin</strong> responsive-margin($sel: '&') {
  #{$sel} {
    margin: $gap-s auto;

    + #{$sel} {
      padding-top: $gap-m;
    }

    <strong i="9">@media</strong> (min-width: $size-phablet) {
      margin: $gap-l auto;
    }
  }
}

Eu precisava fazer isso porque meu mixin tinha & + & , mas isso teria repetido meu seletor global de módulos CSS. Então eu tive que "salvá-lo" e, em seguida, recomeçar na raiz com a classe global e passar o seletor salvo.

@matthew-dean você está dizendo que vai até o nó raiz (possível com menos) e depois usa um seletor salvo para ? Seu exemplo não está completo, pois parece ter sido retirado de uma fonte de código real. Não tenho certeza do que é suposto fazer e gerar.

No meu exemplo, ele pode segmentar qualquer seletor de ancestral e aplicar uma regra a partir daí, então no meu exemplo isso

.grandparent {
       .something {
              closest('.grandparent', { &:hover { color:red: } })
      }
}

é o mesmo que

.grandparent { &:hover { .something { color:red; } } }

@momomo

Quanto a descobrir a base de código, eu estaria perfeitamente disposto a dizer o que eu sei/aprendi sobre a base de código se você quiser dar uma olhada. Sinta-se à vontade para me enviar uma DM no Twitter e verei o que posso fazer para ajudar - https://twitter.com/matthewdeaners

@momomo

Seu exemplo não está completo

Atualizei meu exemplo.

a pergunta foi considerada estúpida, censurada e encerrada

Interessante. Eu ficaria curioso se alguém usasse a palavra "estúpido". Caso contrário, pode ser que alguém não tenha visto o valor e pode ser difícil defender seus próprios casos de uso, especialmente para uma biblioteca de uso geral.

Para ser justo, todo esse segmento era inteiramente teórico até que eu precisei disso hoje e não haveria outra maneira de implementar isso de maneira abstrata.

Também a isto:

Até os caras do Sass diziam que era impossível.

Observe que meu caso de uso não aborda "inserir" algo como :hover em um seletor pai (herdado). Portanto, seu caso de uso pode ter sido impossível em Sass, como é em Less. Então, meu exemplo foi postado apenas para ilustrar que ALGUNS casos de uso podem ser resolvidos, mas não resolve todos, incluindo alguns anteriores que postei.

"Então, seu caso de uso pode ter sido impossível em Sass, como é em Less"

Não, não era impossível em termos de funcionalidade. Claro, eu tive que adicionar um método de extensão, mas foi considerado impossível porque Less ou Sass não podiam procurar porque está compilado e não sabe sobre seus arredores (html). Foi considerado "inútil", não benéfico de forma alguma. Bem, seus padrões de codificação não são bons o suficiente, eu acho. Eu não estava falando sobre subir na árvore dom, mas na árvore declarada css/less/sass.

Realmente não é tão complexo de entender e meu exemplo é bastante simples. Você acha que é difícil de entender?

O meu basicamente resolve a maioria, se não todos esses problemas.

A ideia é que, se você estilizar algo e precisar ir até algum ancestral, digamos, para hover ou class add, ou attribute, ou qualquer outra coisa, esse código deve estar no mesmo local, não precisa ser declarado separadamente no nível do ancestral e repetido até o mesmo elemento que precisa ser estilizado. Isso causa a fragmentação do código e, no final, você tem código para estilizar os mesmos elementos em vários locais.

Eu estava defendendo uma solução para que permitisse que você avançasse segmentando um determinado seletor ou andasse N pais.

Por exemplo

closest(3, { :hover { walks up three parents } }

também funciona

closest(1, { :hover { walk up one parent } } que é o mesmo que &{ :hover { walk up one parent }}

closest('.someAncestorVeryHighUp', { :hover { walks up all the way up to that class } })

closest('[attribute=valueAlsoWorks]', { :hover { walks up all the way up to that attribute val match } })

Se meu código for tornado público, quero um pedido de desculpas primeiro, porque ainda estou frustrado, principalmente porque continuei batendo em uma parede como a maioria aqui e a falta desse recurso tem sido um grande irritante há anos, porque sempre levou ao código ficando mais complexo do que o necessário à medida que o código less/css em um projeto crescia.

Além disso, você acabou de reabrir um ticket fechado. Por que foi fechado? Quem o * * decidiu fechá-lo? Eu odeio Reddit, censura e pessoas que pensam que sabem melhor ou têm todas as respostas.

Então, por fazer uma pergunta que se originou há seis anos, se não mais (outras questões anteriores) que foi encerrada, finalmente abordada e resolvida por mim sem nenhuma ajuda para entender esse código de merda, quero um pedido de desculpas. ( <- "Continue sonhando. É grátis." - spm ).

Sim, soa como Trump. Estou totalmente ciente, mas, novamente, isso é um discurso retórico.

@matthew-dean

Falando do seu exemplo em https://github.com/less/less.js/issues/1075#issuecomment -396367364.
Temos até um protótipo de plugin funcional para isso: https://github.com/less/less.js/issues/2619#issuecomment -115006426
(também em https://github.com/seven-phases-max/less-plugin-reflections).
O único problema é que (mesmo que o plugin funcione como você espera) há alguns truques teóricos do ponto de vista da linguagem: por causa da avaliação preguiçosa, o valor de @grandparent não deve ser "congelado" no <strong i="12">@grandparent</strong>: &; linha (ou seja, a menos que haja alguma sintaxe específica e/ou alguma função específica para forçar sua avaliação, o princípio LE determina que @{grandparent}:hover & seja expandido para a mesma coisa &:hover & ) . Ou seja, não podemos economizar esse valor assim: <strong i="17">@grandparent</strong>: &; - mais pesquisas necessárias.

E é lindo código:

https://imgur.com/a/RWCEYtB

Todo offtopic está limpo (para os interessados ​​eu movi todas as acusações com meus comentários aqui ).

Não, não era impossível em termos de funcionalidade. Claro, eu tive que adicionar um método de extensão, mas foi considerado impossível porque less não poderia procurar porque está compilado e não conhece o ambiente (html).

Então isso é apenas alguém entendendo completamente mal o seu exemplo. Não, seu exemplo é simples e eu entendo o que você quer. É uma solicitação semelhante aos exemplos "capture" e "replace" em todo este tópico, você está apenas demonstrando usando uma sintaxe diferente.

Eu me pergunto se o mais fácil não é apenas:

  1. Permitindo atribuir & a uma variável, ou como parâmetro a uma função.
  2. Usando a função de substituição.
  3. Adicionando um seletor de tipo "na raiz" ( ^ ?)

Então você poderia apenas fazer:

.grandparent {
  .something {
    @grandparent-hover: replace(&, '.grandparent', '.grandparent:hover');
    ^ @{grandparent-hover} {
      color: red;
    }
  }
}

São alguns recursos em um, e é por isso que a discussão deste tópico tem sido tão complexa, porque quando as pessoas levantam exemplos, estão falando sobre vários recursos para um caso de uso.

Ops, eu tinha essa guia aberta no meu navegador e não vi os comentários mordazes que aconteceram nesse ínterim.

Ou construir em substituir? ...
🤔

.grandparent {
  .something {
    // & currently = .grandparent .something
    &:visited {
      color: yellow;
    }
    &(.grandparent; .grandparent:hover) {
      // & now = .grandparent:hover .something
      color: red;
      &:visited {
        color: blue;
      }
    }
  }
}

// output CSS
.grandparent .something:visited {
  color: yellow;
}
.grandparent:hover .something {
  color: red;
}
.grandparent:hover .something:visited {
  color: blue;
}

Spitballin'... parece mais robusto e claro do que a referência numérica do índice, que pode ser ambígua. Apenas o seletor de pesquisa / substituição embutido em uma função &() .... uma desvantagem é que podemos querer outras extensões " & alteração" no futuro?

Isso ainda requer as adições de recursos de:

  1. Passando seletores para funções.
  2. & como uma função

Ou construir em substituir? ...

Ou declarando explicitamente um espaço reservado dentro do seletor de interesse para não criar um código potencialmente independente para adivinhar, saber ou hackear o nome ou a posição de um elemento específico (quando não for necessário).

Para o meu gosto, a coisa Sassish @at-root tem um problema típico de backdoor codificado (de ser facilmente quebrado):

.foo {
   @at-root .bar {color: red}
}

então em uma galáxia distante:

.baz {
    <strong i="14">@import</strong> "foo.less"; // oops
}

Ou declarando explicitamente um espaço reservado dentro do seletor de interesse para não criar um código potencialmente independente para adivinhar, saber ou hackear o nome ou a posição de um elemento específico (quando não for necessário).

Esse exemplo parece um pouco confuso para mim, embora eu ache que é essencialmente "capturar" e "substituir"? Eu não poderia dizer. Assim , mas apenas com nomes explícitos? Se for esse o caso, isso também é razoável para mim.

Para o meu gosto, a coisa Sassish @at-root tem um problema típico de backdoor codificado (de ser facilmente quebrado):

Eu não discordo, por isso escrevi um segundo exemplo que não exige isso. Mas não acho totalmente desnecessário. Eu só acho que não deveria ser construído em uma solução potencial aqui. Eu acho que "alteração no local da herança & " é provavelmente melhor (do que algo usando uma solução semelhante a @at-root ).

Mas, para ser claro, como mencionei acima, capturar/substituir também parece apropriado.

@seven-phases-max Uma coisa que pode ajudar esse tópico a girar suas rodas para todo o sempre. Destas soluções: a) alteração in loco de & , b) captura/substituição, c) outra - Tem preferência? Porque parte do giro da roda é literalmente abordagem, não apenas sintaxe. Se houvesse algum consenso sobre a abordagem, a sintaxe poderia eventualmente se consolidar aqui.

O que há de errado com:

css  = '' +
'.body {  ' +

        '.main { ' +

            '.section {' +

                '.article {' +
                        // --- Call made here! ---

                        // Climb up to .main, and then add the selectors inside the body below
                        'closest(".main", {' +

                            '&:hover {' +
                                'background-color:red;' +   // Meaning that when you hover .main then .article will get background-color:red;
                            '}' +

                            '&.someclass {' +
                                'background-color:blue;' +   // Meaning that when .someclass is added to .main then .article will get background-color:blue;
                            '}' +

                        '})' +

                        // Do note that purpose of climbing up is to style article, nothing else.

                    '}' +

                '}' +
        '}' +
'}';

less.render( css ,function (error, output) {
        console.log('xxx');  console.log(output.css);
});

Você pode fazer um monte de outras coisas dois.

@momomo

O que há de errado com:

Não há nada particularmente "errado" com isso. De fato, há algum tempo, Less permite que funções sejam chamadas em praticamente qualquer nó. Então você provavelmente poderia fazer isso como Less @plugin . Gostaria de saber se essa não é a melhor maneira de resolver isso.

Mas, no que diz respeito à sintaxe, IMO não é um bom ajuste na linguagem Less, porque existem algumas esquisitices / outliers nessa construção, como envolver seletores entre aspas e chamar uma função na raiz. O que você PODE fazer e definir funções para esse fim. Portanto, se você quiser resolver isso como um plug-in, poderá fazê-lo hoje, sem nenhuma alteração de sintaxe Less. Seria chamado literalmente com:

<strong i="12">@plugin</strong> "closest";
.body {
  .main {
    .section {
      .article {
        // This will parse, as there's nothing invalid about this syntax
        closest(".main", {
          &:hover {
            background-color: red;
          }
          &.someclass {
            background-color: blue;
          }
        });
      }
    }
  }
}

A única parte complicada: qualquer seletor retornado por closest() ainda terá as mesmas regras de mesclagem aplicadas. Ainda acho que um plugin conseguiria dar o comportamento desejado.

@matthew-dean

Exatamente. Em relação às cotações não serem ideais, concordo com você, no entanto, considerando a complexidade e o tempo que levou para resolver esse problema usando outros meios e a desvantagem percebida de usar aspas, acho que basicamente não é um problema, especialmente se quisermos acelerar a adição de tal funcionalidade.

Certamente isso pode e deve ser feito antes do método do plug-in entrar em ação (o desempenho é um dos motivos), mas isso pode mostrar a funcionalidade desejada e abrir o caminho, pois ainda não está claro o que a funcionalidade desejada deve fazer. Há também muitos outros problemas, em termos de sintaxe com Less, que são muito piores.

Por favor, entre em contato comigo no opensource ATTT momomo DOTTT com e podemos começar a partir daí. Eu não uso Twitter infelizmente.

Por comentário aqui , na discussão sobre como "consumir" um seletor & capturado, houve uma discussão sobre a substituição de & no local, o que levou de volta a esse problema. Como isso está mais alinhado, pensei em continuar aqui do que estava sendo discutido, que era semelhante ao que mencionei em https://github.com/less/less.js/issues/1075#issuecomment -397697714

  • &() - retorno no local &
  • &(arg) - substitua & por arg e retorne
  • &(arg1, arg2) - substitua arg1 em & por arg2 e devolva como novo &

A coisa complicada sobre isso é: é uma modificação da herança do seletor para todos os outros filhos? Ou é apenas uma modificação _para esse seletor específico_? Como em:

.component {
  &(.foo) .child { // selector is now .foo .child ?
    & .grandchild { // is & now .foo .child? Have we altered it permanently? I would presume yes
    }
  }
}

Além disso, isso evitaria coisas como:

.something:not {
  &(.selector) {}
}

Não tenho certeza se alguém teria motivos para escrever isso, mas vale a pena apontar.

Que tal esta abordagem:

^ - volta um seletor
^(x) - voltar x seletores
(sinal: "^" é inspirado em: http://docs.emmet.io/ )

#wrapper {
  .row {

   .text-side {
      h2{
        color : #000;
        }// h2
      .text-description{
          p{
            color : #333;
            mark{
              background-color: green;
              } // mark
            } // p
        } // .text-description  
    }

    ^ .image-side {
   // avoid 1 selectors: .row
      .image-block {
        ^(2) img{
        // avoid 2 selectors: .image-block .image-side
          width: 100%;
          } // img
        } // .image-block
      } // .image-side

  }// . row
} // #wrapper

Fonte: https://github.com/sass/sass/issues/2193

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

Questões relacionadas

briandipalma picture briandipalma  ·  6Comentários

renoth picture renoth  ·  6Comentários

BrianMulhall picture BrianMulhall  ·  4Comentários

chricken picture chricken  ·  6Comentários

papandreou picture papandreou  ·  7Comentários