Less.js: Adicione suporte para variáveis ​​"default" (semelhante a !default no SASS)

Criado em 3 dez. 2013  ·  35Comentários  ·  Fonte: less/less.js

Estamos pensando em mudar de SASS para LESS, mas o principal obstáculo para nós é a falta de um recurso de "variável padrão" (consulte http://sass-lang.com/documentation/file.SASS_REFERENCE.html#variable_defaults_)

Esse recurso é incrivelmente útil ao distribuir seu código SASS como uma biblioteca onde as variáveis ​​servem como uma espécie de "API" para seus usuários. Nesse caso de uso, tudo o que o usuário precisa fazer é certificar-se de que suas variáveis ​​sejam incluídas antecipadamente para substituir os padrões que ele deseja alterar e voila! sem mexer na ordenação dos (possivelmente) muitos arquivos que podem conter as variáveis ​​que precisam ser substituídas.

Comecei a trabalhar em uma implementação, ainda não escrevi nenhum teste, mas espero que possamos usar essa solicitação de pull como ponto de partida para discussão: https://github.com/less/less.js/pull/1705

Eu escolhi a seguinte sintaxe:

?foo: value;

em oposição ao modo SASS:

<strong i="13">@foo</strong>: value !default;

por 2 razões - é mais conciso, e a sintaxe !default pode apresentar problemas potenciais com a análise de expressão no lado direito no futuro (mas eu posso estar errado sobre isso).

A implementação que criei foi surpreendentemente simples - espero não ter perdido nada importante. Eu realmente aprecio qualquer feedback que você possa ter.

Saúde,
Phil

consider closing feature request low priority

Comentários muito úteis

Eu ia sugerir o artigo que escrevi e então vi que @seven-phases-max tinha um link para ele. 😄 Confie em nós, o que você está pedindo já existe! Mas você precisa entender a avaliação de variáveis ​​de Less para entender como/por que ela existe.

Todos 35 comentários

Consulte A Documentação .


Atualização: Removido meu comentário anterior deste post para não confundir futuros visitantes (aqui eu estava tentando responder a pergunta "como definir uma variável se ainda não estiver definida" e perdi o ponto de que é um "Problema XY" e a resposta correta para um Sass-like !default é: em Less você não precisa de nada disso porque a funcionalidade necessária ("(re)definição após o uso") já é fornecida pela maneira como as variáveis ​​Less funcionam).

Se você definir a mesma variável duas vezes, a última declaração vence e é válida em todo o escopo. Então, outra opção seria declarar variáveis ​​normalmente e pedir ao usuário para incluir suas variáveis ​​após sua biblioteca.

biblioteca.sem

<strong i="7">@width</strong>: 0;
.mixin {
  width: @width;
}

user.less:

<strong i="11">@import</strong> "library.less"; //first declaration of <strong i="12">@width</strong>
<strong i="13">@width</strong>: 1; //this will override <strong i="14">@width</strong> defined previously
.class {
  .mixin();
}

compila em:

.mixin {
  width: 1;
}
.class {
  width: 1;
}

Obrigado pelo feedback sobre o nosso PR. Essas soluções seriam viáveis ​​se tivéssemos uma única coisa ou algumas pequenas coisas para consumir. Então deixe-me explicar por que essas soluções não são viáveis ​​no nosso caso.

Fazemos um grande framework de componentes implementados como uma hierarquia de classes. Declaramos as variáveis ​​para cada componente em seu próprio arquivo... em nosso tema base. Em seguida, "derivamos" temas daqui que desejam modificar essas variáveis. Os usuários podem fazer isso para ajustar um tema às suas necessidades.

Além disso, as variáveis ​​geralmente "derivam" de outras variáveis. O mais óbvio é a cor base. Passamos muito tempo discutindo alternativas para os problemas de grandes hierarquias de classes de componentes usando propagação agressiva de valor de variável combinada com temas e seu próprio comportamento de herança.

De longe, a melhor solução para esses problemas é _sempre_ definir variáveis ​​como "!default" (em termos Sass). Isso permite que os usuários simplesmente entrem primeiro e definam seus valores antes que esses valores sejam usados ​​para calcular outros valores. O tempo é então bastante simples de gerenciar para nossos usuários. Como esse é sempre o caso de todas as variáveis ​​em todos os nossos temas, problemas de sintaxe como os sugeridos acima seriam um fardo e também propensos a erros.

Adoraríamos contribuir com outros recursos para o Less à medida que continuamos. Acho que nosso caso de uso (extraordinariamente?) em grande escala pode ser uma validação útil do que é necessário para aumentar o conjunto de idiomas/recursos.

Espero que você considere mesclar isso ou forneça algumas alternativas que sejam mais declarativas por natureza. Explorar truques de escopo realmente não funcionará para nós.

Obrigado novamente pelo seu tempo e consideração!

Parece que você pode ser melhor definir mixins em vez de classes diretas. Então, as variáveis ​​podem ser substituídas mais tarde em sua folha de estilo principal ou em outro tema derivado. É assim que sou capaz de substituir coisas como as larguras da minha calha nas minhas grades depois de importá-las.

Apenas para esclarecer, estamos falando apenas de variáveis ​​aqui. E não temos uma folha de estilo principal - temos uma por classe por tema. :)

Talvez eu não esteja seguindo sua sugestão, mas como exemplo, um de nossos arquivos de variáveis ​​de tema se parece com isso:

$panel-base-color: $neutral-light-color !default;
$panel-header-color: $base-color !default;
$panel-frame-border-width: 1px !default;
$panel-header-font-size: round($font-size * 1.15) !default;
$panel-body-border-color: $neutral-dark-color !default;

$panel-light-header-color: #000 !default;
$panel-light-header-background-color: #fff !default;
$panel-light-tool-background-image: 'tools/tool-sprites-dark' !default;
$panel-light-body-border-color: $neutral-dark-color !default;
$panel-ignore-frame-padding: true !default;

Este arquivo configura os vários valores do Painel para um tema que possui uma cadeia de temas básicos 4 de profundidade. Esses temas básicos têm seus próprios valores de variável para Panel, mas eles são carregados primeiro, portanto, substitua-os. A menos que um tema de usuário seja derivado desse tema e forneça valores próprios.

Este padrão é repetido _muito_ :)

Ok, bem, por que não apenas substituir @panel-base-color em sua folha principal menos? As variáveis ​​LESS são globais, então a que ocorrer por último é a vencedora.

<strong i="7">@import</strong> 'theme.less';

@panel-base-color: red;

Agora, qualquer lugar usado no tema será substituído. Se ninguém substituir isso em sua cadeia de importação, o que foi definido originalmente será o padrão.

Não temos uma "folha principal menos" :) Agradeço sua ajuda e sugestões, mas tivemos muitas discussões sobre isso internamente e elas tendem a continuar um pouco. Basta dizer que acreditamos que precisamos de configuração de variável padrão como propomos aqui. Esse recurso existe no Sass e achamos muito útil para reduzir a complexidade e fornecer aos usuários flexibilidade na configuração de nossos temas.

Estou curioso se tudo isso significa que este pull request ou algum derivado similar seria aceito? Ficaríamos felizes em ajustar a sintaxe se isso for censurável.

Não temos uma "folha principal menos" :)

Simplesmente substitua "sua folha principal menos" nas respostas acima por "qualquer uma das folhas menos do usuário". Até agora parece que SASS !default (qualquer que seja a sintaxe que tenha) foi inventado para resolver um problema que não existe em LESS.
@dongryphon , posso estar errado, é claro, mas você ainda não entendeu por que não pode usar a solução sugerida por @SomMeri e @Soviut.

Em outras palavras, imagine se você não estivesse importando e, em vez disso, tivesse todas as suas variáveis ​​na mesma planilha. Isso é efetivamente o que a importação faz. Então, nessa situação, se você tivesse duas declarações de variáveis ​​com o mesmo nome, a última da planilha venceria.

@base-color: green;

div {
    background: @base-color;
}

@base-color: red;

Como a cor base é declarada novamente no final, a cor base usada na div será vermelha. Ele irá compilar para:

div {
    background: red;
}

Isso surgiu antes, na verdade, acredito que foi implementado e tivemos um pull request de caras que queriam isso no bootstrap e eles concordaram após alguma discussão que era um recurso inútil em menos.

A única coisa que permite é que os usuários definam variáveis ​​antes de importar. Se os usuários definirem overrides depois, funcionará como se tivesse um padrão nele.. isso porque mesmo no arquivo importado, ele levará a última definição da mesma maneira que o css, mesmo se definido após o uso.

Não é um fardo para os usuários de uma biblioteca dizer que eles substituem variáveis ​​​​após importações (ou importam um arquivo de variáveis ​​​​após importações) versus adicionar mais sintaxe a menos. faça a mesma quantidade que o sass, mas na maioria das vezes com uma sintaxe mais simples.

Isso é contrário ao que um programador JavaScript pode pensar, mas a ideia por trás disso é que está mais perto de css.

Por favor, você pode explicar por que pedir aos consumidores que considerem o pedido não é possível ou desejável? Aceitaremos recursos com casos de uso fortes, mas temos que ser rigorosos para evitar excesso de linguagem e complexidade.

Consulte #1109 #1104 #313

E só para esclarecer, não estamos dizendo "não" de forma alguma. Estamos tentando mostrar que esse recurso já pode existir.

Eu adicionei algumas informações a less-docs

Fechando como já disponível (em "Menos maneira") recurso (http://lesscss.org/features/#variables-feature-default-variables).

Acho que essa confusão geralmente surge porque, embora haja _sintaxe_ sobreposta, o SASS "executa" de cima para baixo, mas o LESS não e, em vez disso, opera mais como CSS. LESS é como CSS+ (CSS com recursos adicionais), e SASS é como "PHP com sintaxe CSS". Eu me pergunto se há uma maneira (se necessário) de fazermos essa distinção.

Por favor, você pode explicar por que pedir aos consumidores que considerem o pedido não é possível ou desejável? Aceitaremos recursos com casos de uso fortes, mas temos que ser rigorosos para evitar excesso de linguagem e complexidade.

Porque ensinamos os usuários da biblioteca (e consumidores) a nunca editarem os códigos da biblioteca. A falta do recurso !default significa que temos que fazer uma dessas duas coisas - ambas igualmente ruins imo:

  • Os próprios usuários precisam editar a folha de estilo da biblioteca para editar as variáveis ​​onde são declaradas (o que é meio proibido, dificultando as atualizações da biblioteca) ou,
  • A biblioteca deve fornecer duas folhas de estilo: uma para variáveis ​​padrão e outra para regras reais. Então o usuário tem que @importar a primeira, então declarar suas próprias variáveis, então @importar a segunda. É mais complexo do que deveria ser, principalmente manter esses dois arquivos na mesma versão.

A abordagem sass significa que uma biblioteca só precisa fornecer um único arquivo, que o usuário poderá personalizar.

my-color: red;
<strong i="15">@import</strong> "./my-library.less";

Ao invés de:

<strong i="19">@import</strong> "./my-library-variables.less";
my-color: red;
<strong i="20">@import</strong> "./my-library-rules.less";

Acho que você deveria reconsiderar essa questão.

@arcanis Na verdade, não consigo ver por que você acha que:

A biblioteca deve fornecer duas folhas de estilo: uma para variáveis ​​padrão e outra para regras reais.
A abordagem sass significa que uma biblioteca só precisa fornecer um único arquivo

Em Less é absolutamente o mesmo design de biblioteca:

<strong i="11">@import</strong> "./my-library.less";
@my-color: red;

Eu acho que você está simplesmente perdendo a coisa "Lazy-Loading" (e exatamente o mesmo exemplo é usado nos documentos para dizer no, thanks! to !default ).

Eu acho que você está simplesmente perdendo a coisa "Lazy-Loading"

@seven-phases-max WTF, você está certo. Droga, eu provavelmente deveria deletar minha resposta inteira (e acabei de fazer). Você está me dizendo que pode importar bootstrap e apenas substituir vars específicos, e isso funcionará?

Eu não acreditei em você, e fiz meus próprios testes para verificar isso. Como eu perdi isso?? Acho que é porque todos os artigos que vi no Bootstrap, que incluíam customização, recomendavam que você copiasse o arquivo variables.less e defina seus próprios valores, o que obviamente causa problemas quando mais variáveis ​​são adicionadas à biblioteca. E acho que tive a impressão de que os seletores estavam sendo produzidos no ponto imediato da importação. As variáveis ​​sempre "carregaram lentamente" dessa maneira?

Esse deve ser o recurso mais importante e comumente perdido no Less. Eu nunca vi uma postagem no blog sobre a biblioteca Less or Less que menciona esse recurso. Mesmo com tudo no tópico aqui e a documentação, não ficou imediatamente óbvio o que isso significava com as bibliotecas do mundo real. Eu pensei que todo mundo estava simplesmente dizendo que você poderia substituir variáveis ​​declaradas anteriormente, definindo-as mais tarde, e eu nunca entendi que isso afetaria a avaliação de variáveis ​​de documentos importados anteriores.

Eu não posso acreditar que eu nunca consegui isso até agora. Isso muda basicamente tudo sobre como eu estruturo meus documentos menos, e tem uma pequena menção nos documentos que não demonstra a saída.

Talvez a razão pela qual recebemos tantos pedidos para um recurso !default no Less seja porque poucas pessoas intuem esse recurso ou o entendem pelo breve exemplo dos documentos (incluindo eu, obviamente).

No mínimo, obrigado por explicar novamente @seven-phases-max!

Ops. Bem, você está certo. Eu também interpretei mal os documentos, meu mal!

@Soviut você é um gênio danado! Eu não tinha ideia de que as declarações de variáveis ​​funcionassem assim em SASS/LESS. Obrigado!

Ainda estou batendo na minha testa que este não era um comportamento óbvio com tudo o que escrevi em Less. Acho que meu problema era que eu tinha visto artigos de exemplos ruins escritos por pessoas que não entendiam como fazer isso.

Além disso, observe: @spikesagal no que diz respeito à sua declaração: "Eu não tinha ideia de que as declarações de variáveis ​​funcionassem assim em SASS/LESS" -- Até onde eu sei, o comportamento das variáveis ​​não é o mesmo entre as duas linguagens, já que SASS e LESS avaliam as coisas de forma muito diferente.

E eles estão matando esse recurso no BS4 por causa da mudança para o Sass... :-1: Ainda muito triste com essa mudança.

Assim começa, a luta por mais variáveis ​​!default: [twbs/bootstrap#17418]

Bem, eles não podem matar o recurso Less alterando as fontes SCSS de qualquer maneira. (Tecnicamente, nem é um "recurso" (como algum tipo de "comportamento sintetizado"), mas uma propriedade/corolário fundamental da avaliação preguiçosa). Contanto que haja uma versão Less do BS (isso é apenas uma questão de contagem de pessoas dispostas a contribuir para isso), e houver pelo menos uma variável global - você sempre poderá substituir essa variável.

Nós vamos. O oficial v4-alpha do bootstrap mudou-se para Sass. Isso, pelo menos no meu entendimento, está matando menos em sua documentação oficial - e isso significa também matar o suporte para esse recurso porque o Sass não possui variáveis ​​​​de carregamento lento. Eles suportam apenas !default, o que, de certa forma, significa: "Ah, sim, permitimos que você substitua nossas variáveis ​​apenas uma vez de fora, e somente se permitirmos. Então, se esquecermos de lhe dar acesso a uma variável simplesmente omitindo o !default, você está bem ferrado e tem que sobrescrever todo o maldito seletor em seus arquivos.

e isso significa também matar o suporte para esse recurso porque o Sass não possui variáveis ​​de carregamento lento.

Bem, isso significa apenas "eles matam no Bootstrap" (o que obviamente é algo fora do escopo deste segmento - desde que não haja uma versão Less do BS, não devemos nos importar com os recursos do Bootstrap no repositório _this_, devemos?).

Como essa discussão foi basicamente sobre substituir variáveis ​​no bootstrap ...

Estamos ficando com menos :smile:

Eu tenho um caso de uso para o dilema originalmente declarado. Considere o seguinte exemplo simplificado:

  1. Eu tenho um arquivo menos que define o tamanho da fonte de h1, algo assim
    <strong i="8">@font_size__h1</strong> = 30px;
  2. Eu tenho (por falta de uma frase melhor) um plugin que contém um arquivo LESS separado que usa a declaração @font_size__h1 . Então eu <strong i="12">@import</strong> (reference) "path/to/file.less"; isso. Sem problemas, já está disponível.
  3. Agora eu levo esse "plugin" para um novo site que não tem @font_size__h1 definido em nenhum lugar. Neste ponto, seria ótimo dizer "Se @font_size__h1 estiver definido, use esse valor. Se não estiver definido, use o valor que defino aqui."

O item 3 não é possível no momento, até onde posso ver.

@theMikeD

O item 3 não é possível no momento, até onde posso ver.

Parece que você não leu o tópico:

<strong i="10">@import</strong> "path/to/file.less";
<strong i="11">@import</strong> "here.less"; // if it's not defined <elsewhere>, then use the value I define <here>
<strong i="12">@import</strong> "elsewhere.less";

que naturalmente pode ser reduzido a:

<strong i="16">@import</strong> "path/to/file.less"; // <- define default value there
@font-size-h1: foo;          // if it's not defined here then use the value defined above

que é basicamente o mesmo exemplo que http://lesscss.org/features/#variables -feature-default-variables

Sim, eu li o tópico. Parece que você não entende o que estou perguntando, porque seu exemplo tem minha pergunta invertida.

que naturalmente pode ser reduzido a:
@import "caminho/para/arquivo.less"; // <- defina o valor padrão lá
@font-size-h1: foo; // se não estiver definido aqui, use o valor definido acima

Isso é o oposto do que eu preciso. Isso substituirá o valor de @font-size-h1 em path/to/file.less pelo valor local, não importa o que aconteça. O que eu preciso é que o valor no arquivo local seja usado apenas se:
a) path/to/file.less não está carregado, ou
b) o valor de '@ font_size__h1 is not set in path/to/file.less`

IOW o valor local de @font-size-h1: foo; sempre estará presente no arquivo local, mas deve ser substituído se estiver definido em path/to/file.less

De qualquer forma, encontrei a solução ontem à noite, que é atribuir primeiro o valor local e depois colocar a instrução @import no final do arquivo, não no início. Se encontrado, ele substituirá o valor local.

Obrigado de qualquer maneira.

Parece que você não entende o que estou perguntando

Eu prefiro sugerir que você comece com algumas noções básicas de menos variáveis ​​para atualizar sua visão:

(porque parece que você está apenas tentando pensar em tudo de uma maneira imperativa do tipo C/PHP, enquanto em Less/CSS é totalmente "declarativo de cabeça para baixo").
Tem sido falado até a morte ao longo desses anos, !default pode adicionar _nada_ novo se comparado à substituição nativa da variável Less. Período. (Já estivemos lá muitas vezes antes: se alguém acha que encontrou algum caso de uso para !default em Less, isso não significa nada além de seu mal-entendido sobre a semântica de Less variable).

O que eu preciso é que o valor no arquivo local seja usado apenas se:
a) path/to/file.less não está carregado, ou
b) o valor de @ font_size__h1 não está definido em path/to/file.less

Então é simplesmente o oposto:

@font-size-h1: foo;
<strong i="27">@import</strong> "path/to/file.less"; 

tada!

...que é onde eu pousei, como eu disse.

Eu ia sugerir o artigo que escrevi e então vi que @seven-phases-max tinha um link para ele. 😄 Confie em nós, o que você está pedindo já existe! Mas você precisa entender a avaliação de variáveis ​​de Less para entender como/por que ela existe.

Eu tenho um componente - que é uma grade de dados. Este componente deve ter um estilo padrão - definido pelo pacote de componentes. Mas se uma determinada variável de fora já está definida, essa deve ter prioridade.

app.less
/grade/grade.less

Como a grade é um componente, esqueça de adicionar qualquer coisa aqui - ou adicionar qualquer código após o arquivo grid.less.
Não vejo como menos cobre esse problema. O Scss oferece esse recurso por um bom motivo.

@geri777

Mas se uma determinada variável de fora já está definida, essa deve ter prioridade.

Menos avalia como CSS.

.css {  
  --color: blue;
  color: var(--color);  // --color will be red
  --color: red;
  border-color: var(--color);  // --color will still be red, red is the scope's final value
}

.less {  
  <strong i="10">@color</strong>: blue;
  color: @color;  // <strong i="11">@color</strong> will be red
  <strong i="12">@color</strong>: red;
  border-color: @color;  // <strong i="13">@color</strong> will still be red, red is the scope's final value
}
````

Scss, instead, doesn't mimic CSS evaluation and instead evaluates more like, say, PHP.

```scss
.scss {  
  $color: blue;
  color: $color;  // $color will be blue
  $color: red;
  border-color: $color;  // $color will be red
}

Então, em Sass/SCSS, para substituir o valor de uma variável raiz, você é forçado a fazer duas coisas:

  1. Você deve marcar todas as suas declarações de variáveis ​​com !default
  2. Você deve inserir suas variáveis ​​globais antes dessas declarações padrão.

Como em:

// main.scss
<strong i="22">@import</strong> "overrides.scss";
<strong i="23">@import</strong> "library.scss";

// overrides.scss
$color: red;

// library.scss
$color: blue !default;

.scss {
  color: $color;
}

No Less, o tema é muito mais fácil. Você (normalmente) não precisa alterar nada em sua biblioteca, você só precisa colocar suas substituições depois. Você só precisa fazer uma coisa.

// main.less
<strong i="27">@import</strong> "library.less";
<strong i="28">@import</strong> "overrides.less";

// overrides.less
<strong i="29">@color</strong>: red;

// library.less
<strong i="30">@color</strong>: blue;

.less {
  color: @color;
}

Portanto, você não precisa !default porque Less sempre aceitará seu valor final.

Pense na avaliação Less como a cascata do CSS. Ele apenas funciona. A declaração final vence.

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