Skip to content
New issue

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

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Variable property #36

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

Variable property #36

gjunge opened this issue Jun 16, 2010 · 47 comments

Comments

@gjunge
Copy link

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

@cloudhead
Copy link
Member

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.

@jamesfoster
Copy link
Contributor

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
Copy link
Author

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

@cloudhead
Copy link
Member

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.

@jamesfoster
Copy link
Contributor

:)

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.

@cloudhead
Copy link
Member

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
Copy link
Author

gjunge commented Jun 19, 2010

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

@dylan
Copy link

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. :\

@jamesfoster
Copy link
Contributor

How would you prefer to use it?

@dylan
Copy link

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
Copy link

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

@cloudhead
Copy link
Member

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

@dylan
Copy link

dylan commented Jul 8, 2010

@dancrew32
Copy link

@dylan
Copy link

dylan commented Mar 11, 2011

nice!

@metaskills
Copy link

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;

@metaskills
Copy link

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

@Heilemann
Copy link

@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.

@SomMeri
Copy link
Member

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.

@lukeapage
Copy link
Member

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.

@SomMeri
Copy link
Member

SomMeri commented Dec 14, 2012

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

@SomMeri
Copy link
Member

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.

@SomMeri
Copy link
Member

SomMeri commented Dec 15, 2012

Thank you again, I should have seen that solution.

@demoive
Copy link

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.

@extemporalgenome
Copy link
Contributor

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

@lukeapage
Copy link
Member

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

@extemporalgenome
Copy link
Contributor

@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).

@lukeapage
Copy link
Member

@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?

@extemporalgenome
Copy link
Contributor

@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.

@ghost
Copy link

ghost commented Jun 29, 2013

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

@matthew-dean
Copy link
Member

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

@ghost
Copy link

ghost commented Jun 29, 2013

@matthew-dean Excellent, any idea when?

@Soviut
Copy link

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.

@jonschlinkert
Copy link
Contributor

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?

@ghost
Copy link

ghost commented Jun 29, 2013

@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
Copy link

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.

@ghost
Copy link

ghost 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.

@TedDriggs
Copy link

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
Copy link

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.

@cloudhead
Copy link
Member

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.

@jonschlinkert
Copy link
Contributor

👍

@Soviut
Copy link

Soviut commented Aug 16, 2013

👍 agreed

@ghost
Copy link

ghost commented Aug 16, 2013

👍

@seven-phases-max
Copy link
Member

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
Copy link

cwygoda commented Dec 14, 2013

👍

@lukeapage
Copy link
Member

In 1.6.0

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

Successfully merging a pull request may close this issue.