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

@import (important) for higher "specificity" variables #2590

Closed
calvinjuarez opened this issue May 21, 2015 · 11 comments
Closed

@import (important) for higher "specificity" variables #2590

calvinjuarez opened this issue May 21, 2015 · 11 comments

Comments

@calvinjuarez
Copy link
Member

I've thought recently about how theming and overriding would be so much easier if I could specify that my definitions are !important. That is,

// my.variables.less
@theme-var: value !important;

// 3rd-party-library.variables.less
@theme-var: default value;

// 3rd-party-library.core.less
.this {
  uses: @theme-var; // → `value`
}

In other words, !important would do for Less variables what it does for CSS properties: increase the "strength" of the declaration.

I realize this may cause headaches (!important in variables is already a question in #2374) but it seems like a super useful feature for a major use case for Less.

Edit:

Sorry, just noticed this is a duplicate of #1401 (I forgot to search closed issues). I'm gonna leave the issue open for the @import (important) suggestion (see below) since many of the objections brought up in 1401 don't really apply there. I'll change the issue title, for clarity.

@calvinjuarez calvinjuarez changed the title Variable priority control with !important Variable "specificity" control with !important May 21, 2015
@calvinjuarez
Copy link
Member Author

And while I'm spitballing,

@import 'my.variables.less' !important; // treats these variables as if they had `!important` on them.

// OR

@import (important) 'my.variables.less'; // behaves like `(reference)`, but with `!important` variables.
// or
@import (theme) 'my.variables.less'; // behaves like `(reference)`, but with `!important` variables.
// or
@import (override) 'my.variables.less'; // behaves like `(reference)`, but with `!important` variables.
// or
@import (strong-variables) 'my.variables.less'; // behaves like `(reference)`, but with `!important`
// or
@import (reference important) 'my.variables.less'; // allow two import options, maybe?

That way, you could just have a theme file with the override variables and ensure its importance in your master Less file (which would be good for readability).

This would let you organize your master file much more nicely:

//
// Main Stylesheet - style.less
//


// Totally untouched library master files (easy to update)
// ----------

@import 'libraries/a-library.less';
@import 'libraries/another.less';
// ... etc.


// Stuff I wrote
// ----------

// Themes
@import (theme) 'theme.a-library.less'; // these override variables defined in similar
@import (theme) 'theme.another.less';   // scopes in the library files above.
// ... etc.

// The rest of my stuff
@import 'the.less';
@import 'rest.less';
@import 'of.less';
@import 'my.less';
@import 'stuff.less';

@calvinjuarez calvinjuarez changed the title Variable "specificity" control with !important @import (important) for higher "specificity" variables May 21, 2015
@matthew-dean
Copy link
Member

I don't get this. In the last example, if the variables are defined in the same scopes (the way that we've defined namespaced vars), then the themes will override regardless.

@matthew-dean
Copy link
Member

However, !important seems like a useful concept in general. That said, like !important in CSS, the need could imply that there's a structural issue at play (but not that it's more easily solvable a different way).

@seven-phases-max
Copy link
Member

-1 (sorry too lazy to comment why).

@matthew-dean
Copy link
Member

-1 (sorry too lazy to comment why).

lol - I'm probably more on the minus side as well. It doesn't seem to add much value for the extra weight it adds to the engine/language.

@calvinjuarez
Copy link
Member Author

@matthew-dean

I don't get this. In the last example, if the variables are defined in the same scopes (the way that we've defined namespaced vars), then the themes will override regardless.

Let me show you that with Bootstrap

// Libraries
// ----------

@import 'libraries/bootstrap/bootstrap.less'; // note: includes BOTH variables & rules


// Stuff I wrote (everything below this is okay to edit)
// ----------

// Themes
@import (theme) 'house/theme.bootstrap.less'; // these override variables defined in similar

// The rest of my stuff
@import 'house/stuff.less';
//...

In other words, the Library import includes the whole library. Doing that now will compile bootstrap with it's defaults, since the theme doesn't get evaluated 'til later.

There obviously ways around this, but they're pretty verbose. If I want to keep a library clean (for easy updating), the best option I have is:

// Libraries
// ----------

// Core variables and mixins
@import 'libraries/bootstrap/variables.less';
@import 'house/theme.bootstrap.less'; // This gets lost and isn't how I want to group it
@import 'libraries/bootstrap/mixins.less';

// Reset and dependencies
@import 'libraries/bootstrap/normalize.less';
@import 'libraries/bootstrap/print.less';
@import 'libraries/bootstrap/glyphicons.less';

// Core CSS
@import 'libraries/bootstrap/scaffolding.less';
@import 'libraries/bootstrap/type.less';
@import 'libraries/bootstrap/code.less';
@import 'libraries/bootstrap/grid.less';
@import 'libraries/bootstrap/tables.less';
@import 'libraries/bootstrap/forms.less';
@import 'libraries/bootstrap/buttons.less';

// Components
@import 'libraries/bootstrap/component-animations.less';
@import 'libraries/bootstrap/dropdowns.less';
@import 'libraries/bootstrap/button-groups.less';
@import 'libraries/bootstrap/input-groups.less';
@import 'libraries/bootstrap/navs.less';
@import 'libraries/bootstrap/navbar.less';
@import 'libraries/bootstrap/breadcrumbs.less';
@import 'libraries/bootstrap/pagination.less';
@import 'libraries/bootstrap/pager.less';
@import 'libraries/bootstrap/labels.less';
@import 'libraries/bootstrap/badges.less';
@import 'libraries/bootstrap/jumbotron.less';
@import 'libraries/bootstrap/thumbnails.less';
@import 'libraries/bootstrap/alerts.less';
@import 'libraries/bootstrap/progress-bars.less';
@import 'libraries/bootstrap/media.less';
@import 'libraries/bootstrap/list-group.less';
@import 'libraries/bootstrap/panels.less';
@import 'libraries/bootstrap/responsive-embed.less';
@import 'libraries/bootstrap/wells.less';
@import 'libraries/bootstrap/close.less';

// Components w/ JavaScript
@import 'libraries/bootstrap/modals.less';
@import 'libraries/bootstrap/tooltip.less';
@import 'libraries/bootstrap/popovers.less';
@import 'libraries/bootstrap/carousel.less';

// Utility classes
@import 'libraries/bootstrap/utilities.less';
@import 'libraries/bootstrap/responsive-utilities.less';


// Stuff I wrote (everything below this is okay to edit)
// ----------

// Themes
@import (theme) 'house/theme.bootstrap.less'; // these override variables defined in similar

// The rest of my stuff
@import 'stuff.less';
//...

@calvinjuarez
Copy link
Member Author

Also, I agree that !important definitely smells, and I know "default variables" or "important variables" has been shot down repeatedly. I wonder, though, when a request is considered 'tenacious' enough to reconsider? (I also obviously feel like a semantic & specific @import (theme) 'file.less'; stinks a lot less than a repetitive, over-generic !important.)

Also, for tiny libraries (like 1pxdeep) there's little or no file abstraction, which (currently) means you're required to edit the downloaded files. And that stinks, too.

I really think this feature is one that deserves to be addressed. Libraries+Themes are a huge part of the Less community, and it seems a shame to ignore that.

At any rate, are there any plugins that answer this need? I just want my code to be more organized.

@matthew-dean
Copy link
Member

I know "default variables" or "important variables" has been shot down repeatedly. I wonder, though, when a request is considered 'tenacious' enough to reconsider?

It's not because Less contributors hate the idea. It's because the request is inevitably the result of not understanding how Less scoping / evaluation works, which is very different from Sass. In fact, your specific example was one I tripped up on. (See #1706 (comment) from Feb). It wasn't immediately obvious to me either, even though I've used the behavior of overriding variables in other ways. So, doing this works:


@import 'libraries/bootstrap/bootstrap.less'; // note: includes BOTH variables & rules
@import 'house/theme.bootstrap.less'; // this will just work, try it

// The rest of my stuff
@import 'house/stuff.less';

So using (theme) wouldn't matter. If the variables are in the same scope, the later ones will be evaluated before the step which generates the CSS. Is that what you were stuck on, or am I misunderstanding what you are saying?

@calvinjuarez
Copy link
Member Author

😳

Well I feel sheepish

I could've sworn I'd tried it once...that was years ago, now, though, when I was brand new to Less.

Anyway, I'm closing, since I'm just 100% dead wrong.

@matthew-dean
Copy link
Member

@calvinjuarez Don't be embarrassed. I've been on the core team for years, and I only figured this out (or embarrassed myself the same way until @seven-phases-max explained it) a few months ago. That could just mean that it's not immediately intuitive behavior. Although once you think through it and realize that CSS output is the very last step, which outputs based on the final value of each variable, then it makes sense. So it's easy to assume that CSS evaluation is happening at the same time (or in the same order) as variable declaration. But, well, it isn't. 😄

@matthew-dean
Copy link
Member

Even better than that, I've seen people who ship popular Bootstrap themes, or have written articles about extending Bootstrap, who all have gotten this wrong.

I'm planning on writing an article soon about what makes Less unique, and plan to cover this. Maybe I should call it: "Less, the World's Most Misunderstood CSS Preprocessor". * nods to Doug Crockford *

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

No branches or pull requests

3 participants