How to change variable value using parent selector in LESS - css

So lets have following snippet:
.dashboard.tile {
display: block;
color:white;
&-blue {
#body-color:#light-blue;
#footer-color:#dark-blue;
font-size: 10px;
}
#body-color:#greenBright;
#footer-color:#000;
div.tile-body {
border-radius: #tile-border-radius #tile-border-radius 0 0;
background-color: #body-color;
font-size: #font-size-h2;
}
div.tile-footer {
border-radius: 0 0 #tile-border-radius #tile-border-radius;
background-color: #footer-color;
}
}
My goal is to create additional classes like tile-blue tile-red etc that would only change color variable values.
Unformtunelty this does not work. tile-blue gets generated with font-size:10 but variables are unaffected - more over, default color is not applied so I guess that i have messed something up with selector hierarchy etc.

Found the solution that exactly suits my needs
.dashboard-tile{
&-blue{
.dashboard-tile(#light-blue,#dark-blue)
}
&-green{
.dashboard-tile(#light-green,#dark-green)
}
&-red{
.dashboard-tile(#light-red,#dark-red)
}
&-violet{
.dashboard-tile(#light-violet,#dark-violet)
}
}
.dashboard-tile(#body-color,#footer-color) {
margin-bottom: 5px;
margin-top: 5px;
display: block;
color: white;
.tile-body {
border-radius: #tile-border-radius #tile-border-radius 0 0;
background-color: #body-color;
font-size:#font-size-h2;
#tilePadding;
}
.tile-footer {
border-radius: 0 0 #tile-border-radius #tile-border-radius;
background-color: #footer-color;
#tilePadding;
}
}

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.

merge #extend with parent style and make one class name

I'm trying to merge the style into one class but its showing an error. Look at the example below.
%banner-style{
banner {
padding: 140px 0 210px;
background: url(https://im2.ezgif.com/tmp/ezgif-2-92c6382d82ba.jpg) top center/cover no-repeat;
&.row {
margin: 0;
}
.main-heading {
font-size: 40px;
letter-spacing: -1px;
font-weight: 600;
padding-right: 20px;
sup {
font-size: 10px;
vertical-align: super;
}
}
}
}
And I want it to merge with the parent class .parent
.parent{
color: red;
&_#extend %banner-style;
}
using & to merge into one class name. but showing error unless i do this
.parent{
color: red;
&_{#extend %banner-style};
}
Which is same as if I remove &_.
I wanted .parent_banner {...} but instead got .parent_ banner{...};
Does anyone know how I can accomplish this?
You are getting exactly what is supposed to happen. Extend does not "merge" classes, it extends another class/placeholder into a new selector's styles.
What that means is if I write:
%banner-style {
background: black;
}
.parent {
#extend %banner-style;
}
.other-selector {
#extend %banner-style;
color: red;
}
The css I get will be
.parent {
background: black;
}
.other-selector {
color: red;
background: black;
}
So you are getting expected results. If you'd like to make this "work" the way you want, you can just change your code to:
%banner-style {
padding: 140px 0 210px;
background: url(https://im2.ezgif.com/tmp/ezgif-2-92c6382d82ba.jpg) top center/cover no-repeat;
&.row {
margin: 0;
}
.main-heading {
font-size: 40px;
letter-spacing: -1px;
font-weight: 600;
padding-right: 20px;
sup {
font-size: 10px;
vertical-align: super;
}
}
}
.parent{
color: red;
&_banner {
#extend %banner-style;
};
}
Note: I took out the banner block because it seems you don't want that (and banner isn't a normal html element).

Dynamic margin/padding with sass

Is it possible to simplify and make this more easily maintained with sass?
.padding-8 { padding: 8px !important; }
.padding-10 { padding: 10px !important; }
.padding-top-0 { padding-top: 0 !important; }
.padding-top-3 { padding-top: 3px !important; }
.padding-bottom-0 { padding-bottom: 0 !important; }
.padding-bottom-3 { padding-bottom: 3px !important; }
.padding-bottom-5 { padding-bottom: 5px !important; }
.margin-top-0 { margin-top: 0 !important; }
.margin-top-5 { margin-top: 5px !important; }
.margin-bottom-0 { margin-bottom: 0 !important; }
.margin-bottom-5 { margin-bottom: 5px !important; }
etc..
Is it also possible to write something like .padding-$dir-$value { padding-$dir: $value px !important; } so you can use a class with f.ex padding-left-13?
Make two maps with the properties you want to mix.
For each combination create a placeholder class. I think it's appropiate if you don't want to create a full list of classes that maybe you won't use. This is the modular-friendly use.
Extend the class in your element.
$paddingDirection:('right','left','top','bottom');
$paddingLength:(15,30,45,50);
#each $dir in $paddingDirection{
#each $len in $paddingLength{
%padding-#{$dir}-#{$len}{ padding-#{$dir}: #{$len}px;}
}
}
.any-class{
#extend %padding-right-30;
}
/*output*/
.any-class {
padding-right: 30px;
}
Original answer here
you can use this: (enhanced the above solution)
$paddingDirection:('right','left','top','bottom');
$paddingLength:(15,30,45,50);
// if you only wants to use "padding" without postfix
#each $len in $paddingLength {
.padding-#{$len} { padding: #{$len}px;}
}
// if you want to use padding-left, padding-right etc.
#each $dir in $paddingDirection {
#each $len in $paddingLength {
.padding-#{$dir}-#{$len} { padding-#{$dir}: #{$len}px;}
}
}
usage:
<div class="padding-15"></div>
<div class="padding-left-15 padding-top-15"></div>

How to Add flexibility to SASS for another color

I've got some Sass I've inherited that looks like below. I want to be able to specify a CSS tag to differentiate between green and another color (see anchor tag and comment).
Now, I have-
<div class="names"></div>
The link shows green. I want to be able do something like-
<div class="names myblue"></div>
And instead have it be a different color.
&.SpeakerCount3 {
.names {
text-align: center;
li {
text-align: center;
display: inline-block;
width: 82px;
margin-left: 5px;
&:first-child {
margin-left: 0;
}
}
img {
max-width: 100%;
}
h3 {
margin-top: 0;
a {
font-size: 10px;
}
}
}
}
.names {
min-height: 180px;
.photo {
margin-top: -21px;
}
img {
display: block;
border: 3px solid #282828;
margin: 0 auto;
}
h3 {
margin-top: 5px;
}
a {
font-size: 20px;
color: #5c5c5c; // this was green but I could not figure how to make it orange for css and green for kids
text-decoration: none;
}
}
.description {
margin-bottom: 15px;
min-height: 120px;
h3 {
margin: 5px 0 20px 0;
min-height: 40px;
}
}
Having seen the HTML code that was being hidden in your question, I should say that good class names generally should relate to state rather than properties - so the class name "myblue" should probably be replaced with something like "featured", "highlighted" etc. This is especially the case where you are asking for "myblue" to actually change the colour to Orange - something that may well confuse future maintainers. In the case that "myblue" is a company or feature name it may well be legitimate, but I would consider carefully if there is an alternative class name which does not include a colour name.
In Sass you could do something like-
a {
font-size: 20px;
color: #5c5c5c; // this was green but I could not figure how to make it orange for css and green for kids
text-decoration: none;
.myblue & {
color: orange;
}
}
As the "a" selector is contained within the ".names" selector though, this will result in a rendered rule of-
.myblue .names a {
color: orange;
}
As "names" is not a descendant of "myblue" in your DOM, the selector will not match - and this isn't what you want.
If you only want the rule to apply where both "names" and "myblue" are present I would write this-
.names {
min-height: 180px;
.photo {
margin-top: -21px;
}
img {
display: block;
border: 3px solid #282828;
margin: 0 auto;
}
h3 {
margin-top: 5px;
}
a {
font-size: 20px;
color: #5c5c5c; // this was green but I could not figure how to make it orange for css and green for kids
text-decoration: none;
}
&.myblue {
a {
color: orange;
}
}
}
The ampersand produces a combined selector, rather than the descendant selector you would get with a space (this is Sass only - not valid CSS).
Alternatively, if you want the "myblue" class selector to apply even without the "names" class, then simply do this-
.names {
min-height: 180px;
.photo {
margin-top: -21px;
}
img {
display: block;
border: 3px solid #282828;
margin: 0 auto;
}
h3 {
margin-top: 5px;
}
a {
font-size: 20px;
color: #5c5c5c; // this was green but I could not figure how to make it orange for css and green for kids
text-decoration: none;
}
}
.myblue {
a {
color: orange;
}
}
As the "myblue" selector appears after the "names" selector, the color property for the link will override the color set in "names" - leaving all other properties for the link and other elements intact. This solution simply utilises the CSS cascade to achieve the desired effect.

Making use of CSS vs Sass (SCSS) - base class issues and redundency

I'm trying to clean up my CSS to be cleaner by using SCSS.
Standard CSS:
.dark-hr,
.light-hr {
width: 100%;
height: 1px;
margin: 15px 0px;
}
.dark-hr {
background-color: #595959;
}
.light-hr {
background-color: #cccccc;
}
vs SCSS:
.generic-hr {
width: 100%;
height: 1px;
margin: 15px 0px;
}
.dark-hr {
#extend .generic-hr;
background-color: #595959;
}
.light-hr {
#extend .generic-hr;
background-color: #cccccc;
}
Is there any way to avoid creating the 'generic-hr' class that won't be used? I was hoping that some kind of nest would work well.
In this scenario the CSS is definitely way cleaner and more readable than SCSS.
Ideally I would need this to work in SCSS:
.## {
// base class that is not outputted
.dark-hr {
//attributes the extend the base class '.##'
}
.light-hr {
//attributes the extend the base class '.##'
}
}
OUTPUT:
.dark-hr, .light-hr {
//shared attributes defined by '.##'
}
.dark-hr {
// overrides
}
.light-hr {
// overrides
}
What you're wanting to use is an extend class (I call them "silent classes"), which is signified by using a % instead of a ..
hr%base {
width: 100%;
height: 1px;
margin: 15px 0px;
}
.dark-hr {
#extend hr%base;
background-color: #595959;
}
.light-hr {
#extend hr%base;
background-color: #cccccc;
}
Wouldn't you normally do something like this:
.generic-hr {
width: 100%;
height: 1px;
margin: 15px 0px;
&.dark {
background-color: #595959;
}
&.light {
background-color: #cccccc;
}
}
My pattern for this kind of thing is a mixin:
#mixin generic-hr {
width: 100%;
height: 1px;
margin: 15px 0px;
}
.dark-hr {
#include generic-hr;
background-color: #595959;
}
.light-hr {
#include generic-hr;
background-color: #cccccc;
}
This has the added advantage of being extensible, so if you find yourself needing several selectors with really similar properties you can add in variables:
#mixin generic-hr($background-color: transparent) {
width: 100%;
height: 1px;
margin: 15px 0px;
background-color: $background-color;
}
.dark-hr {
#include generic-hr(#595959);
}
.light-hr {
#include generic-hr(#cccccc);
}
.medium-hr {
#include generic-hr(#818181);
}

Resources