Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

Already on GitHub? Sign in to your account

Variable property #36

Closed
gjunge opened this Issue Jun 16, 2010 · 47 comments

Comments

Projects
None yet

gjunge commented Jun 16, 2010

See: http://groups.google.com/group/dotless/browse_thread/thread/9d580e75248b3250

Hi,

SHORT VERSION:
Is the following doable:
.bla {
padding-@variable: 5px; //where @variable could be left, right, top, bottom.
}

INTRO:
I'm working on a website that supports both LTR and RTL. So far I made
two stylesheets, one for LTR and one for RTL. The RTL stylesheet
imports the LTR stylesheet and "overrides" those items that are RTL
specific. (padding-right vs padding-left etc).

float: right/left I manage by having a variable called @SIDE (and
@side-opposite) and setting it to the correct side in both stylesheets
(in RTL it is "right", and in LTR it is "left"). In my LTR stylesheet
I write : float : @SIDE

That was the intro....

QUESTION:
I would also like to eliminate the "overriding" issue, to keep my code
more DRY.

The ultimate thing would be if I could make the property variable:

.bla {
padding-@SIDE: 20px;
}

Can this be done?

Thanks a lot.
Gidon

Owner

cloudhead commented Jun 16, 2010

Hey, you can do that with pattern matching, let me illustrate:

.blah ()       { color: black }                     // All blahs
.blah(right)  { padding-right: 20px }          // Right blahs
.blah(left)    { padding-left: 20px }           // Left blahs

@side: left;
.class { .blah(@side) }

Output

.class { color: black; padding-left: 20px;}

So in essence, you can match an arbitrary mixin depending on a variable, instead of creating an arbitrary property name.

Contributor

jamesfoster commented Jun 17, 2010

Gidon, this is in dotless so you could use it as cloudhead suggests.

One issue with this it takes a lot of setting up. instead of potentially having 4 mixins, one each for padding-top, -left, -bottom and -right. you would just have 1.

as an aside. I like the sass sub property syntax...

.class {
  padding: {
    top: 10px;
    left: 20px;
    bottom: 30px;
    right: 40px;
  }
}

this outputs as the usual padding-top: 10px;

perhaps it would be possible to store that in a variable?

@left: 1;
@right: 0;

@mypadding: {
    left: 20px * @left;
    right: 20px * @right;
  }

.class {
  padding: @mypadding;
}

(I'm just thinking out loud, it's probably not very elegant but looks interesting.)

gjunge commented Jun 18, 2010

Looks also nice, though it doesn't look very "lessy", does it?

LESS also doesn't support conditions, or does it?
Because that would also solve it:

.mypadding {
[if @direction="ltr"]
padding-left : 20px;
[else]
padding-right: 20px;
[endif]
}

Owner

cloudhead commented Jun 18, 2010

the best solution is the one I proposed imo. Cascading stylesheets shouldn't have logic in them, so if/then/else is not an option.

Contributor

jamesfoster commented Jun 18, 2010

:)

I love it when people say things like that.

surely, when i write .blah(right) there is logic which determines which mixin to mixin!

there is logic in less. It just doesn't feel like logic because it doesn't include the word "if".

i still like the #{} idea from sass, I just think implementing it would be a nightmare.

Owner

cloudhead commented Jun 18, 2010

there's logic in the implementation of course, but not in the stylesheet. It's declarative. Yea, attribute interpolation is powerful, but I don't think we need it.

gjunge commented Jun 19, 2010

Yep, I got your point. I can work with the solution provided in less.js

dylan commented Jul 8, 2010

How would you recommend doing a CSS3 mixin? right now I can do this:
.transition-property(e("box-shadow, top"));
.transition-property(@attr) {
transition-property: @attr;
-webkit-transition-property: e(%("-webkit-%d", @attr));
-o-transition-property: e(%("-o-%d", @attr));
-moz-transition-property: e(%("-moz-%d", @attr));
}

But that only allows for one cross-browser compatible call per selector. :\

Contributor

jamesfoster commented Jul 8, 2010

How would you prefer to use it?

dylan commented Jul 8, 2010

I am not entirely sure what an elegant way would be to pull this off, not without iterating through arguments and having logic of some sort to modify the strings. :P As it stands there are only a few properties that you would need to do for this sort of thing, but I am spoiled and dont want to do them all by hand. :P

dylan commented Jul 8, 2010

Gradients are another thing that logic would help with generation. Especially considering the differences in browser syntax at the moment. Right now I have to make different gradient mixins, ones that accept 3 arguments, and ones that accept 2. :D

Owner

cloudhead commented Jul 8, 2010

Hmm, could you show me the desired CSS output, maybe in a Gist, and I'll see if I can think of anything.

dylan commented Mar 11, 2011

nice!

First, I would like to thank @cloudhead for his awesome work. Being an open source author, I know how thankless it can feel sometimes. Specific to this project, I have worked on two ruby gems less-rails and less-rails-bootstrap to help promote LESS CSS. Both of these gems build on top of @cowboyd's wonderful less.rb. With that out of the way, about this issue.

I think it is important to note that there are always going to be "workarounds". Hell, we can just write raw CSS right? Some of the workarounds I have seen may be pragmatic for some but fail to address the core concern. To me this ticket's subject says it all. It would be really nice to have variable or string substitution for CSS properties, not just their values. I can provide my own use case for said feature and I simply ask you do not turn my contrived code examples around with said workarounds that debase this feature request.

Given that I may have my CSS setup like this, imagine that my color pallet has around 24 colors. I would like to (1) create a mixin that helps define descendant selectors on a given CSS property. In my case I have the contrived background-color as an argument. But in actuality I would use this as to help me define descendant color selects for almost anything, like font-color etc. So this code.

@myWhite: rgb(240,240,240);
@myGray:  rgb(140,140,140);
@myBlack: rgb(30,30,30);

.myColorClasses(@property) {
  &.white   { @property: @myWhite !important; }
  &.gray    { @property: @myGray  !important; }
  &.black   { @property: @myBlack !important; }
}

.box {
  .myColorClasses("background-color");
}

Could possibly generate this CSS.

.box.white {
  background-color: #f0f0f0 !important;
}
.box.gray {
  background-color: #8c8c8c !important;
}
.box.black {
  background-color: #1e1e1e !important;
}

The list of the usages of this would be numerous and allow a form of meta prgramming within the LESS CSS framework. I understand that @cloudhead is a busy person and that being a good OSS participant, I should generate a patch which would hopefully include tests. To that end, can I get some feedback on my comments, accepted syntax, comments on if this may be possible, where might I head in the code, etc?

Thoughts on accepted syntax?

//  @property: @myWhite !important;
//  @{property}: @myWhite !important;
//  "@{property}": @myWhite !important;
//  ~'@{property}': @myWhite !important;
//  ~"@{property}": @myWhite !important;
//  ~`'@{property}'`: @myWhite !important;

Am I to understand that 93b23d2 is the closer for this issue?

@metaskills As I understand it, that trick only works for selectors, not for properties (at least I can't make it work).

My problem is that I'm building a grid generator, which uses the same calculation for push, pull and column width, but because I can't give it a property as a parameter, I have to have three different mix-ins for the exact same thing. And further more, if I wanted to fork out my IE hack from that, I'd have to put that in three further mix-ins. That's six vs. two.

Owner

SomMeri commented Dec 14, 2012

Just a through: Since selectors already accept (~"escaped selector") escaping, what about using the same syntax for properties or declarations? It could be used also to add various browser hacks without having them in less syntax.

Used for whole declaration:

.selector {
   (~"some-property-hack: value");
 }

Used only for property:

(~"escaped selector") {
   (~"some-property-hack"): value;
}

Values use different escape syntax ~"escaped value". That one could be used too, but I assumed that there was some reason why selectors use parentheses and that reason may apply here too.

Owner

lukeapage commented Dec 14, 2012

have a look at #698

some property hacks are already supported and there is an argument that because some prefixing requires different values, having a generic prefix mixin has limited use.

Since it adds limited value, I'm not sure on the future of this feature request.

also note that the syntax above is being deprecated and replaced by @{variable} directly in the selector.

Owner

SomMeri commented Dec 14, 2012

Thank you, I did not knew that (~"something") is deprecated nor that @{variable} in selector works.

Owner

SomMeri commented Dec 14, 2012

Deprecated means "will be removed from 1.4"?

It seems like the new @{variable} is not fully equivalent to the old (~"@{variable}"). The same code with different syntaxes produces different results.

Input:

 @a: ".something";
 // mixin uses the old syntax
 .oldSyntax () {
   (~"@{a}") { 
     padding: 2 2 2 2;
   } 
 }

 // mixin uses the new syntax
 .newSyntax () {
   @{a} { 
     padding: 2 2 2 2;
   } 
 }

 // use both mixins
 #usePlace {
   .oldSyntax();
   .newSyntax();
 }

Output:

#usePlace .something {
  padding: 2 2 2 2;
}
#usePlace ".something" {
   padding: 2 2 2 2;
}

New syntax generates additional quotes around the value. However, it is impossible to assign the .something value to the variable, because @a: .something; causes syntax error.

Is this ok? It looks suspicious, but I do not want to open a new issue for "as intended" behavior nor for bugs in deprecated features.

Owner

lukeapage commented Dec 15, 2012

Assign .selector to the variable by adding ~ to the variable definition ...
If I remove quotes then you wouldn't be able to use variables to insert
quotes.

Owner

SomMeri commented Dec 15, 2012

Thank you again, I should have seen that solution.

demoive commented May 26, 2013

I like @metaskills proposal, and I would like to share the simple solution I created and that I am using while variable interpolation isn't supported. I call it vendorify.less and it has already been submitted as a solution to issue 698. @cloudhead, see the comments below the Gist for more information, test cases and sample output.

Contributor

extemporalgenome commented Jun 13, 2013

The primary usefulness of this isn't to solve problems that otherwise can't be solved, but to (sometimes drastically) reduce the amount of coding needed to do similar tasks. For example:

.prefixer(@prop, @vals...) {
    -moz-@prop: @vals;
    -webkit-@prop: @vals;
    @prop: @vals;
}
.radius(all, @vals...)    { .prefixer(border-radius, @vals); }
.radius(@side, @vals...)  { .prefixer(border-@{side}-radius, @vals); }

.radius(top, @vals...)    { .radius(top-left, @vals);    .radius(top-right, @vals); }
.radius(right, @vals...)  { .radius(top-right, @vals);   .radius(bottom-right, @vals); }
.radius(bottom, @vals...) { .radius(bottom-left, @vals); .radius(bottom-right, @vals); }
.radius(left, @vals...)   { .radius(top-left, @vals);    .radius(bottom-left, @vals); }
Owner

lukeapage commented Jun 14, 2013

@extemporalgenome another example using prefixes. We have other issues attempting to make prefixes easier, but also prefixes are in the long term going away

Contributor

extemporalgenome commented Jun 14, 2013

@lukeapage true enough, though the above example would still get some usefulness out of this hypothetical feature, even without prefixes, not to mention it's a consistency issue (considering that unquoted interpolation works in mixin names but not attribute names).

Owner

lukeapage commented Jun 14, 2013

@extemporalgenome

(considering that unquoted interpolation works in mixin names but not attribute names)

thats a different issue and happens to be fixed in 1.4.0

though the above example would still get some usefulness out of this hypothetical feature, even without prefixes

what use is that?

Contributor

extemporalgenome commented Jun 14, 2013

@lukeapage regarding the fix for that, running lessc on the commit titled "1.4.0 release" with the following input:

div {
    @name: left;
    border-@{name}-width: 1px;
}

I still get an "ParseError: Unrecognised input" error.

Usefulness-wise, attribute variable interpolation can be used to make attribute values (and patterns/groups of attributes) reusable. For example, padding, margins, border widths, etc. have identical value grammars in CSS, yet without this kind of interpolation, separate mixins sets would be needed for each attribute type, as opposed to a single set of generic mixins.

Is this really still not possible? Why the resistance for an obvious piece of functionality?

Owner

matthew-dean commented Jun 29, 2013

@thelucid This feature is being added. There is no longer any resistance to it. :-)

@matthew-dean Excellent, any idea when?

Soviut commented Jun 29, 2013

Probably when 1.5 comes out and no, there is no definitive timeline for that.

There has never been any resistance to this feature, only discussion. Being a library that others rely upon, the developers have be very sure-footed and as forward-looking as possible when they make implementation decisions.

Contributor

jonschlinkert commented Jun 29, 2013

Agreed with @matthew-dean, there isn't resistance to it, but there is limited time. I don't recall seeing @lukeapage mention this as being planned for 1.5, he's super busy atm. @thelucid are you interested in implementing the code for this?

@jonschlinkert Possibly, I'm not completely familiar with the code but will take a look over the next couple of weeks. I though I recalled seeing a pull request back-along that was refused as @cloudhead didn't want it, I may be wrong.

Soviut commented Jun 29, 2013

Link the pull request if you can. I'm sure if it was rejected that there was a good reason for it.

thelucid commented Jul 5, 2013

@Soviut I can't find the pull request I was thinking of but this is similar: #698

Also this comment suggests that @cloudhead doesn't see the need: #36 (comment) ...I understand not wanting to include too much conditional stuff but I see variable properties as quite an elegant solution and necessary for things like rem mixins.

For the specific case of bidirectional sites, I'd like to suggest a more-scoped alternative: Create near and far and replace them with left/right as appropriate. That way your stylesheets remain concise and logic-free, and now actually do a better job of being directionally agnostic.

Soviut commented Aug 16, 2013

@TedDriggs what are you referring to? This is a discussion about allowing attributes/properties to have variables in their names. Any references to "left" or "right" are just examples one might use for wanting to add left float and left margin using a mixin.

Owner

cloudhead commented Aug 16, 2013

Given that we've introduced variable interpolation in selectors since then, I'd say it's OK (if not expected) to have it in property names too now.

Contributor

jonschlinkert commented Aug 16, 2013

👍

Soviut commented Aug 16, 2013

👍 agreed

👍

Owner

seven-phases-max commented Oct 14, 2013

Above. I did not create a pull-request to the master repo yet as I guess it would probably be too dramatic change for 1.5.0-beta at the last moment.

cwygoda commented Dec 14, 2013

👍

Owner

lukeapage commented Feb 13, 2014

In 1.6.0

@lukeapage lukeapage closed this Feb 13, 2014

@Booster2ooo Booster2ooo referenced this issue in dotless/dotless Dec 9, 2016

Open

Variables in property names #517

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment