Less.js: Разрешить охранникам работать с неопределенными переменными

Созданный на 4 июл. 2013  ·  46Комментарии  ·  Источник: less/less.js

.guard () when (@variable) {
  a {
    color: red;
  }
}

Переменная не определена, поэтому нет вывода.

<strong i="8">@variable</strong>: true;

.guard () when (@variable) {
  a {
    color: red;
  }
}

Переменная определена, поэтому вывод:

a {
  color: red;
}
feature request low priority support as plugin

Самый полезный комментарий

Было ли какое-то движение по этому запросу? Я уже некоторое время беспокоюсь о проверке неопределенной переменной. На данный момент у меня есть работа, которая далека от идеала...

p {
  & when not (@body-text-color = null) {
    color: @body-text-color;
  }
}

но для того, чтобы это работало, переменная должна существовать и быть определена как null по умолчанию. Это было бы гораздо более эффективным/гибким, если бы я мог просто проверить, существует ли переменная вообще.

Все 46 Комментарий

+1
Это также можно использовать для установки базовых цветов в библиотеках.
Представьте себе следующий случай:
У вас меньше файла для конкретного приложения, например, главного меню веб-сайта.
Вы импортируете этот файл меньшего размера в основной файл меньшего размера, где ваши базовые цвета определены как переменные.
Теперь, если вы используете эти базовые цвета в меньшем файле главного меню, они зависят от основного файла.
Если бы вы могли проверить существование переменных, вы могли бы вернуться к цветам, определенным модулем.
Вот пример того, как я представляю файл без меню:

@menu-base-color: white;
@menu-base-color: @base-color when (@base-color);
...or...
@menu-base-color: @base-color when isset(@base-color);

+1, у нас уже есть istext , isnumber с isdefined и isundefined очень поможет в создании тем с меньшими затратами.

Т.е. используйте value или userValue , если isdefined

Я часто сталкиваюсь с этой проблемой, когда пытаюсь установить соглашения о темах для семантического пользовательского интерфейса с помощью LESS.

+1 на этом - было бы действительно здорово.

+1 за это тоже для меня

Не так уж сложно добавить функцию is-defined (я ожидаю, что она появится в одном из первых плагинов, как только выйдет v2). Хотя, если честно, печально то, что те, кто хочет эту функцию, действительно упускают из виду тот факт, что оба приведенных выше варианта использования решаемы (во многих случаях даже с более компактным кодом) без какой-либо подобной функции.

Вариант использования @InitArt :

// library.less
<strong i="9">@variable</strong>: false;

a when (@variable) {
    color: red;
}

// ......................................
// user.less
<strong i="10">@import</strong> "library.less"
<strong i="11">@variable</strong>: true;

Вариант использования @nemesis13 :

// library.less
@base-color: green;
@menu-base-color: @base-color;

.menu {
    background-color: @menu-base-color;
}

// ......................................
// user.less
<strong i="16">@import</strong> "library.less"
@base-color: white;
// or:
@menu-base-color: black;
// or whatever...

То есть в итоге: вместо проверки того, определена ли переменная, просто укажите значение по умолчанию для этой переменной, поскольку значения переменных можно свободно переопределять.

Может ли кто-нибудь ответить, почему пример Макса им не подходит? я могу только
предположим, это потому, что вы не знаете, определена ли переменная выше или
ниже импорта? Или что-то еще?
Мы не будем рассматривать то, что не имеет вариантов использования.
Недостатком этого является то, что люди, вводящие переменную с ошибкой, не увидят
ошибка. Мы могли бы обойти это с помощью предупреждения, но тогда, если вы сделали это на
цель, которую вы не хотели бы предупреждать .. это моя единственная проблема с этим
предложение.

Это особенно полезно при определении тем, чтобы уменьшить размер результирующего CSS. При создании тем в целом хотелось бы разрешить установку множества свойств. Однако пользователи могут захотеть установить только некоторые из них, оставив остальные свойства неустановленными. Конечно, установка их на значения по умолчанию в целом будет работать, однако это раздует окончательный CSS.

Рассмотрим следующую базовую тему (шаблон):

.my-class {
    color: @text-color;
    background-color: @background-color;
    border-color: @border-color;
}

Пользователь темы может захотеть установить только цвет текста, оставив остальные свойства неустановленными. Конечно, можно установить значения «начальный», «прозрачный», «наследовать» и т. д., однако это увеличивает размер окончательного CSS. Темы, как правило, имеют сотни таких свойств, поэтому размер может значительно увеличиться.

@JechoJekov

Я думаю, что вы упускаете смысл этого запроса функции, обратите внимание, что для вашего варианта использования вам все равно нужно будет установить защиту для каждого из этих свойств (следовательно, обоснование, которое я предложил двумя постами выше, все еще применимо). Поэтому я не думаю, что ваш вариант использования добавляет что-то новое в # 1400 (в основном это выглядит так, как будто вы предлагаете другую функцию, такую ​​​​как «пропустить свойство, если все его значения установлены с неопределенными переменными» или что-то в этом роде, но это другое большая история).

@семь фаз-макс

Возможно, было бы лучше, если бы можно было установить для переменной «неопределенное» или «неустановленное» значение. Установка для свойства такого значения будет означать, что свойство не отображается в окончательном CSS. Это упрощает синтаксис и позволяет проверить, объявлена ​​ли переменная.

@JechoJekov

Возможно, было бы лучше, если бы можно было установить для переменной «неопределенное» или «неустановленное» значение.

Как я уже упоминал, это еще одна функция, для которой нужен отдельный тикет (со своим обсуждением).

Просто небольшое уточнение для дорожной карты: это помечено как «ReadyForImplementation», но, похоже, в этой теме нет консенсуса, и похоже, что @seven-phases-max предложил достойную альтернативу. @lukeapage @seven-phases-max, нужно ли удалить готовый к реализации?

@matthew-dean Понятия не имею. Я полагаю, здесь «ReadyForImplementation» все еще действует, что означает что-то вроде «эта функция кажется не очень необходимой, но если кто-то придумает PR, реализующий такую ​​​​вещь, сопротивления не будет» или что-то вроде :)

Как это? (на рассмотрении)

Для меня «Готово к реализации» означает, что существует общий (но не обязательно единодушный) консенсус в отношении того, что это _должно_ быть рассмотрено или реализовано. Я думаю, что "На рассмотрении" соответствует вашему определению.

Все еще сталкиваюсь с этой проблемой при использовании области видимости

<strong i="6">@foo</strong>: 'bar';
& { 
  // not sure if <strong i="7">@foo</strong> is defined
}

Хотелось бы иметь возможность использовать isDefined

Хотя что-то вроде is-defined имеет смысл (как синтаксический сахар), на самом деле это не требуется. Просто _всегда_ определяйте @foo (с любым значением по умолчанию, которое вам нужно), в конце концов, если вы используете переменную в своих стилях - вы _можете_ предсказать, что вам нужно ее определить, например:

// in a far far away galaxy of your library default variables:
<strong i="8">@foo</strong>: undefined;

// the code where you need it
& when not(<strong i="9">@foo</strong> = undefined) { 
    // <strong i="10">@foo</strong> is defined by user    
}

// some user code
<strong i="11">@foo</strong>: bar;

Хотя, я думаю, я уже написал это в примерах выше (я просто пытаюсь озвучить тот факт, что отсутствие этой функции не может быть препятствием для чего-либо. Если вы знаете какой-либо вариант использования, где это один, пожалуйста, поделитесь).

Я пытаюсь настроить превью тем в браузере.

Это означает, что я должен использовать less.js и перезаписать переменную по умолчанию @theme настройками времени выполнения.

Ала

window.less.modifyVars({
  theme: 'someOtherValue'
})

В моем LESS я импортирую глобальный файл theme.less , который включает

<strong i="14">@theme</strong>: undefined;

.setTheme {
  <strong i="15">@theme</strong> : 'default';
}
.setTheme;

Я также пробовал просто

<strong i="19">@theme</strong>: 'default';

В первом случае выводимое значение равно undefined , во втором случае оно всегда равно default независимо от того, что установлено в modifyVars

Щелкните раскрывающийся список тем здесь, чтобы посмотреть пример.

Текущий обходной путь (который находится на действующем сайте) заключается в том, чтобы вручную захватить путь импорта переменной и проанализировать его с помощью регулярного выражения, а затем импортировать все эти переменные с помощью modifyVars , как вы можете догадаться , это довольно грязно.

@ Seven-phases-max Я сузил его до очень конкретного тестового примера, в котором @import вызывает проблемы.

В обоих случаях предположим:

Javascript

window.less.modifyVars({
  theme: 'changedValue'
});

В первом случае в theme.less для outer правильно установлено значение changedValue

компонент.less

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

тема.less

<strong i="22">@theme</strong>: 'default';
.outer {
  value: @theme; // value is set to changedValue
}

В этом неудачном случае в theme.less @theme установлено значение default , а не changedValue

компонент.less

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

тема.less

<strong i="37">@theme</strong>: 'default';
<strong i="38">@import</strong> "@{theme}"; // theme is set to default not changedValue

В случае «var in mixin» сниппет превращается в:

// defaults:
.setTheme {
   <strong i="6">@theme</strong>: undefined;
}

// custom:
.setTheme {
  <strong i="7">@theme</strong>: 'default';
}
.setTheme;

Хотя для modifyVars это всегда должно давать 'someOtherValue' для любого фрагмента, который вы пробовали (поскольку modifyVars работает, просто добавляя простую строку <strong i="14">@theme</strong>: 'someOtherValue'; прямо в конце скомпилированного исходный код). Так что, если modifyVars не работает, проблема, скорее всего, в другом месте.
Я просмотрел код страницы button , но он слишком сложен, чтобы быстро сказать, что может быть не так. На первый взгляд я не вижу (или, может быть, просто не могу понять), как код Less перекомпилируется и результирующий CSS повторно применяется после modifyVars (в простых фрагментах это делается через less.refreshStyles после modifyVars ).


Кстати, на всякий случай, вы уверены, что не планируете использовать is-default как что-то вроде:

.setTheme when not(is-defined(@theme)) {
  <strong i="26">@theme</strong>: 'default';
}
.setTheme;

? Если это так, проблема в том, что такой код будет напрямую нарушать принцип ленивых вычислений ( is-defined должен возвращать false, если переменная не определена, но поскольку она _будет_ определена в этой области видимости, , is-defined также имеет для возврата true -> неразрешимая рекурсия (подробнее о том, почему условные императивные переопределения нельзя безопасно разрешить в Less, см. # 2072).
Т.е. на самом деле это могло бы работать так, как ожидалось (если только is-defined не закодировано для явного обнаружения и выхода из такой рекурсии), но только как своего рода неопределенное/неопределенное поведение, без согласованности с нормальными правилами видимости переменных, что создает даже больше беспорядка.

@jlukic

<strong i="8">@theme</strong>: 'default';
<strong i="9">@import</strong> "@{theme}"; // theme is set to default not changedValue

Да, это тоже было одним из моих подозрений (к сожалению, я не могу проверить это прямо сейчас, и я не могу догадаться, как это могло произойти, но да, это возможно, потому что использование переменных в импортах является настоящей черной магией. Я создам специальный отчет о проблеме, если это проблема).

Я почти уверен, что это как-то связано с той чудесной черной магией.

Я работал с очень простыми файлами less для отладки, однако у меня еще не было возможности создать тестовый репозиторий.

В моих тестах сбой связан с использованием значений {@variable} в импорте, но не в свойствах css.

Действительно наслаждаюсь созданием тем с меньшими затратами, хотелось бы решить эти проблемы. Вот забавный пример темы с LESS , который я только что продемонстрировал в Meteor DevShop на прошлой неделе (щелкните значок ведра с краской в ​​правом верхнем углу)

@jlukic Я проверил это, и modifyVars работает для vars в импорте, как и ожидалось, как с lessc , так и с less.js (см . демо codepen , там немного сложный код, так как он должен был импортировать из основного страшного URL-адреса, но я полагаю, что он равен тому, что должны выполнять ваши страницы ... Так что на самом деле кажется, что проблема в другом).

Спасибо, что нашли время подготовить для меня тестовый пример. Это довольно четко. Я не уверен, что со мной происходит.. Мне придется расследовать

Было ли какое-то движение по этому запросу? Я уже некоторое время беспокоюсь о проверке неопределенной переменной. На данный момент у меня есть работа, которая далека от идеала...

p {
  & when not (@body-text-color = null) {
    color: @body-text-color;
  }
}

но для того, чтобы это работало, переменная должна существовать и быть определена как null по умолчанию. Это было бы гораздо более эффективным/гибким, если бы я мог просто проверить, существует ли переменная вообще.

+1

Таким образом, для реализации функции is-defined(name) (и/или get-value-of(var-name, fallback-value-if-not-defined) ) в плагине требуется менее 15 строк кода. Так что просто сделайте это, если вы достаточно смелы.

+1 к этому. Есть ли прогресс в этом как над плагином? Я имею в виду, что @seven-phases-max вы знаете код лучше, чем большинство участников, я думаю. Если для этого требуется около 15 строк кода, почему это еще не сделано?

Если для этого требуется около 15 строк кода, почему это еще не сделано?

Потому что никому это не интересно? Каждая функция крута и «чрезвычайно полезна», когда кто-то другой делает это за вас... Но это волшебным образом становится не таким важным, когда речь идет о вашем личном времени ;)

вы лучше знаете код, чем большинство участников

Это не означает, что я должен ставить что-то, что представляет мой собственный интерес, после того, что представляет интерес для кого-то еще, извините (особенно если это что-то поощряющее то, что я лично рассматриваю как неправильное использование/стиль плохого кода).

Чтобы не казаться пустым, для варианта использования @ashenden : вот правильный способ сделать любой из ваших наборов правил настраиваемым с помощью «неизвестных» (очевидно, предполагая случай, когда обычное переопределение CSS по какой-то причине неприменимо) без ошибочных идея «вслепую переместить-каждое-значение-CSS-в-переменную-плюс-использовать-что-то-что-вы-не-используете» (я не буду вдаваться в подробности, почему это на самом деле не работает, поскольку это история для длинный пост в блоге).

Есть понятие, обычно называемое "крючки", поэтому следующий "фестиваль не могу решиться":

// .............................................
// base code:

p {
    & when not (is-defined(@body-text-color)) {
        color: @body-text-color;
    }
    & when not (is-defined(@body-text-color)) {
        background-color: @body-back-color;
    }
}

span {
    & when not (is-defined(@body-text-color)) {
        color: @body-text-color;
    }
    & when not (is-defined(@body-text-color)) {
        background-color: @body-back-color;
    }
}

// .............................................
// customization:

@body-back-color: blue; // how about gradient?

следует заменить на:

// .............................................
// base code:

p {
    .body-text();
    .body-back();
    // ^ it's actually better to group all this into a singe entity, e.g. .p()
    // so that as you don't know WHAT or HOW to be customized
    // you don't pre-enforce any limitations and/or hardcoded approach
    // for something YOU do not even write
}

span {
    .body-text();
    .body-back();
}

.body-text() {}
.body-back() {}

// .............................................
// customization:

.body-back() {background-color: blue}

Считайте линии, считайте возможности, считайте ограничения.
Т.е. действительно, если вы не используете некоторые свойства CSS, просто оставьте их в покое для тех, кто будет .

Ребята, вот где я столкнулся с этим, пожалуйста, взгляните на этот пример и скажите мне, является ли это допустимым случаем и его нельзя исправить без is-undefined.

Я хочу загрузить темы в такой модуль библиотеки, как этот:

В моем основном приложении я определяю переменную @theme : 'желтый', а затем меньше импортирую библиотеку.

А вот как в этом случае могла бы выглядеть библиотека less:

@import 'темы/@{тема}';

тело {
фон: @primaryColor;
}

Таким образом, я мог бы иметь yellow.less и default.less с @primaryColor : yellow и @primaryColor : red.

В конце концов, я могу написать свою библиотеку, используя семантические имена переменных, такие как primaryColor, и предоставить набор тем с определенными этими переменными. И пользователь библиотеки просто определит имя темы в своем приложении и импортирует стили библиотеки.

Хорошо, неважно, похоже, я понял, мне просто нужен такой миксин для импорта:

<strong i="6">@theme</strong>: 'default';

.imports(@theme) when (<strong i="7">@theme</strong> = 'yellow') {
    <strong i="8">@import</strong> "themes/yellow";
}
.imports(@theme) when (<strong i="9">@theme</strong> = 'default') {
    <strong i="10">@import</strong> "themes/default";
}
.imports(@theme);

@waterplea Вы можете упростить свой код до:

<strong i="7">@theme</strong>: default;

.imports(yellow) {<strong i="8">@import</strong> "themes/yellow";}
.imports(default) {<strong i="9">@import</strong> "themes/default";}
.imports(@theme);

также обратите внимание на удаленные избыточные кавычки.

Хотя, если честно, я не вижу, <strong i="13">@theme</strong>: yellow; (+ весь код примесей) лучше, чем просто явная строка <strong i="15">@import</strong> "themes/yellow"; . Т.е. во-первых, вы в курсе переопределения ? Т.е. вам не нужно скрывать по умолчанию <strong i="18">@import</strong> "themes/default"; , если пользователю вашей библиотеки нужно применить материал yellow - она ​​просто импортирует вашу желтую тему ( в любом месте после вашего основного файла библиотеки, и опять же это одну и ту же строку) и вуаля — ваша библиотека использует значения переменных, указанные в желтом файле.

В итоге я получил необязательный импорт файла, который переопределяет тему или переключается на предустановленную тему. В проекте, который использует библиотеку, мы затем настраиваем веб-пакет для использования псевдонима этого файла в качестве модуля узла, если проекту нужна другая тема. То, что я написал раньше или то, что вы написали, не будет работать в нашем случае, поскольку мы создаем набор пользовательского интерфейса для Angular, и он очень модульный. Мы можем импортировать только одну кнопку или выбрать элемент управления, и он должен учитывать тему, которую мы используем, со всеми инкапсуляциями стилей. Решение легко настроить, поэтому я им доволен.

то, что вы написали, не сработает в нашем случае, поскольку мы создаем набор пользовательского интерфейса для Angular, и он очень модульный.

Я видел это бесконечное количество раз раньше - это одна из самых печальных проблем Less (неправильного) понимания - люди просто упускают из виду фундаментальный принцип Less lazy-evaluation и вместо того, чтобы использовать естественное переопределение Less, создают библиотеки с тяжелым внедрением файлов- основанные на шаблонах настройки, вдохновленных привычками языков с прямо противоположной семантикой переменных (таких как PHP, Sass и т. д.). Это должно быть что-то большее, чем просто какой-то парень, постоянно кричащий: «Ребята, вы делаете это неправильно!»

Я хотел бы понять это правильно, я не утверждаю, что все понимаю :) Хотите объяснить свое предложение на моем примере? Вот что мы получили:

Вот минимальный структурный пример:

Библиотека:

  • без импорта
    <strong i="10">@import</strong> 'theme-default';
    <strong i="13">@import</strong> 'mixins';
  • миксин.лесс
    some mixins here like resetting default browser button styles
  • тема-default.less
    <strong i="20">@primary</strong>: red;
    <strong i="23">@secondary</strong>: blue;
  • тема-secondary.less
    <strong i="27">@primary</strong>: green;
    <strong i="30">@secondary</strong>: yellow;
  • кнопкаКомпонент
    <strong i="34">@import</strong> 'import';
    .button { color: @primary; }

Проект 1 (необходимо использовать тему по умолчанию):

  • компонент
    <strong i="42">@import</strong> 'import';
    body { background: @secondary; }

Проект 2 (необходимо использовать дополнительную тему):

  • компонент
    <strong i="50">@import</strong> 'import';
    body { background: @secondary; }

Наша библиотека добавляется как модуль узла, и в проектах мы импортируем только компонент кнопки из библиотеки. Поскольку это модуль Angular для этой кнопки со своим собственным файлом less, он компилируется отдельно от остальной части проекта 1 или проекта 2.

Я думал об этом некоторое время, и я не мог придумать способ организовать меньше файлов, чтобы разрешить Project 1 или Project 2 устанавливать, какой файл темы использовать при компиляции как компонентов, так и собственного кода проектов. Я не вижу способа переопределить стили для компонента кнопки из кода проекта.

Поэтому вместо этого, в основном, вот как я написал import.less:
<strong i="58">@import</strong> 'theme-default';
<strong i="61">@import</strong> 'mixins';
<strong i="64">@import</strong> (optional) '~custom-theme';

И в проектах, если я хочу переопределить переменные темы как для кода проектов, так и для компонентов библиотеки, я называю этот файл модулем, используя webpack. Этот файл может иметь явное переопределение, скажем, @primary или просто переключение на дополнительную тему:
<strong i="69">@import</strong> '~myLibrary/styles/theme-secondary';

Итак, я знаю о переопределении, проблема в том, что пользователь библиотеки не может попасть между «где-либо после вашего основного файла библиотеки» и кодом компонента библиотеки. Я понимаю, что то, что вы говорите, будет работать для фреймворков без инкапсуляции стилей, но для Angular это либо не сработает, либо я что-то неправильно понял в вашем решении.

Понимаю. Тогда мы фактически говорим об одном и том же (только разными словами). Как только buttonComponent (или любой другой компонент) будет скомпилирован отдельно, "мастером настройки проекта" останется файл import.less , и вы сделали именно то, что я предложил. (в то время как Project 1 и Project 2 оказываются просто еще одним компонентом «что-то еще» (или «все в одном»?) того же уровня, что и buttonComponent , а не вполне себе "проекты").

Т.е. таким образом я бы сказал, что вы "сделали правильно" на мой вкус.

Эта проблема была автоматически помечена как устаревшая, поскольку в последнее время в ней не было активности. Он будет закрыт, если никакой дальнейшей активности не произойдет. Спасибо за ваш вклад.

@устаревший пинг.

Технически плагин, реализующий эту функцию, доступен с 2015 года . Но лично я никогда не проверял это, поэтому, пожалуйста, не вините меня, если что-то пойдет не так (это просто для вашего сведения).

Эта проблема была автоматически помечена как устаревшая, поскольку в последнее время в ней не было активности. Он будет закрыт, если никакой дальнейшей активности не произойдет. Спасибо за ваш вклад.

Итак... Я просмотрел эту ветку, и я не могу определить, в основном это случаи, когда люди неправильно понимают Меньше масштаба или нет.

Я действительно не вижу необходимости проверять, определены ли переменные. Вары должны быть определены, если они будут потребляться.

<strong i="7">@import</strong> "library";  // contains @library-color: blue;

@library-color: red;

.box {
  color: @library-color;
}

Я не понимаю необходимости условно устанавливать свойство на основе значения _change_. Если для свойства задана переменная, просто измените значение переменной.

То есть, если library.less имеет это:

@library-color: blue;
.box {
  color: @library-color;
}

Все, что нужно сделать кому-то, чтобы установить его вывод:

<strong i="16">@import</strong> "library";
@library-color: red;

Это выведет:

.box {
  color: red;
}

Понимают ли ОП и другие в этом потоке такое поведение?

Я думаю, что вариант использования «существует ли переменная» — хороший способ сделать флаги. То есть я не думаю, что существует концептуально прямолинейная «фальшивка». Или, скорее, необычно, что true является единственным «истинным» значением. Другими словами, я думаю, что это вопрос воспитания, а не поведения.

Я думаю, что нам следует подумать о закрытии этой проблемы, так как это обычно исправляется одной строкой, объявляющей значение переменной по умолчанию. Хотя Less v3.5 движется к более либеральной сделке, может быть, переменные внутри охранников оцениваются более либерально?

Но мой голос - нет. @the-variable: false; , кажется, все, что нужно добавить OP.


Всем, у кого есть вопросы о том, как решить конкретную проблему, которая, по их мнению, связана с этим, не стесняйтесь публиковать сообщения на сайте less gitter и @me.

Хорошо, закрытие, спасибо @calvinjuarez.

Что также произошло с тех пор, как это было открыто, так это функция if() . Так что вы можете сделать color: if((@variable), green, red);

@matthew-dean Большое спасибо, что написали этот совет. Я видел добавление if() в примечаниях к выпуску 3.0, но не упомянул об этой проблеме, для которой у меня был уникальный случай (но не время для создания сокращенной версии). Опять же, очень ценю. Молодцы, команда LESS.

@kbav Нет проблем! Еще один совет вдобавок к этому совету: когда if() был впервые введен, он требовал скобок вокруг условий, потому что он фактически «встраивал» блокировку when (например, часть после when в when (@variable) ). Однако это было исправлено в Less 3.6, поэтому приведенный выше пример можно написать без круглых скобок (при компиляции с последней версией):

color: if(<strong i="10">@variable</strong>, green, red);
Была ли эта страница полезной?
0 / 5 - 0 рейтинги