How to mix in generated sprites mixins to loop-generated classes in LESS? - less

I'd like to generate multiple classes with mixed in sprites, using recursive, guarded mixins (and LESS compiler version 1.7).
The basic idea looks like this:
.sprite-img {
background: url("sprite.png") no-repeat;
}
.icon_1 { width: 26px; height: 23px; background-position: -27px -27px; }
.icon_1_hover { width: 26px; height: 23px; background-position: -73px -51px; }
.icon_2 { width: 26px; height: 22px; background-position: -73px -28px; }
.icon_2_hover { width: 26px; height: 22px; background-position: 0 -48px; }
// setup some lists
#colors: #efa, #a77 ...;
#IDs: 1, 10,...;
.generate-colored-toggles(#n, #i: 1) when ( #i =< #n) {
#c: extract(#colors, #i); // subtracts 1 from index for list access
#j: extract(#IDs, #i);
.container .toggle._#{j} .img-holder {
border-color: #c;
.sprite;
/* LESS compiler error: */
.icon_#{i}; // adding parentheses won't work either
&:hover {
.icon_#{i}_hover;
}
}
.generate-colored-toggles(#n, (#i + 1)); // recurse
}
.generate-colored-toggles(length(#colors));
The resulting classes ( ._1 ... ._n ) are to be assigned, dynamically (in a loop, cf. JSF's ui-repeat), during page generation.
Now I'm facing numerous limitations:
My sprites are generated using http://zerosprites.com/; thus, names of the sprite mixin classes .icon_ are taken from the image file names, and should therefore not be modified.
The .toggle's structure is determined by my widget library and should be left unchanged. This prevents me from assigning the specific sprite image class to the .img-holder directly in the markup.
Can you think of a workaround (preferably, using LESS only)?

Related

How to Add in Less Meta Informations for a Mixin Class? (phpStorm)

Is it possible in Less to setup mixin informations that can read phpStorm?
I write a Mixin like this:
.action-btn(#size: 32px, #color: #fff, #bgColor: #overlayStyleBlack, #bgColorHover: #red) {
a {
width: #size;
display: block;
color: #color;
text-align: center;
line-height: #size;
background-color: #bgColor;
&:hover {
cursor: pointer;
background-color: #bgColorHover;
}
}
}
What i want now is, that when i use this mixin in another less file: ".action-btn();" then i want to see that i have in this Mixin 4 Settings that i can Setup. In php Classes i can do this with:
/**
* #param string $xxx
* function to check and change user is_online flag in sphinx and in mysql
*/
But this dont work in the Less Mixin File.
And how can i Skip some settings? Here a example to explain what i mean. (This ry dont worked)
.action-btn(64px, , , #fff);

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

How to customize bootstrap3 #grid-gutter-width for only .col-xs- [duplicate]

This question already has answers here:
Reduce the gutter (default 30px) on smaller devices in Bootstrap3?
(5 answers)
Closed 8 years ago.
I'd like to have thinner gutters when rendered on mobile devices. I found this in mixins.less to let me set #grid-gutter-width globally. But what's the best way to set a different gutter width for ONLY col-xs- (mobile devices) when the columns are all collapsed without breaking everything else?
// Grid System
// -----------
// Centered container element
.container-fixed() {
margin-right: auto;
margin-left: auto;
padding-left: (#grid-gutter-width / 2);
padding-right: (#grid-gutter-width / 2);
.clearfix();
}
// Creates a wrapper for a series of columns
.make-row(#gutter: #grid-gutter-width) {
margin-left: (#gutter / -2);
margin-right: (#gutter / -2);
.clearfix();
}
// Generate the extra small columns
.make-xs-column(#columns; #gutter: #grid-gutter-width) {
position: relative;
float: left;
width: percentage((#columns / #grid-columns));
// Prevent columns from collapsing when empty
min-height: 1px;
// Inner gutter via padding
padding-left: (#gutter / 2);
padding-right: (#gutter / 2);
}
There is a good answer here that will solve this problem: Reduce the gutter (default 30px) on smaller devices in Bootstrap3?
i.e.:
/* Extra-small devices (767px and below) */
#media (max-width: 767px)
{
div[class^="col-xs-"] {
padding-left: 5px;
padding-right: 5px;
}
}
Of course, you might to wrap that up in LESS.
If you want to change gutter size you must open the variable.less, and look for
#grid-gutter-width:
and change it to your desired value.
Tips:
you can also change/edit number of columns, container width inside the variable.less.

Can you adopt a 'specific' single property from another style?

I'm pretty new to LESS and have been playing with ways to reuse properties from existing styles.
Is there a way I get reuse a Single Style/Property (by name) of a known CSS Class, for example:
This Obviously merges all of .source into .target:
.source { width: 100%; display: block; color: #ff0000; }
.target {
height: 10px;
.source;
}
What if I wanted just the width property, something like this:
.source { width: 100%; display: block; color: #ff0000; }
.target {
height: 10px;
width : .source:width;
}
I've been looking for a while now, and I'm doubtful its possible, but hoping someone has some suggestions.
Essentially I'm hoping to not generate tons of repeated CSS for properties I don't need.
Short Answer, Not at Present (as of version 1.7)
There is no way to target just a single property for retrieval without setting up the class to allow access to it. For example, if it was worth it to you, a class could be set up like so:
.source {
.get(#prop) when (#prop = width), (#prop = all) {width: 100%;}
.get(#prop) when (#prop = display), (#prop = all) {display: block;}
.get(#prop) when (#prop = color), (#prop = all) {color: #ff0000;}
.get(all);
}
.target {
height: 10px;
.source > .get(width);
}
This will get the output you want. But as you can see, it involves much more coding than just setting the properties on the two items themselves (or setting a global variable for both to access, which would be the better way to go). I cannot think of a situation when it would be best to use the above method, but maybe someone might find this useful.

Generic `vendors` mixin

Defining vendors' mixins is common task under LESS, ie:
.box-shadow() {
-moz-box-shadow:#arguments;
-webkit-box-shadow:#arguments;
-o-box-shadow:#arguments;
-ms-box-shadow:#arguments;
box-shadow:#arguments;
}
.border-radius() {
-moz-border-radius:#arguments;
-webkit-border-radius:#arguments;
-o-border-radius:#arguments;
-ms-border-radius:#arguments;
border-radius:#arguments;
}
...
But it seems a bit repeating...
What I would like is a generic vendor mixin which do this for me, ie:
.vendors(#prop, #val) {
-moz-#prop:#val;
-webkit-#prop:#val;
-o-#prop:#val;
-ms-#prop:#val;
#prop:#val;
}
Then defining box-shadow mixin would as simple as:
.box-shadow() {
.vendors(box-shadow, #arguments);
}
The problem is my .vendors mixin does not compile...
I tried:
.vendors(#prop, #val) {
-moz-#prop: #val; /* Error */
~"-moz-#{prop}": #val; /* Error */
~`"-moz-#{prop}": #val; /* Error */
}
Do you have an idea on how to do this?
Cheers
Stylus has this, which is called Interpolation, eg:
vendor(prop, args)
-webkit-{prop} args
-moz-{prop} args
{prop} args
border-radius()
vendor('border-radius', arguments)
box-shadow()
vendor('box-shadow', arguments)
— Then,
button
border-radius 1px 2px / 3px 4px
yields to:
button {
-webkit-border-radius: 1px 2px / 3px 4px;
-moz-border-radius: 1px 2px / 3px 4px;
border-radius: 1px 2px / 3px 4px;
}
\o/
Another option, that I think is a little cleaner, would be do create a list of vendors and then iterate over that list to create the particular styles you want. Here's an example:
ALLVENDORS = webkit moz o ms w3c
vendors(prop, args)
for vendor in ALLVENDORS
if vendor == w3c
{prop}: args
else
-{vendor}-{prop}: args
This creates a list of vendors that you want to support and then allows you to reuse them. if later, you decide you want to support another prefix or want to remove one, all you have to do is remove it from the list.
And then you would use the list just as shown above:
border-radius()
vendors(border-radius, arguments)
box-shadow()
vendor(box-shadow, arguments)
I'm pretty sure less now has it. I've used this code in a Meteor.js project:
.vendor(#property, #value) {
-webkit-#{property}: #value;
-khtml-#{property}: #value;
-moz-#{property}: #value;
-ms-#{property}: #value;
-o-#{property}: #value;
#{property}: #value;
}
.vertical-align {
position: relative;
top: 50%;
.vendor(transformY, -25%);
}