LESS CSS - Different elements in a function - css

I use LESS CSS. My code looks like this.
Repeatable pattern
Do you see the pattern in my code? The only thing that differs the two is the padding value and the class name.
Question
Is it possible in LESS CSS to make a function / mixin of a block like this with many different elements?
LESS CSS
&.pad-10 > [class*='cols-'] {
background: #ccc;
padding: 10px;
&:first-child {
padding-left: 0;
}
&:last-child {
padding-right: 0;
}
}
&.pad-20 > [class*='cols-'] {
background: #ccc;
padding: 20px;
&:first-child {
padding-left: 0;
}
&:last-child {
padding-right: 0;
}
}
Mixin suggestion
do_padding( $value ) {
&.pad-#value > [class*='cols-'] {
background: #ccc;
padding: #valuepx;
&:first-child {
padding-left: 0;
}
&:last-child {
padding-right: 0;
}
}
do_padding( 10 );
do_padding( 20 );
I know that my exact problem can be solved in other ways without LESS CSS, but I have this problem from time to time.

Yes, you just need to set up a proper counting and looping structure in LESS. Here's how:
LESS
.do_padding(#startValue, #increment) {
.loop(#value) when (#value > 0) {
//set top amount
&.pad-#{value} > [class*='cols-'] {
background: #ccc;
padding: #value * 1px;
&:first-child {
padding-left: 0;
}
&:last-child {
padding-right: 0;
}
}
// next iteration
.loop(#value - #increment);
}
// end the loop when index is 0 or less
.loop(#value) when not (#value > 0) {}
//start the loop
.loop(#startValue);
}
Use it
.myClass {
.do_padding(30, 10);
}
CSS Output
.myClass.pad-30 > [class*='cols-'] {
background: #ccc;
padding: 30px;
}
.myClass.pad-30 > [class*='cols-']:first-child {
padding-left: 0;
}
.myClass.pad-30 > [class*='cols-']:last-child {
padding-right: 0;
}
.myClass.pad-20 > [class*='cols-'] {
background: #ccc;
padding: 20px;
}
.myClass.pad-20 > [class*='cols-']:first-child {
padding-left: 0;
}
.myClass.pad-20 > [class*='cols-']:last-child {
padding-right: 0;
}
.myClass.pad-10 > [class*='cols-'] {
background: #ccc;
padding: 10px;
}
.myClass.pad-10 > [class*='cols-']:first-child {
padding-left: 0;
}
.myClass.pad-10 > [class*='cols-']:last-child {
padding-right: 0;
}

Related

How to nest SCSS with "&" properly to re-use immediate parent (partial) class name?

I want to re-use the class name of the parent and use it on a child element, but it is not working as expected when nesting more than one level.
I want to concatenate the child class name only with the immediate parent string and not the whole concatenated parent.
I am starting to believe this is not possible.
The SCSS:
.block {
margin: 2px;
& &__element {
margin: 3px;
&-nested {
margin: 4px;
}
}
}
The output:
.block {
margin: 2px;
}
.block .block__element {
margin: 3px;
}
.block .block__element-nested {
margin: 4px;
}
The desired output:
.block {
margin: 2px;
}
.block .block__element {
margin: 3px;
}
.block .block__element .block__element-nested {
margin: 4px;
}
Bro, currently nested-& is not supported in Sass. Hopefully, that's the only solution:
.block {
margin: 2px;
& &__element {
margin: 3px;
}
& &__element &-nested {
margin: 4px;
}
}
EDIT
To achieve your desired output you may do this.
.block {
margin: 2px;
& &__element {
margin: 3px;
}
& &__element &__element-nested {
margin: 4px;
}
}
EDIT 2
.block {
margin: 2px;
& &__element {
margin: 3px;
& .block__element-nested {
margin: 4px;
}
}
}
Output:
.block {
margin: 2px;
}
.block .block__element {
margin: 3px;
}
.block .block__element .block__element-nested {
margin: 4px;
}
In my opinion, your desired output doesn't make sense because it's very confusing on a larger scale. The bottom example is from the docs. The point is not to go deeper than the third level I think...
.block {
background: red;
&__element {
background: red;
&--nested {
background: red;
}
}
}
.block {
background: red;
}
.block__element {
background: red;
}
.block__element--nested {
background: red;
}
Here 2 solution that are working fine with the use of selector-nest.
You will find more information: https://sass-lang.com/documentation/modules/selector#nest
You can test solution here: https://www.sassmeister.com
Method 1:
.block {
margin: 2px;
& &__element {
margin: 3px;
#{selector-nest('.block__element', '&-nested')} {
margin: 4px;
}
}
}
Method 2:
.block {
margin: 2px;
#{selector-nest('.block', '&__element')}{
margin: 3px;
#{selector-nest('.block__element', '&-nested')} {
margin: 4px;
}
}
}
Apparently this can not be done. As described here as well:
https://css-tricks.com/the-sass-ampersand/#what-the-isnt
My intention was for the & to only get replaced with .parent in hopes of compiling to this:
.parent .child {}
But that doesn’t work.
The & is always the fully compiled parent selector.

Multiply css value for child nodes in LESS

I have classes like below
.item-1{
.child-item-1 {
.child-item-2 {
}
}
}
I want to increase padding for each child something like that
padding: (n*10)px
How can I get this as I have varied number of child items and for each child item I want to increase padding
Thanks in advance for help
You can define a constant variable with # and just multiply it for the n number, in case you need to specify specific child classes you need to do like this:
#default-padding: 5px;
.item-1{
padding: #default-padding;
.child-item-1 {
padding: #default-padding*10;
.child-item-2 {
padding: #default-padding*100;
}
}
}
Compiles to:
.item-1 {
padding: 5px;
}
.item-1 .child-item-1 {
padding: 50px;
}
.item-1 .child-item-1 .child-item-2 {
padding: 500px;
}
If you want to apply it to all the childrens you can use * CSS selector like:
#default-padding: 5px;
.item-1{
padding: #default-padding;
& > * {
padding: #default-padding*10;
& > * {
padding: #default-padding*100;
}
}
}
Compiles to:
.item-1 {
padding: 5px;
}
.item-1 > * {
padding: 50px;
}
.item-1 > * > * {
padding: 500px;
}

How to make a loop in Less

I'm trying to achieve a loop for padding.
Example from less.org just modified
.generate-pad(10);
.generate-pad(#n, #i: 1) when (#i =< #n) {
.padd-top-#{i} {
padding-top: (#i * 100px / #n);
}
.generate-pad(#n, (#i + 1));
}
outputs the following when its compiled
.padd-top-1 {
padding-top: 10px;
}
.padd-top-2 {
padding-top: 20px;
}
.padd-top-3 {
padding-top: 30px;
}
.padd-top-4 {
padding-top: 40px;
}
.padd-top-5 {
padding-top: 50px;
}
.padd-top-6 {
padding-top: 60px;
}
.padd-top-7 {
padding-top: 70px;
}
.padd-top-8 {
padding-top: 80px;
}
.padd-top-9 {
padding-top: 90px;
}
.padd-top-10 {
padding-top: 100px;
}
but I am trying to replace .pad-top-#{i} with a variable so I can call it later. How can I achieve this?

Scalable/Modular CSS: how to handle vertical margins between modules?

I've searched extensively, and can't seem to find a consistent way that people handle the top/bottom margins between modules in a... modular way. I like the idea of just using a generic wrapper div with the css as .page-area { margin-bottom: 1em }, but in the real world, designers aren't that consistent, and you end up with multiple variations on that container. I've used this sass code on a few projects, and it worked alright, but I didn't necessarily love it (credit to Nicole Sullivan):
*p,m = padding,margin
*a,t,r,b,l,h,v = all,top,right,bottom,left,horizontal,vertical
*s,m,l,n = small($space-half),medium($space),large($space-double),none(0)
*/
$space : 1em;
$space-half : $space/2;
$space-double : $space*2;
.ptn, .pvn, .pan { padding-top: 0; }
.pts, .pvs, .pas { padding-top: $space-half; }
.ptm, .pvm, .pam { padding-top: $space; }
.ptl, .pvl, .pal { padding-top: $space-double; }
.prn, .phn, .pan { padding-right: 0; }
.prs, .phs, .pas { padding-right: $space-half; }
.prm, .phm, .pam { padding-right: $space; }
.prl, .phl, .pal { padding-right: $space-double; }
.pbn, .pvn, .pan { padding-bottom: 0; }
.pbs, .pvs, .pas { padding-bottom: $space-half; }
.pbm, .pvm, .pam { padding-bottom: $space; }
.pbl, .pvl, .pal { padding-bottom: $space-double; }
.pln, .phn, .pan { padding-left: 0; }
.pls, .phs, .pas { padding-left: $space-half; }
.plm, .phm, .pam { padding-left: $space; }
.pll, .phl, .pal { padding-left: $space-double; }
.mtn, .mvn, .man { margin-top: 0; }
.mts, .mvs, .mas { margin-top: $space-half; }
.mtm, .mvm, .mam { margin-top: $space; }
.mtl, .mvl, .mal { margin-top: $space-double; }
.mrn, .mhn, .man { margin-right: 0; }
.mrs, .mhs, .mas { margin-right: $space-half; }
.mrm, .mhm, .mam { margin-right: $space; }
.mrl, .mhl, .mal { margin-right: $space-double; }
.mbn, .mvn, .man { margin-bottom: 0; }
.mbs, .mvs, .mas { margin-bottom: $space-half; }
.mbm, .mvm, .mam { margin-bottom: $space; }
.mbl, .mvl, .mal { margin-bottom: $space-double; }
.mln, .mhn, .man { margin-left: 0; }
.mls, .mhs, .mas { margin-left: $space-half; }
.mlm, .mhm, .mam { margin-left: $space; }
.mll, .mhl, .mal { margin-left: $space-double; }
I realize that questions like this can potentially start discussions, but that's not my intent - I'm just wondering if there is a single common best practice for consistent vertical margin/padding of modules and page sections? SMACSS doesn't seem to touch on it.
I don't know if this will be helpful for you, but this is usually what I do.
I set a vertical rhythm variable based on my defaults, and then make a placeholder class for vertical rhythm, which I extend on elements that need it.
$base-font-size: 20px !default
$base-line-height: 1.3
$base-vertical-rhythm: ceil($base-font-size * $base-line-height)
%base-vertical-rhythm
margin-bottom: em($base-vertical-rhythm)
blockquote,
dl,
ol,
p,
ul
#extend %base-vertical-rhythm
Compass also has some presets for vertical rhythm.

How to effectively write -sm, -md, -lg padding classes in LESS

I'm trying to create standard classes that can be used to add different amounts of padding. This would be added to the individual elements within the DOM to control padding/margins. I'd like to eventually leverage it for different sizes and for margins as well. This is how I've begun to write it in LESS, but is there a shorter way to write this?
#padding-sm: 5px;
#padding-md: 10px;
#padding-lg: 20px;
.padding-sm {
padding: #padding-sm;
}
.padding-sm-h {
padding-right: #padding-sm;
padding-left: #padding-sm;
}
.padding-sm-v {
padding-top: #padding-sm;
padding-bottom: #padding-sm;
}
.padding-sm-top {
padding-top: #padding-sm;
}
.padding-sm-right {
padding-right: #padding-sm;
}
.padding-sm-bottom {
padding-bototm: #padding-sm;
}
.padding-none {
padding: 0;
}
For LESS 1.7+
This uses the .for looping code that can be found here, which is normally recommended to be saved in a separate less file and imported, like so:
#import "for";
Assuming that code is in place, whether by import or hard copied in, then you can build the following mixin:
.setPadding(#size) {
#s: ~"-#{size}";
#getSize: ~"padding#{s}";
#getValue: ##getSize;
#directions: top right bottom left;
#pairs: h right left, v top bottom;
.appendPadding() {.padding& { #props();}}
#{s} {
//set all directions
& {
#props: {padding: #getValue;};
.appendPadding();
}
//set paired directions
& {
.for(#pairs); .-each(#pair) {
#name: extract(#pair, 1);
#one: extract(#pair, 2);
#two: extract(#pair, 3);
&-#{name} {
#props: {
padding-#{one}: #getValue;
padding-#{two}: #getValue;
};
.appendPadding();
}
}
}
//set four base directions
& {
.for(#directions); .-each(#dir) {
&-#{dir} {
#props: {padding-#{dir}: #getValue;};
.appendPadding();
}
}
}
}
}
Now the above looks vastly more complicated than your original code, but it gets its power by its ability to easily reproduce for all your sizing levels. So with the above code, then the following minimal amount of code defines your three groups into CSS as you are desiring:
#padding-sm: 5px;
#padding-md: 10px;
#padding-lg: 20px;
.setPadding(sm);
.setPadding(md);
.setPadding(lg);
.padding-none {
padding: 0;
}
CSS Output
.padding-sm {
padding: 5px;
}
.padding-sm-h {
padding-right: 5px;
padding-left: 5px;
}
.padding-sm-v {
padding-top: 5px;
padding-bottom: 5px;
}
.padding-sm-top {
padding-top: 5px;
}
.padding-sm-right {
padding-right: 5px;
}
.padding-sm-bottom {
padding-bottom: 5px;
}
.padding-sm-left {
padding-left: 5px;
}
.padding-md {
padding: 10px;
}
.padding-md-h {
padding-right: 10px;
padding-left: 10px;
}
.padding-md-v {
padding-top: 10px;
padding-bottom: 10px;
}
.padding-md-top {
padding-top: 10px;
}
.padding-md-right {
padding-right: 10px;
}
.padding-md-bottom {
padding-bottom: 10px;
}
.padding-md-left {
padding-left: 10px;
}
.padding-lg {
padding: 20px;
}
.padding-lg-h {
padding-right: 20px;
padding-left: 20px;
}
.padding-lg-v {
padding-top: 20px;
padding-bottom: 20px;
}
.padding-lg-top {
padding-top: 20px;
}
.padding-lg-right {
padding-right: 20px;
}
.padding-lg-bottom {
padding-bottom: 20px;
}
.padding-lg-left {
padding-left: 20px;
}
.padding-none {
padding: 0;
}

Resources