Less Mixin using variable in attribute selector - css

EDIT: The issue might be with a bug in dotless, which is what we're using.
I'm trying to write a Less Mixin method for writing out a lot of CSS styles. The general format of the method is:
.icon-styles(#name) {
.#{name}-icon {
background-image: url('../images/icon-#{name}.png');
display: none;
}
[data-#{name}="true"] .#{name}-icon {
display: inline-block;
}
}
Such that the icon is only visible if a containing object has the related attribute set.
However, I'm getting an error at the attribute selector saying:
Expected ']' but found '{'
Pointing to the # inside the square brackets.
I've found this post:
LESS mix variable into attribute name in an attribute selector expression
With a similar issue, and the answer suggests it might be a bug, but unfortunately the workaround doesn't work for me. I'm getting the same error on trying to write out attr inside the brackets.
I've also tried writing it like this:
[~'data-#{name}'="true"] .#{name}-icon {
Which gets rid of the error, but then #{name} is not resolved in the resulting css.
Does anyone know if there's any way to achieve what I want?

The trick is the same as suggested in LESS mix variable into attribute name in an attribute selector expression. You're just missing the main point of it: "concatenation of interpolated variables is not supported inside [attr] blocks", so you need to move out of it:
.icon-styles(#name) {
.#{name}-icon {
background-image: url('../images/icon-#{name}.png');
display: none;
}
#data-name: ~'data-#{name}';
[#{data-name}="true"] .#{name}-icon {
display: inline-block;
}
}

Related

How to make parent selector interpolated in the middle of nested selector in sass/scss

I'd like to get the result below using sass nesting
css
.box {...}
h3.box-title {...}
I tried code like this, but it causes an error.
sass
.box {
h3.&-title {
...
}
}
I'd like to know if there is any way to do this keeping sass nesting?
I know that it's not good to write HTML element on CSS,
but I'm working on a project that I can't modify existing CSS and need to overwrite them.
Try this:
.box {
#at-root h3#{&}-title {
...
}
}
I used the sass interpolation #{} to compile expectedly the value of &, and #at-root to prevent the prefix .box (prevent resulting to .box h3.box-title because we want h3.box-title only - without the prefix .box)
Here's the captured result:
Anyway, I don't think this is a good practice to write sass/scss
.box
and
.box-title
are two different class names. Unless h3.box-title is a child of .box, honestly, there's no reason you should be nesting it.
Also & is used to look for additional class names. i.e.
.box {
&.box-title {}
}
would be
.box.box-title {}

What is the use of parent selector (&) alone as a selector? Is it bad practice to use such selectors?

After reading tutorial after tutorial regarding Less (LessCSS), I was just wondering how this & operator is supposed to be used. I know it's referring the parent element like:
div {
&.fullheight {
height: 100%;
}
}
// turns into
div.fullheight {
height: 100%;
}
But I often saw this:
div {
span {
& {
padding: 1em;
margin: 1em;
}
}
}
// turns into
div span {
padding: 1em;
margin: 1em;
}
Like when using ONLY the & operator inside of a class, it represents pretty much the parent element, but is doing this bad practise since you can have the same result when you would type like this:
div {
span {
padding: 1em;
margin: 1em;
}
}
Both work, so is it bad/good practise or are each of them maybe used in different situations?
For extra clarity, below is the link to an answer where I first saw that you can write & only in a class without anything else.
LESSCSS - use calculation and return value - First post by ScottS, fourth solution in his post.
Generally writing something like below would be considered as bad practice because the & there is just redundant and does no value add at all. It just outputs the entire parent selector div span.
div {
span {
& {
padding: 1em;
margin: 1em;
}
}
}
So, you should avoid writing such selectors which use only the & (parent selector).
The other example to which you have linked is an interesting case which I would term as an educated hack to get around the variable scoping and lazy loading concepts in Less.
Assume that the same code was written without the parent selectors (like below).
#unit:em;
#basevalue:1;
#val: 1;
#setUnit: unit(#basevalue*#val, #unit);
.someAwesomeClass {
#val: .2;
padding: #setUnit;
#val: .1;
margin: #setUnit;
}
Here the #val variable is declared twice within the same block. Since Less does lazy loading of the variables, they need not be declared before being used (and) if the same variable is declared twice or more within the same scope, the last declaration would win.
When defining a variable twice, the last definition of the variable is used, searching from the current scope upwards. This is similar to CSS itself where the last property inside a definition is used to determine the value.
So, the compiled CSS output would have the value as 0.1em for both padding and margin whereas the expectation is for padding to be 0.2em and for margin to be 0.1em.
To overcome this, the author of that answer has introduced two namespaces (with no name) and has thus restricted the scoping issue. The variable defined within each nested block becomes local to that block only and so will be considered as two separate variables.
#unit:em;
#basevalue:1;
#val: 1;
#setUnit: unit(#basevalue*#val, #unit);
.someAwesomeClass {
&{
#val: .2; /* this declaration applies only within this nest */
padding: #setUnit;
}
&{
#val: .1; /* this declaration applies only within this nest */
margin: #setUnit;
}
}
As indicated by the author of that answer (in the first line), it was a workaround because there was no way to create a true function with Less.
But starting with Less v2, we can define our own custom functions in Less and use them as described in this answer by Bass Jobsen. The ability to write such custom functions should eliminate the need to write such hacks.
You can also refer to the comment by seven-phases-max in the same thread for a solution without the need for such hacks.
Bottomline is that usage of & alone as a selector is a bad practice. The solution in the linked answer was a hack which was useful in earlier versions of Less. It is still useful but there are alternate options and so & alone as a selector should be used only in extremely rare circumstances where none of the other option work.

How to override mixins in LESS CSS 1.4+

I've been using what I thought was a very elegant pattern for defining the styles of reusable components/widgets, using LESS. It works beautifully in LESS 1.3-, but after upgrading recently, my whole library is broken. Does anyone know a way to accomplish something like this in 1.4+?
Here's a very simple example of a component:
#componentName {
.loadMixins(){
.text() {}
.header() {}
}
.apply(){
> h3 {
// markup-specific styles
padding: 3px;
margin-bottom: 0;
// custom styles
.header();
}
> div.body, > div.popup p {
color: red;
// custom styles
.text()
}
}
}
And here's how it would be used:
.coolWidget {
#componentName.loadMixins();
// override mixins here
.text(){
color: green;
}
#componentName.apply();
}
This keeps all the markup-dependent styles abstracted from the user. I could completely change my markup and the user's styles would still work. According to the less.js changelog, 1.4.0 Beta 1 has a line "variables in mixins no longer 'leak' into their calling scope"
Is there any way around this?
Strictly speaking nested variables and mixins are still expanded into calling scope unless this scope already has those names defined.
Your example above results in a error:
SyntaxError: .header is undefined...
and it's expected as no .header() is actually defined within the .coolWidget (or anywhere else).
This can be fixed by providing "default" definitions for .text and .header somewhere inside #componentName.
For example if you modify .loadMixins() to:
.loadMixins() {
.text();
.header();
// default properties in case a caller does not provide its own:
.text() {}
.header() {}
}
then the example compiles OK and all text/header properties are overridden as expected.
I can imagine how your library may become broken because of new scope rules but this particular example you gave above does not illustrate the problem.

CSS class nesting

I havent done CSS in awhile (~5-7yrs).
So i need a little assistance in a possible solution to my quandry.
Ideal design:
table.ctable
{ class:collapsible collapsed; }
Now i know that its syntactically not correct but was wondering if there was a way to create some base-class CSS and then have those class(es) derive into a parent. I know its not OOP, but figured there would be a way around the current structure to accomidate this type of inclusion.
You couls use a SASS mixin:
#mixin left($dist) {
float: left;
margin-left: $dist;
}
#data {
#include left(10px);
}
or a LessCSS mixin:
.left(#dist) {
float: left;
margin-left: #dist;
}
#data {
.left(10px);
}
No, unfortunately you can't inherit rules from another class. The closest you can get is JavaScript getting elements by class name and applying extra classes to them, but then you have the jump between the page loading the JS running.

CSS "properties of .x" syntax

Is it possible to add additional rules to a css block when using a "{ (properties of x) }" selector?
I looked at references but I can't find anything related to "properties of x". A link would be wonderful. I tried the following two combinations, but neither worked:
.dock li { (properties of grid_2; display:inline; background-color:#666; ) }
.dock li { display:inline; background-color:#666; (properties of grid_2) }
Many thanks!
EDIT
Apparently I misread an article and thought that such a syntax existed. I thought one could create a class and let it inherit the properties of another using such syntax, which is evidently not the case.
CSS does not have such a feature.
What you are describing is not possible. I think there are two other possibilities you could maybe use. The first is, that you need to know that several styles can be applied to an element at the same time. I'll give you an example:
li { font-size: 10pt; }
.dock li { color: #ff0000; }
All list items will be formatted with a font size of 10 points and only those within an element containing the dock class will be red.
My second suggestion is that you try applying two or more classes to your HTML element, for instance:
.grid li { font-size: 10pt; }
.dock li { color: #ff0000; }
Now put the grid and dock class into your HTML, and the elements will apply both style definitions:
<ul class="grid dock"> ...
Whatever you consider best for your project: remember that the properties defined in the second style overwrite the properties of the first one (if they do not define the same properties at all, there will be no confusion).
maybe your question is not too strange..
What I understand is that you want to do something like:
.a { prop1: val; prop2: val; }
.b { prop3: val; prop4: val; }
.c { .a; .b; prop5: val; prop6: val; }
You want the class .c to inherit all the properties and values of .a and .b
If this is ok, you can do that using LESS.
To use your LESS code in your sites you have different ways to do it.
First of all check the original site: LESS.org
If you are on Mac check this site: LESS APP + PLUGINS
If you are on PC the less.js plugin should be easier to implement LESS in your sites: less.js usage
Hope it helps.
Happy coding y'all! :)

Resources