SCSS helper classes #mixin with dashes issue - css

I'm building a bunch of my own helper classes and for most CSS properties/values they are one word so my SCSS code below works fine but for something like justify-content: flex-start I've hit the wall.
I was using str-slice to take the first letter from the property and value but now I need to extend that if the property value uses a dash.
Any thoughts?
$positions: ('relative', 'absolute', 'fixed', 'sticky');
$flexPositions: ('flex-start', 'center', 'flex-end');
#mixin positionHelpers($breakpoint) {
#each $position in $positions {
.p\:#{str-slice($position, 0, 1)}\##{$breakpoint} {
position: #{$position} !important;
}
}
#each $position in $flexPositions {
.jc\:#{str-slice($position, 0, 1)}\##{$breakpoint} {
justify-content: #{$position} !important;
}
}
}
Added the following for more context:
$defaultBreakpoints: (
'xs': 'screen and (max-width: 767px)',
'sm': 'screen and (min-width:768px)',
'md': 'screen and (min-width:1024px)',
'lg': 'screen and (min-width:1201px)'
);
#each $breakpoint, $query in $defaultBreakpoints {
#if $breakpoint == 'xs' {
#include positionHelpers(#{$breakpoint})
} #else {
#media #{$query} {
#include positionHelpers(#{$breakpoint})
}
}
}

I created a function to split your string in 2 parts when there is a dash - in it.
#function split($string, $separator:"-") {
$index : str-index($string, $separator);
$newString:"";
#if($index!= null){
$str-1 : #{str-slice(str-slice($string, 1, $index - 1), 0, 1)};
$str-2 : #{str-slice(str-slice($string, $index + 1), 0, 1)};
$newString: $str-1 + $str-2
} #else{
$newString: str-slice($string, 0, 1);
}
#return $newString;
}
Then you can call it in your #each $position in $flexPositions {...}:
$positions: ('relative', 'absolute', 'fixed', 'sticky');
$flexPositions: ('flex-start', 'center', 'flex-end');
#mixin positionHelpers($breakpoint) {
#each $position in $positions {
.p\:#{str-slice($position, 0, 1)}\##{$breakpoint} {
position: #{$position} !important;
}
}
#each $position in $flexPositions {
$string: split($position); /*here you create a new string*/
.jc\:#{$string}\##{$breakpoint} {
justify-content: #{$position} !important;
}
}
}

Related

How to insert an ampersand conditionally in a SASS mixin?

Below is some sass Im trying out, The css generated is correct, Im just trying to reduce my mixin duplication. The two mixins genProps and genPropsAmp are exactly the same except that the Amp mixin uses the & to prefix the rule with &. I tried to just add another var to the original mixin $amp: false and prefix my rule with an if so it became #if $amp {&}.#{$class}-... but that didnt work nor did trying to have it as an interpolation. Is there away of conditionaly placing the ampersand so I can just reuse the one mixin?
SASS:
$max_size: 0;
$sub_suffixes: '', 'q', 'h', 't';
$sub_divs: '', '.25', '.5', '.75';
#mixin genProps($class, $props, $val_prefix: r, $max_size: $max_size, $sub_suffixes: $sub_suffixes) {
#for $i from 0 through $max_size {
#each $sub_suffix in $sub_suffixes {
.#{$class}-#{$i}#{$sub_suffix} {
#each $prop in $props {
#{$prop}: var(--#{$val_prefix}-#{$i}#{$sub_suffix});
}
}
}
}
}
#mixin genPropsAmp($class, $props, $val_prefix: r, $max_size: $max_size, $sub_suffixes: $sub_suffixes) {
#for $i from 0 through $max_size {
#each $sub_suffix in $sub_suffixes {
&.#{$class}-#{$i}#{$sub_suffix} {
#each $prop in $props {
#{$prop}: var(--#{$val_prefix}-#{$i}#{$sub_suffix});
}
}
}
}
}
.root{
#include genProps(f, font-size, a);
#include genPropsAmp(m, margin);
}
CSS:
/* without amp */
.root .f-0 {font-size: var(--a-0);}
.root .f-0q {font-size: var(--a-0q);}
/*...*/
/* with amp */
.root.m-0 {margin: var(--r-0);}
.root.m-0q {margin: var(--r-0q);}
/*...*/
You can use a ternary operator: if($amp, "&", "")
#mixin genProps($class, $props, $amp, $val_prefix: r, $max_size: $max_size, $sub_suffixes: $sub_suffixes) {
#for $i from 0 through $max_size {
#each $sub_suffix in $sub_suffixes {
#{if($amp, "&", "")}.#{$class}-#{$i}#{$sub_suffix} {
#each $prop in $props {
#{$prop}: var(--#{$val_prefix}-#{$i}#{$sub_suffix});
}
}
}
}
}
#mixin genProps($class, $props, $amp: false, $val_prefix: r, $max_size: $max_size, $sub_suffixes: $sub_suffixes) {
#for $i from 0 through $max_size {
#each $sub_suffix in $sub_suffixes {
#if $amp {
&.#{$class}-#{$i}#{$sub_suffix} {
#each $prop in $props {
#{$prop}: var(--#{$val_prefix}-#{$i}#{$sub_suffix});
}
}
} #else {
.#{$class}-#{$i}#{$sub_suffix} {
#each $prop in $props {
#{$prop}: var(--#{$val_prefix}-#{$i}#{$sub_suffix});
}
}
}
}
}
}
this is the best Iv got so far, not great as theres still a lot of duplication in the if elses but at least I only have one mixin now

How to make a mixin helper responsive using breakpoints?

I want to make this mixin responsive means it generate the media queries
based on breakpoints.
Here is my SCSS Code :
$grid-breakpoints: (
xs: 0,
sm: 576px,
md: 768px,
lg: 992px,
xl: 1200px,
xxl: 1400px
) !default;
#mixin overscroll-behavior-auto() {
-ms-scroll-chaining: chained;
overscroll-behavior: auto;
}
#mixin overscroll-behavior-contain() {
-ms-scroll-chaining: none;
overscroll-behavior: contain;
}
#mixin overscroll-behavior-none() {
-ms-scroll-chaining: none;
overscroll-behavior: none;
}
.overscroll-auto {
#include overscroll-behavior-auto();
}
.overscroll-contain {
#include overscroll-behavior-contain();
}
.overscroll-none {
#include overscroll-behavior-none();
}
#each $breakpoint in map-keys($grid-breakpoints) {
#include media-breakpoint-up($breakpoint) {}
}
I include my sass code thank you guys
Codepen
I made some modifications to the syntax of overscroll-behavior(). Mainly that its not overscroll-behavior-auto(), overscroll-behavior-contain() etc. any longer, but:
overscroll-behavior($behavior, $breakpoint);
This was necessary to not write the same code three times, since you can't generate mixins.
$overscrollBehavior: (
"auto": ["chained", "none" ],
"contain": ["none", "contain"],
"none": ["none", "none" ],
)!default;
$breakpoints: (
"xs": 0px,
"sm": 576px,
"md": 768px,
"lg": 992px,
"xl": 1200px,
"xxl": 1400px,
) !default;
#mixin overscroll-behavior($behavior, $breakpoint) {
$map: $overscrollBehavior;
#for $i from 1 through length($map) {
$label: nth(nth($map, $i), 1);
$values: nth(nth($map, $i), 2);
#if $behavior == $label {
$map: $breakpoints;
#for $i from 1 through length($map) {
$bp: nth(nth($map, $i), 1);
$bpValue: nth(nth($map, $i), 2);
#if $breakpoint == $bp {
#media (min-width: #{$bpValue}) {
-ms-scroll-chaining: unquote(nth($values, 1));
overscroll-behavior: unquote(nth($values, 2));
}
}
}
}
}
}
body {
#include overscroll-behavior(none, xs);
}
#media (min-width: 0px) {
body {
-ms-scroll-chaining: none;
overscroll-behavior: none;
}
}
If that's not quite what your looking for, let me know!

Generate a grid columns in scss, with media breakpoint particle at the end

I want to generate media queries grids having the below format:
I use a first large/desktop approach, with floats. It is intentional used instead of mobile-first approach.
#media (max-width: 36em) {
.col-1#sm {
width: 25%; }
.col-2#sm {
width: 50%; }
.col-3#sm {
width: 75%; }
.col-4#sm {
width: 100%; }
}
starting from the following grid-config map:
$grid-config: (
lg: (
width: em(960px),
columns: 16,
gutter-horizontal: rem(8px)
),
md: (
width: em(768px),
columns: 8,
gutter-horizontal: rem(8px)
),
sm: (
width: em(568px),
columns: 4,
gutter-horizontal: rem(8px)
),
);
For the first element in the map(lg) I don't want to add a media query.
The first element can change, so I don't want to do a string check (if bp !=='lg') if possible(not like in my code)
I have the following mixin to generate media-query:
#mixin media-breakpoint($bp) {
$columns: get-grid($bp, columns) !global;
#if $bp != 'lg2' {
#media (max-width: get-grid($bp, width)) {
#content
}
} #else {
#content
}
}
and another mixin to generate grid:
#mixin grid-generator {
#each $key, $value in $grid-config {
$bp: $key !global;
&--#{$key} {
#content;
}
}
}
Then I use:
.col {
#include grid-generator {
#include media-breakpoint($bp) {
$grid-columns: get-grid($bp, 'columns');
#for $i from 1 through $grid-columns {
&-#{$i} {
width: 100%/$grid-columns * $i;
}
}
}
}
}
but this generates the following format col--sm-1 and not col-1#sm.
The problems I have:
keep the cols inside media queryset, and add the media at the end.
compare to first in grid-config dynamic, check if $bp == first in map, instead of lg

Dynamic variable for class name in sass

Im creating for my project helper-class as margins, font-sizes etc and I got problem.
I want to define a class name, where property in class name should be assigned as "placeholder".
Currently as you can see it generates m-r-(amount) by range loop and it has huge limitation (time for compiling and range).
Is there any possibility to make $value variable act like
placeholder?
If not, how can I increase compile time in gulp?
Here is link for codepen http://codepen.io/anon/pen/NAmVVj
$break-small: 320px;
$break-medium: 768px;
$break-large: 1024px;
$break-extra: 1280px;
$baseSizes: (s: 1.5vw, m: 0.7vw, l: 5px, x: 5px);
$fontSizes: (s: 4.7vw, m: 2.08vw, l: 16px, x: 16px);
#mixin respond-to($media) {
#if $media == s {
#media (max-width: $break-medium) {
#content;
}
}
#else if $media == m {
#media (min-width: $break-medium) and (max-width: $break-large) {
#content;
}
}
#else if $media == l {
#media (min-width: $break-large) and (max-width: $break-extra) {
#content;
}
}
#else if $media == x {
#media (min-width: $break-extra) {
#content;
}
}
}
$range: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10;
$properties: (m: "margin", p: "padding", b: "border");
$directions: (t: "top", b: "bottom", l: "left", r: "right", a: "all");
#each $value in $range {
#each $breakpoint, $size in $baseSizes {
#each $aliasProp, $propValue in $properties {
#each $aliasFrom, $fromValue in $directions {
#if $aliasFrom == a {
.#{$aliasProp}-#{$aliasFrom}-#{$value} {
$final: calc((#{$value} * #{$size}) * 2);
#{$propValue}: $final;
}
}
#if $aliasFrom != a {
.#{$aliasProp}-#{$aliasFrom}-#{$value} {
$final: calc((#{$value} * #{$size}) * 2);
#{$propValue}-#{$fromValue}: $final;
&-#{$breakpoint} {
#include respond-to($breakpoint) {
$final: calc((#{$value} * #{$size}) * 2);
#{$propValue}-#{$fromValue}: $final !important;
}
}
}
}
}
}
}
}
Thanks for answers!
I solved it by processing my library through node-sass as it takes ~ 0.2s while gulp-sass is ~ 23sec, but I'm still curious about question no1.

SASS and data attribute multiple

I have a problem with the nesting of SAS to make multiple selections, nose much about it, I hope you can help me and understand (because I do not write very good English).
SASS mixin:
#mixin data($x) {
$sel: &;
$collector: ();
#for $i from 1 through length($sel) {
$s: nth($sel, $i);
$last: nth($s, -1);
#if str-slice($last, -1) == "]" {
// if is just the bare attribute with no value, $offset will be -1, otherwise it will be -2
$offset: -1;
$current-x: $x;
#if str-slice($last, -2) == '"]' {
// this attribute already has a value, so we need to adjust the offset
$offset: -2;
} #else {
// no attribute value, so add the equals and quotes
$current-x: '="' + $x + '"';
}
$last: str-slice($last, 1, $offset - 1) + $current-x + str-slice($last, $offset);
$collector: append($collector, set-nth($s, -1, $last), comma);
} #else {
// following line will append $x to your non-attribute selector
$collector: append($collector, selector-append($s, $x), comma);
// the following line will not change your non-attribute selector at all
//$collector: append($collector, $s, comma);
}
}
#at-root #{$collector} {
#content;
}
}
SASS:
[data-content] {
#include data("content") {
background: black;
}
}
Output:
[data-content="content"] {
background: black;
}
The problem is I can not nest more than one item, for example does not work:
[data-content] {
#include data("content", "menu") {
background: black;
}
}
Output:
[data-content="content"],
[data-content="menu"] {
background: black;
}
Any way to solve?
You can always do something like this if you don't mind having to specify your selectors instead of passing them through as variables.
[data-content="content"], [data-content="menu"]{
#include data() {
background: black;
}
}

Resources