Variables in Bourbon size() mixin - css

I've recently started using an updated version of the Bourbon SASS plugin. I've previously used a custom mixin to set the width and height using the following syntax;
$width: 350;
$height: 200;
.wrapper {
#include size($width $height);
}
This would assume px as the unit of measurement. However with the updated version of Bourbon, it has it's own size() mixin which doesn't work quite the same.
I cannot figure out how to use variables for the width and height properties. I've tried the following to no avail;
#include size(#{$width}px #{$height}px); - interpolation doesn't appear to work directly in the mixin. I tried doing something similar by making a new variable that had the unit on the end.
$width: 350;
$height: 200;
$width_str: #{$width}px;
$height_str: #{$height}px;
.wrapper {
#include size($width_str $height_str);
}
Finally, I tried setting the variables like this as I've used similar syntax elsewhere (albeit not for a mixin);
$width_str: ($width) + px;
$height_str: ($height) + px;
I don't get any errors when compiling the SCSS, instead the width and heigth properties are just missing from the stylesheet. I can confirm that using string values like so: #include size(350px 200px); does work, I just cannot get variables to play nice with this mixin. Any ideas?
UPDATE: While I still can't get the bourbon size mixin to work with variables, I can still use the custom one I was using previously, as long as that's defined after including bourbon in my project. For reference, this is the size mixin I use, works with everything I've ever thrown at it;
#mixin size($size) {
#if length($size) == 1 {
#if $size == auto {
width: $size;
height: $size;
}
#else if unitless($size) {
width: $size + px;
height: $size + px;
}
#else if not(unitless($size)) {
width: $size;
height: $size;
}
}
// Width x Height
#if length($size) == 2 {
$width: nth($size, 1);
$height: nth($size, 2);
#if $width == auto {
width: $width;
}
#else if not(unitless($width)) {
width: $width;
}
#else if unitless($width) {
width: $width + px;
}
#if $height == auto {
height: $height;
}
#else if not(unitless($height)) {
height: $height;
}
#else if unitless($height) {
height: $height + px;
}
}
}

In the code of new Bourbone library you can find the following code for the "size" mixin:
#if $height == auto or (type-of($height) == number and not unitless($height)) {
height: $height;
}
#if $width == auto or (type-of($width) == number and not unitless($width)) {
width: $width;
}
The main problem is about "unitless" function that returns:
unitless(100) => true
unitless(100px) => false
that's why you have to always pass into the mixin values such as "350px", "250px"
You can try to use the following "size" mixin%
#mixin size($size) {
$height: nth($size, 1);
$width: $height;
#if length($size) > 1 {
$height: nth($size, 2);
}
#if $height == auto or type-of($height) == number {
#if unitless($height){
height: ($height) + px;
} #else {
height: $height;
}
}
#if $width == auto or type-of($width) == number {
#if unitless($width){
height: ($width) + px;
} #else {
height: $width;
}
}
}

Related

Mixin: Add property dynamically

Using Mixin, I want to determine a value between two entries and add it to a specific property.
Here is a dummy example:
#mixin min($property, $min1, $min2) {
#if ($min1 > $min2) {
$property: $min2;
}
#else {
$property: $min1;
}
}
.test {
#include min(width, 11px, 13px);
}
.test1 {
#include min(background-size, 30px, 13px);
}
.test2 {
#include min(height, 8px, 50px);
}
I would like to have the ouput:
width: 11px;
background-size: 13px;
height: 8px;
The problem is that $property: $min1; sets min1 value to property and I would like to return a literal.
How can I do that using mixin ?
You're almost there. You must use interpolation on the $property variable:
#mixin min($property, $min1, $min2) {
#if ($min1 > $min2) {
#{$property}: $min2;
}
#else {
#{$property}: $min1;
}
}

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

SASS offset position mixin troubles

I've been trying to make an offset positioning mixin for the past couple of hours. I've been struggling with lots of errors, I cant understand what is wrong.
Here is the latest version,
#function is-offset-prop-valid($value) {
$values: auto initial inherit 0;
#return (type-of($value) == number and not unitless($value))
and (index($values, $value) != false);
}
#mixin position($position, $args) {
$offsets: top right bottom left;
#each $offset in $offsets {
$i: index($args, $offset);
#if $i == length($args) {
#error "Empty offset values not allowed";
} else {
#if is-offset-prop-valid(nth($args, $i+1)) {
#{$offset}: nth($args, $i+1);
} else {
#error "Set value #{nth($args, $i+1)} not a valid property for #{$offset}";
}
}
}
positon: $position;
}
Normally I would have the nth($args, $i + 1) set as variable, but for the sake of this example, I left it like that.
When I use the mixin
.abs {
#include position(absolute, top 10px);
}
I get this error from the inner if statement:
Set value 10px not a valid property for top
I fixed your code and rewrited it a bit. Sassmeister demo.
At first, is-offset-prop-valid function is now more readable.
Secondly, mixin position does loop through arguments ($args), not through $offsets. And I added more argument checks (look at comments). And you need to write # symbol before else: #else.
#function is-offset-prop-valid($value) {
$values: auto initial inherit 0;
$is-numder: type-of($value) == number;
$is-unitless: unitless($value);
$match-default-values: index($values, $value) != null;
#return ($is-numder and not $is-unitless) or $match-default-values;
}
#mixin position($position, $args...) {
$offsets: top right bottom left;
#if length($args) == 0 {
#error "Empty offset values not allowed.";
}
#each $arg in $args {
// Check offset key-value pair
#if length($arg) != 2 {
#error "Invalid pair offset-name: offset-value.";
}
$offset: nth($arg, 1);
$value: nth($arg, 2);
// Check offset name parameter
#if index($offsets, $offset) == null {
#error "Invalid offset name: `#{$offset}`.";
}
// Check offset value parameter
#if not is-offset-prop-valid($value) {
#error "Set value `#{$value}` not a valid property for `#{$offset}`.";
}
#{$offset}: $value;
}
position: $position;
}
.abs {
#include position(absolute, top 10px, left 23px);
}
But it seems to me that a simple set position is much simpler and more understandable:
.abs {
top: 10px;
left: 23px;
position: absolute;
}

sass how use a #for in a #mixin

I using sass to make a grid, i am using the logic bellow to define the columns in many screens and sizes.
#each $breakpoint, $container-size in $grid-containers {
#include breakpoint($breakpoint){
#for $column from 1 through $grid-columns { /* This loop will define the columns */
#if map-get($grid-breakpoints, $breakpoint) != none{
.col-#{$breakpoint}-#{$column} {
flex-basis: percentage($column / $grid-columns);
padding-left: $grid-gutter;
padding-right: $grid-gutter;
}
}
#else {
.col-#{$column} {
flex-basis: percentage($column / $grid-columns);
padding-left: $grid-gutter;
padding-right: $grid-gutter;
}
}
}
}
}
Now i wanna transform this code into a mixin and define the column like this:
#include column-rule(.col) {
flex-basis: percentage($column / $grid-columns); /* $column is undefined */
padding-left: $grid-gutter;
padding-right: $grid-gutter;
}
/* Another sample */
#include column-rule(.order) {
order: $column; /* $column is undefined */
}
But as you can see i need use variable $column who was define into a loop. I can get the value of $column using a mixin?

Using SASS's #for for multiple selectors and 1 body [duplicate]

I'm working with the SCSS syntax of SASS to create a dynamic grid system but I've hit a snag.
I'm trying to make the grid system completely dynamic like this:
$columns: 12;
then I create the columns like this:
#mixin col-x {
#for $i from 1 through $columns {
.col-#{$i} { width: $column-size * $i; }
}
}
Which outputs:
.col-1 {
width: 4.16667%;
}
.col-2 {
width: 8.33333%;
}
etc...
This works well but what I want to do next is dynamically generate a long list of column classes separated by commas based on the number of $columns chosen - e.g I want it to look like this:
.col-1,
.col-2,
.col-3,
.col-4,
etc... {
float: left;
}
I've tired this:
#mixin col-x-list {
#for $i from 1 through $columns - 1 {
.col-#{$i}-m { float: left; }
}
}
but the output is this:
.col-1 {
float: left;
}
.col-2 {
float: left;
}
etc...
I'm a little stuck on the logic here as well as the SCSS syntax required to create something like this.
Does anyone have any ideas?
I think you may want to take a look at #extend. If you set that up something like:
$columns: 12;
%float-styles {
float: left;
}
#mixin col-x-list {
#for $i from 1 through $columns {
.col-#{$i}-m { #extend %float-styles; }
}
}
#include col-x-list;
It should render in your css file as:
.col-1-m, .col-2-m, .col-3-m, .col-4-m, .col-5-m, .col-6-m, .col-7-m, .col-8-m, .col-9-m, .col-10-m, .col-11-m, .col-12-m {
float: left;
}
#extend in the docs.
There's also a way to do what your question is specifically asking for: generate (and use) a list of classes with commas separating them. D.Alexander's response totally works in your situation, but I'm posting this alternative in case there's another use case for someone looking at this question.
Here's a Pen demonstrating: http://codepen.io/davidtheclark/pen/cvrxq
Basically, you can use Sass functions to achieve what you want. Specifically, I'm using append to add classes to my list, separated by commas, and unquote to avoid compilation conflicts with the period in the classnames.
So my mixin ends up looking like this:
#mixin col-x {
$col-list: null;
#for $i from 1 through $columns {
.col-#{$i} {
width: $column-size * $i;
}
$col-list: append($col-list, unquote(".col-#{$i}"), comma);
}
#{$col-list} {
float: left;
}
}
thnx to #davidtheclark here is a more generic version:
#mixin attr-x($attr, $attr-count: 10, $attr-steps: 10, $unit: '%') {
$attr-list: null;
#for $i from 1 through $attr-count {
$attr-value: $attr-steps * $i;
.#{$attr}#{$attr-value} {
#{$attr}: #{$attr-value}#{$unit};
}
$attr-list: append($attr-list, unquote(".#{$attr}-#{$attr-value}"), comma);
}
#{$attr-list} {
//append style to all classes
}
}
Use it like this:
#include attr-x('margin-left', 6, 5, 'px');
//or
#include attr-x('width');
The result looks like this:
.margin-left5 {
margin-left: 5px; }
.margin-left10 {
margin-left: 10px; }
...
.margin-left30 {
margin-left: 30px; }
.width10 {
width: 10%; }
.width20 {
width: 20%; }
...
.width100 {
width: 100%; }

Resources