Extending nested selectors in LESS - less

I have the follwing HTML (basically)
table
tr
td
.c1
.c2
.c3
td
tr
... more rows...
table
I would like to write LESS for the CSS that applys to the c1, c2, c3 on tr:hover. When you roll over the row the button inside the row have different properties. The output CSS would be:
.table tr:hover {
color: red;
}
.table tr:hover .c1, .table tr:hover .c2, .table tr:hover .c3 .... {
color green;
}
I looked at extend but, somehow, I can't figure out this particular use case. Or should I just use the & char. and nest inside table:tr:hover
& c1, & c2, & c3...

With the requirements you listed you will want to do something like this:
.table tr {
&:hover {
color: red;
.c1, .c2, .c3 {
color: green;
}
}
}
Think of & as anything you want to be at the same level as the parent level, whether it be a class or a pseudo class.
When you nest items usually it matches the HTML structure/hierarchy so deciding how and where to nest is fairly straightforward. You want to share as much as possible without going overboard in getting to "nested hell".

You're trying to select a class within a pseudo class. That's not possible.
As I follow, it should be like this:
.table {
tr:hover {
color:red;
}
.c1, .c2, .c3 {
tr:hover {
color green;
}
}
}
How your HTML is setup is important. We aren't getting the whole picture here.

Related

Conditional when in less-file

I am making a theme editor for WordPress, and would like to use less to build the CSS file.
I have put a string in a variable like this:
#banner-separation-style: 'thick_border';
Then I'm trying to use when() like this:
when (#banner-separation-style = 'thick_border') {
header {
... some style
}
... and some css selectors
}
I've also tried combinations without quoting the variable.
How do I properly create something similar to if-blocks with less?
Guards (when statement) can only be used along with a mixin or a CSS selector. We can't write a when statement without using one of those. So, either write it with a mixin like below:
#banner-separation-style: 'thick_border';
.border-styles() when (#banner-separation-style = 'thick_border') {
header { border: 2px solid red; }
nav { border: 2px solid green; }
}
.border-styles;
or directly with the CSS selector like below:
#banner-separation-style: 'thick_border';
header when (#banner-separation-style = 'thick_border') {
border: 2px solid red;
}
nav when (#banner-separation-style = 'thick_border') {
border: 2px solid green;
}
or atleast using an unnamed selector (&) like below:
#banner-separation-style: 'thick_border';
& when (#banner-separation-style = 'thick_border') {
header { border: 2px solid red; }
nav { border: 2px solid green; }
}
The first version (with mixin) is the one that I prefer because (a) you don't have to repeat the condition multiple times like in the CSS selector version and (b) giving the mixin a name makes it more readable than using an unnamed selector. It is just my choice and some other user could actually prefer the last because it doesn't need that extra mixin call statement.

Improve Less nesting for this rule?

I need the following CSS output. The ie* classes must be there for specificity and the body class also needs to be there without them as they won't always be added.
body.my-class,
html.ie7 body.my-class,
html.ie8 body.my-class,
html.ie9 body.my-class {
background: red;
}
I can get the same thing with this in my Less. However its not a good idea as I have to write the style of background: red twice. So if it was updated it would need to be updated in 2 places.
body.my-class {
background: red;
html.ie7 &,
html.ie8 &,
html.ie9 {
background: red;
}
}
Can I write my Less in a different way so that I'm not repeating the style, but so that the compiled CSS is exactly the same?
Simply add the & (parent selector) as one of the comma separated selector list within the top level nesting. Less compiler would automatically replace it with the full parent selector as it always does.
body.my-class {
&, /* this will replaced with body.my-class as is always the case with parent selectors */
html.ie7 &,
html.ie8 &,
html.ie9 &{
background: red;
}
}
The above code when compiled would result in exactly the same CSS output as required.
body.my-class,
html.ie7 body.my-class,
html.ie8 body.my-class,
html.ie9 body.my-class {
background: red;
}

How to merge parent and child style properties using LESS

I have this less code, this is working just fine. I just want to save some spaces when the less cli compiles it.
.secondary-content {
background: #ffcc80;
color: white !important;
label, i {
background: #ffcc80;
color: white !important;
}
}
When I run less from the command prompt, the output looks like this.
.secondary-content {
background: #ffcc80;
color: white !important;
}
.secondary-content label,
.secondary-content i {
background: #ffcc80;
color: white !important;
}
as you can see they are separated on each block. I would like to have them on the same block. How could I easily merge the parent and child style properties? Like this.
.secondary-content,
.secondary-content label,
.secondary-content i {
background: #ffcc80;
color: white !important;
}
I'm still learning less, so any help would be much greatly appreciated.
Thanks in advance
You can make use of the parent selector (&) like in the below snippet. Usage of parent selector would mean that the same rules apply for .ghost .secondary-content selector as well as its child label and i tags.
.ghost .secondary-content {
&, label, i {
background: #ffcc80;
color: white !important;
}
}
Of course the solution provide by #Harry works. When you are learning Less you should keep in mind that Less helps you to write your CSS code DRY and more efficient. Less does not help you to solve issues, that you can not solve in common CSS, Less compiles into CSS and does not add any feature to the compiled CSS.
To reduce the size of your CSS for selectors which share some properties you should consider the extend feature of Less: http://lesscss.org/features/#extend-feature-reducing-css-size:
.selector1 {
color: red;
}
.selector2:extend(.selector1) {}
outputs:
.selector1,
.selector2 {
color: red;
}
To solve your issue you should reconsider the desired CSS code instead of the Less code. You can not use extend due to the nesting of the label, i, but why should you nest them to set the color and background-color?
The default value for the background-color is transparent so when you set the background-color for the parent you do not have set the background-color for the child elements (when using the same value).
Possible you override the default transparent with an other style rule with a higher specificity, see also http://www.smashingmagazine.com/2010/04/07/css-specificity-and-inheritance/
An example which gives your nested label the wrong background-color:
label {
background-color:green;
}
.secondary-content {
background-color:red;
color: white;
}
The same for the color property which always inherit from its parent, unless applied in an anchor.
You are also using !important, see: https://css-tricks.com/when-using-important-is-the-right-choice/

Inline-block line-wrap extra space

I've got an inline-block element that contains a very long word. When I resize the viewport until I reach the breakpoint of the text wrapping to the next line, I get a substantial amount of space. However, I would like the inline-block element to wrap immediately to the width of its contents.
I found it hard to explain exactly what's going on, so below an animated gif to illustrate my issue:
Upon resizing the viewport:
To be clear, the image above is me continuously resizing the viewport.
Does anybody know a way to achieve what I'd like? Even with CSS hyphenation the white-space still remains (which I don't want).
JSFiddle. Resize the frames to see what I mean.
div {
display: inline-block;
background-color: black;
color: white;
padding: 5px;
}
The inline-block indeed extends on resizing as your animation shows, so that it keeps place for the long word to go into that space again.
One simple solution would be to add text-align: justify, but I'm afraid it may not exactly be what you want (see demo).
Another one would be the use of media queries, as #Parody suggested, but you would have to know the dimentions of the containing div, and that would not be very scalable as you mentionned.
The word-break: break-all suggested by #yugi also works but causes the words to to collapse letter by letter, regardless of their length.
The only way to achieve the exact behavior is (as far as I know) to use javascript. For example, you would have to wrap your text into a span element inside the div, and then add something like this :
var paddingLeft = parseInt($('#foo').css('padding-left')),
paddingRight = parseInt($('#foo').css('padding-left')),
paddingTop = parseInt($('#foo').css('padding-top')),
paddingBottom = parseInt($('#foo').css('padding-Bottom')),
cloned = $('#foo span').clone(),
cloned_wrap = document.createElement('div');
$(cloned_wrap).css({
paddingLeft : paddingLeft,
paddingRight : paddingRight,
display : 'inline-block',
visibility: 'hidden',
float: 'left',
});
$(cloned_wrap).insertAfter('#foo');
cloned.appendTo(cloned_wrap);
$(window).on('resize', function(){
$('#foo').css('width', cloned.width() + 1);
$(cloned_wrap).css('margin-top',- $('#foo').height() - paddingTop - paddingBottom);
}).resize();
Please see the jsfiddle working demo. (← edited many times)
That's quite a lot of code, but it works ; )
(PS : I assumed jquery was available, if not, quite the same is achievable in pure JS)
I don't think this is possible only with CSS for the one element. The reason for your behavior is that the width of the element is still 100% of its container. The only way I could think to accomplish this is by doing something a little bit "creative"...try setting the style to inline so you get the shrink-wrap behavior, but to get around the background color issue, also put it in a container that shares the same background. That should work.
If im understanding you correctly you could use the #media type to decide what css to use depending on the width of the screen
here is an example of what i mean
#media(min-width:0px) and (max-width:200px){
div {
display: block;
background-color: black;
color: white;
padding: 5px;
}
}
#media (min-width:200px){
div {
display: inline-block;
background-color: black;
color: white;
padding: 5px;
}
}
I am still very appreciative of #lapin's answer (which I accepted and awarded bounty to), I found out after the fact that it didn't quite work on multiple elements next to each other (that has nothing to do with #lapin, I just didn't mention it in my original question as I thought it would be irrelevant information).
Anyway, I've come up with the following that works for me (assuming the elements it should be applied to are .title and .subtitle):
$('.title, .subtitle').each(function(i, el) {
var el = $(el),
inner = $(document.createElement('span')),
bar = $(document.createElement('span'));
inner.addClass('inner');
bar.addClass('bar');
el.wrapInner(inner)
.append(bar)
.css({
backgroundColor: 'transparent'
});
});
function shrinkWrap() {
$('.title, .subtitle').each(function(i, el) {
var el = $(el),
inner = $('.inner', el),
bar = $('.bar', el),
innerWidth = inner.width();
bar.css({
bottom: 0,
width: innerWidth + parseFloat(el.css('paddingLeft')) + parseFloat(el.css('paddingRight'))
});
});
}
shrinkWrap();
$(window).on('resize', function() {
shrinkWrap();
});
Basically what I do is:
put the text in an inner wrap element
create an additional absolutely-positioned background element
get the width of the inline inner wrap element
apply said width to the background element (plus padding and whatnot)
The CSS:
.title, .subtitle {
position: relative;
z-index: 500;
display: table;
padding-left: 10px;
margin-right: 10px;
background-color: red;
}
.title .bar, .subtitle .bar {
position: absolute;
top: 0;
left: 0;
bottom: 0;
z-index: -10;
background-color: red;
}

Is there a way to add a mixin into a variable in LESS

Can I add a mixin to a variable in LESS?
Something like this
#input-border-radius: .rounded();
or
#h1: .font-size(46) // This pulls from the rem calculator mixin.
Looked at the LESS Docs but can't see a way to do it.
There is a way.
You can define properties of a (possibly immaginary) class and recall the properties of that class in the style of a different class. For example:
.fontstyling {
font-weight: bold;
color: black;
}
h1 {
font-size: 46px;
.fontstyling;
}
h2 {
font-size: 38px;
.fontstyling;
}
(thats not the best way to format the headings - but for other exemples it is really useful!)