how to get the direct parent in sass interpolation of & - css

Is there a way to use {$} to get the most direct parent?
In the example below '&#{&}' is not working as I expected, I managed to work around it using mixin.
#mixin modifier($modifier, $block: &) {
&#{"."+$block}--#{$modifier} {
#content;
}
}
.namespace{
$button : 'btn';
.#{$button} {
line-height: 1;
#include modifier('big', $button){ // working but not clean
padding-top: 8px;
}
&#{&}--big{ // not working as {&} is interpolated to namespace .btn
padding-top: 12px;
}
}
}
Compiled to:
.namespace .btn {
line-height: 1;
}
.namespace .btn.btn--big {
padding-top: 8px;
}
.namespace .btn.namespace .btn--big {
padding-top: 12px;
}

The construct looks a bit odd to me – but you could do it like:
.namespace {
$class: ".btn";
#{$class} { line-height: 1; }
#{$class}#{$class}--big { padding-top: 8px; }
& #{$class}#{&} #{$class}--big { padding-top: 12px; }
}
...or using selector append
.namespace .btn {
line-height: 1;
#at-root {
#{selector-append(&,".btn")}--big{ padding-top: 8px; }
#{selector-append(&,&)}--big{ padding-top: 12px; }
}
}
both compiling to:
.namespace .btn { line-height: 1; }
.namespace .btn.btn--big { padding-top: 8px; }
.namespace .btn.namespace .btn--big { padding-top: 12px; }

Related

How to inject literal string into scss #mixin

Considering this following scss code:
#mixin homeSlider(
$dim: 150px,
$h1: "h1 { font-size: 4em; margin-top: 0; }"
){
section {
margin-top: -$dim;
}
$h1;
}
#include homeSlider( $dim: 50px, $h1: "h1 { font-size: 3em; margin-top: 0; }" )
I need to know how is it possible to achieve my goal
Try this
#mixin homeSlider($dim, $h1-font-size){
section {
margin-top: -$dim;
h1 {
font-size: $h1-font-size;
margin-top: 0;
}
}
}
#include homeSlider(50px, 3em;) /* $dim = 50px - $h1-font-size = 3em; */

How to overwrite Referencing Parent Selector using Mixin in SCSS

I had a common used component and its scss is like this:
.component {
margin-right: 12px;
&.specified-use-case {
margin-right: 30px;
&:nth-child(odd) {
margin-right: 70px
}
}
}
Now I want everything has same style in mobile view
.component {
margin-right: 12px;
// some predefined mixin
#include viewport(mobile) {
margin-right: 0px;
margin-bottom: 14px;
}
&.specified-use-case {
margin-right: 30px;
&:nth-child(odd) {
margin-right: 70px
}
}
}
But this can't change style for "specified-use-case" in mobile view. In order to do it I have to
.component {
margin-right: 12px;
// some predefined mixin
#include viewport(mobile) {
margin-right: 0px;
margin-bottom: 14px;
}
&.specified-use-case {
margin-right: 30px;
#include viewport(mobile) {
margin-right: 0px;
margin-bottom: 14px;
}
&:nth-child(odd) {
margin-right: 70px
#include viewport(mobile) {
margin-right: 0px;
margin-bottom: 14px;
}
}
}
}
Which just doesn't seem right to me. Is there a better way to define mobile view css just for once?
According to CSS' specificity rules (try this calculator) you unfortunately need to repeat yourself. What your SCSS interpreter does is just compiling what you've written to standard CSS, which will look something akin to:
.component {
margin-right:12px
}
#media (max-width:768px) {
.component {
margin-right:0px;
margin-bottom:14px
}
}
.component.specified-use-case {
margin-right:30px
}
#media (max-width:768px) {
.component.specified-use-case {
margin-right:0px;
margin-bottom:14px
}
}
.component.specified-use-case:nth-child(odd) {
margin-right:70px
}
#media (max-width:768px) {
.component.specified-use-case:nth-child(odd) {
margin-right:0px;
margin-bottom:14px
}
}
As you can see, you're overriding each class with a #media ruleset just after it has been declared. And since I'm a big proponent to never use !important (because you'll open a pandoras box), the only way you can shorten your SCSS is doing:
.component {
margin-right: 12px;
// some predefined mixin
#include viewport(mobile) {
margin-right: 0px;
margin-bottom: 14px; // only need to define margin-bottom once, here.
}
&.specified-use-case {
margin-right: 30px;
#include viewport(mobile) {
margin-right: 0px;
//margin-bottom: 14px;, remove this
}
&:nth-child(odd) {
margin-right: 70px
#include viewport(mobile) {
margin-right: 0px;
//margin-bottom: 14px;, remove this
}
}
}
}
Hope this helps!
You can put the rules inside of the media query:
#include viewport(mobile) {
margin-right: 0px;
margin-bottom: 14px;
&.specified-use-case {
margin-right: 0px;
margin-bottom: 14px;
}
}
seems like sass is wrong because you specify margins above a breakpoint, try this:
.component {
margin-right: 12px;
&.specified-use-case {
margin-right: 30px;
&:nth-child(odd) {
margin-right: 70px
}
}
// some predefined mixin
#include viewport(mobile) {
margin-right: 0px;
margin-bottom: 14px;
}
}

Conditional parameters within LESS mixin

Problem
I've created the following mixin:
.type(#style;#mb) {
& when (#style = hero) {
margin-bottom: #mb;
font-size: 2.625rem;
line-height: 1.238095238;
}
}
Now this does mostly what I want. The problem I am having is sometimes I will want to declare a #mb value, but many times I will not. In those instances I will want to fallback to a pre-determined value for each #style parameter.
For example:
For hero, #mb default is margin-bottom: 1.25rem;
For page, #mb default is margin-bottom: 1.125rem;
etc
Desired Outcome
The desired outcome is as follows:
.sample-class-01 { .type(hero); }
.sample-class-02 { .type(page,0); }
and I would get the following output:
.sample-class-01 {
margin-bottom: 1.25rem;
font-size: 2.625rem;
line-height: 1.238095238;
}
.sample-class-02 {
margin-bottom: 0;
font-size: 2rem;
line-height: 1.3125;
}
How do I create this mixin?
Just make the mixin specialization/overloading for each style set:
.type(hero, #mb: 1.25rem) {
margin-bottom: #mb;
font-size: 2.625rem;
line-height: 1.238095238;
}
.type(not-a-hero, #mb: 2.22rem) {
margin-bottom: #mb;
font-size: 3.333rem;
line-height: 4.444444444;
}
// etc.
Ref.:
Argument
Pattern-matching
Mixins with Multiple
Parameters
Something like this:
.type(#style; #mb: '') {
& when (#style = hero) {
font-size: 42px; // 42px
line-height: 52px; // 52px
& when not (#mb = '') { margin-bottom: #mb; }
& when (#mb = '') { margin-bottom: 1.25rem; }
}
& when (#style = footer) {
font-size: 22px; // 42px
line-height: 32px; // 52px
& when not (#mb = '') { margin-bottom: #mb; }
& when (#mb = '') { margin-bottom: 1.125rem; }
}
}
.sample-class-1 { .type(hero); }
.sample-class-2 { .type(hero,0); }
.sample-class-3 { .type(hero,3rem); }
.sample-class-4 { .type(footer); }
.sample-class-5 { .type(footer,0); }
.sample-class-6 { .type(footer,3rem); }
Should compile to:
.sample-class-1 {
font-size: 42px;
line-height: 52px;
margin-bottom: 1.25rem;
}
.sample-class-2 {
font-size: 42px;
line-height: 52px;
margin-bottom: 0;
}
.sample-class-3 {
font-size: 42px;
line-height: 52px;
margin-bottom: 3rem;
}
.sample-class-4 {
font-size: 22px;
line-height: 32px;
margin-bottom: 1.125rem;
}
.sample-class-5 {
font-size: 22px;
line-height: 32px;
margin-bottom: 0;
}
.sample-class-6 {
font-size: 22px;
line-height: 32px;
margin-bottom: 3rem;
}
Less2css link

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.

SASS: content block mixin (or placeholder) that takes contextual selectors and appends them to selector in mixin

I want to do something like this:
#mixin context($size) {
body.#{$size} {
#content
}
}
div {
span {
font-size: 2em;
#include context('large') {
& {
font-size: 5em;
}
}
}
}
To produce:
div span {
font-size: 2em;
}
body.large div span {
font-size: 5em;
}
What it ACTUALLY (predictably) produces:
div span {
font-size: 2em;
}
div span body.large {
font-size: 5em;
}
I could just replicate the selectors inside different mixins, but given that selectors could be complex that's a lot of extra junk:
#include context('large') {
div {
span {
font-size: 5em;
}
}
}
I could make the selectors into mixins so I don't have to repeat them each time, but...
Isn't there a way to use placeholders, maybe in combination with mixins, to get what I want in the first two code blocks above?
You just need to move the & to be part of the mixin:
#mixin context($size) {
body.#{$size} & {
#content
}
}
div {
span {
font-size: 2em;
#include context('large') {
font-size: 5em;
}
}
}
Output:
div span {
font-size: 2em;
}
body.large div span {
font-size: 5em;
}
As of Sass 3.4, you can write this to work both inside a selector and at the root of the document:
#mixin optional-at-root-nest($sel) {
#at-root #{if(not &, $sel, selector-nest($sel, &))} {
#content;
}
}
#mixin context($size) {
#include optional-at-root-nest('body.#{$size}') {
#content
}
}
div {
span {
font-size: 2em;
#include context('large') {
font-size: 5em;
}
}
}
#include context('large') {
font-size: 2em;
}

Resources