Is it possible to manipulate with #content magic variable in SASS?
I would like to replace some stuff in here before output.
Or maybe can I fill some variable with it?
The conclusion is that, I want to make an mixin #important that create both versions. Important, and no-important.
Input
.test {
#include important {
color: red;
text-align: left;
}
}
Expected output
.test {
color: red;
text-align: left;
}
.test-i {
color: red !important;
text-align: left !important;
}
No, you can't. But I quickly wrote you a mixin to make it work. It doesn't accepts multiple properties (yet).
First Note: I changed the mixin it now does accept multiple properties. Here is the Codepen.
Second Note: I updated the mixin adding multiple properties does no longer compile to different classes for each property, instead you get two versions, one without the !important suffix and one with.
This is the mixin:
#function return($state) {
#return if($state == '', '', '-i');
}
#mixin loop($name, $items...) {
#each $item in $items / 2 {
#each $state in ('', '!important') {
$suffix: return($state);
.#{$name}#{$suffix} {
#for $i from 1 through (length($items) / 2) {
#{nth($items, ($i * 2) - 1)}: #{nth($items, ($i * 2))} #{$state};
}
}
}
}
}
This is how you include it:
// #include loop([classname], [property], [value]);
#include loop(whateverClassname, color, red);
This is what it compiles to:
.whateverClassname {
color: red ;
}
.whateverClassname-i {
color: red !important;
}
This is what it now compiles to, when you use multiple properties at once:
#include loop(whateverClassname, color, red, background-color, green, display, flex);
.whateverClassname {
color: red ;
background-color: green ;
display: flex ;
}
.whateverClassname-i {
color: red !important;
background-color: green !important;
display: flex !important;
}
Conclusion: it works as expected and does no longer bloat your CSS.
Hope I could help you at least a little ;-)
Related
Another problem here.. my team wants to use borders in different widths, colors and positions. So, I made this:
$position-list: top right bottom left;
$colors-list: fff ccc ddd eee;
#for $i from 1 through 3 {
#each $position in $position-list {
#each $color in $colors-list {
.border-#{$position}-#{$i}-#{$color} {
border-#{$position}: #{$i}px solid #{"#"}#{$color} !important;
}
}
}
}
This works great, however, I want to include the colors as variables from my colors.scss sheet ($light-color, $dark-color etc). The problem is that the hashtags from the colors.scss sheet will be transfered as well ($dark-color: #000), so it will most likely generate a weird selector (.border-top-1-#000) or doesn't compile at all.
Is there a way of stripping the variables from the colors.scss sheet of their hashtags before putting them in the selector? Or does anyone have a different/better approach?
We can convert the color to a string (#inspect) and slice it (#str-slice).
$dark-color: #000;
$light-color: #fff;
$abc-color: #abc;
$position-list: top right bottom left;
$colors-list: $dark-color $light-color $abc-color;
#for $i from 1 through 3 {
#each $position in $position-list {
#each $color in $colors-list {
$stripped-color: str-slice(inspect($color), 2);
.border-#{$position}-#{$i}-#{$stripped-color} {
border-#{$position}: #{$i}px solid #{$color} !important;
}
}
}
}
Output (example):
.border-top-1-abc {
border-top: 1px solid #abc !important;
}
I'm trying to create a little overview for all the colors we use in our corporate identity. All our colors have been defined in _settings-colors.scss, and the only reason I need this bit of css is for the library, where the colors need to be listed.
What I have now is as follows:
$colors-brand: color-brand, color-brand-40, color-brand-60, color-brand-70;
.prfx-color {
display: block;
height: 5rem;
width: 100%;
#each $color in $colors-brand {
&--#{$color} {
background-color: #{'$'+$color};
&::after {
content: '$'+$color;
}
}
}
}
These color-brand variables are set in another file which I'm including in this scss file.
The code above outputs this:
.prfx-color {
display: block;
height: 5rem;
width: 100%;
}
.prfx-color--color-brand {
background: $color-brand;
}
.prfx-color--color-brand::after {
content: "$color-brand";
} [...etc]
What I'm after however, is this:
.prfx-color--color-brand {
background: #00ff11; // don't worry, brand is not actually this color
}
The problem I'm having is that the $color-brand variable isn't interpreted as a sass variable anymore, but is a literal value. I need the #hheexx that this variable refers to!
All the solutions I've found so far consist of using two lists, or a key-value pair. In my situation these variables have already been set once, and I want a solution where I don't want to have to manually edit the library if the colors change.
Is this at all possibe, or am I too greedy here?
And I realized I overcomplicated it. You don't need any extra functions because the #each is designed to work with maps and iterating over multiple values.
$cool: blue;
$mad: red;
$colors: (
cool: $cool,
mad: $mad
);
.prfx-color {
#each $key, $val in $colors {
&--#{$key} {
background-color: $val;
&::after { content: "$#{$key}"; }
}
}
}
You could use a map.
Here's a sassmeister playground for you.
$cool: blue;
$mad: red;
$colors: (
cool: $cool,
mad: $mad
);
.prfx-color {
#each $color in map-keys($colors) {
&--#{$color} {
background-color: map-get($colors, $color);
&::after { content: "$#{$color}"; }
}
}
}
I'm creating a mixin called static() that is used inside another mixin to separate the static properties out into placeholders, so that those properties aren't repeated in the output every time a mixin is used. Here's how you would use it in a mixin called button(), for example:
#mixin button($color) {
#include static('button') {
border: 1px solid;
border-radius: 5px;
padding: .25em .5em;
&:hover {
cursor: pointer;
}
}
background-color: $color;
&:hover {
background-color: mix(black, $color, 15%;
}
}
Here's the code for the static() mixin:
#mixin static($mixin-name, $extend: true) {
// set global $Placeholder-Selectors if it doesn't already exist
$Placeholder-Selectors: () !global !default;
$selector: map-get($Placeholder-Selectors, $mixin-name);
#if $extend == true {
#if $selector == null {
$selector: unique-id();
$Placeholder-Selectors: map-merge($Placeholder-Selectors, ($mixin-name: $selector)) !global;
#at-root %#{$selector} {
#include static($mixin-name, false) {
#content;
};
}
}
#extend %#{$selector};
} #else {
#content;
}
}
The only purpose of the variable $mixin-name is to make sure the declarations of the created placeholder are not overwritten by another placeholder of the same name. My assumption is that the best way to ensure this is to use the name of the mixin itself for the $Placeholder-Selectors' key (since this will be unique to the mixin).
Question:
If that assumption is correct, I don't want to have to type out the name of the mixin I'm using (as in "#include static('button')")...so, in the static() mixin, is there a way to dynamically determine the name of the mixin that static() is being used inside?
Or, is there another way to ensure a placeholder that is unique per-mixin?
No. Sass does not have a way to get any of the names of the mixins used.
That said, you're over-engineering. All you need to do is setup your extend selector outside of the mixin.
%common-button-styles {
border: 1px solid;
border-radius: 5px;
padding: .25em .5em;
&:hover {
cursor: pointer;
}
}
#mixin button($color) {
color: $color;
#extend %common-button-styles;
&:hover {
background-color: mix(black, $color, 15%);
}
}
If you're jumping through all of these hoops in an attempt to avoid creating duplicate extend only selectors via multiple imports, what you're looking for is called import once. If you're a Compass user, 1.0 includes an extension by default that does this. If not, a quick search will show you a few different ways of implementing such a feature.
I'm trying to make a mixin that will let me create adapted blocks of code depending on what variable name you up in.
$foo: #00A9EC;
#mixin menu-color($color) {
.color-#{$color} a.level2,
.color-#{$color} a.level2:visited {
color: $color;
&:hover {
color: adjust-lightness($color, 10); }
&:active {
color: adjust-lightness($color, -10); } } }
#include menu-color($foo);
outputs:
.color-foo a.level2,
.color-foo a.level2:visited {
color: #00A9EC; }
.color-foo a.level2:hover,
.color-foo a.level2:visited:hover {
color: #20C0FF; }
.color-foo a.level2:active,
.color-foo a.level2:visited:active {
color: #0084B9; }
In sass you can do this using map, you just pass the variable name instead of the variable itself:
$colors: (
-black: #000,
-blue: #088DC6
);
#mixin generateBgColor($colorName) {
.bg-color#{$colorName} {
background-color: map-get($colors, $colorName);
}
}
#include generateBgColor("-blue");
This will generate class:
.bg-color-blue {
background-color: #088DC6;
}
You achieve this also in less with standard variables, just by using curly brackets and double at character:
#blue: #088DC6;
.generate-bg-color(#color) {
.bg-color-#{color} {
background-color: ##color;
}
}
.generate-bg-color(~"blue");
You should not name CSS classes after specific colors. You would regret that. Just think, if you want to make the color red later on, you would need to go back over all your html and change the classes.
The reason we have CSS is so that you don't have to embed style information in the markup.
Use a semantic class the describes the data, not how it is displayed:
$foo: #00A9EC;
#mixin menu-color($name, $color) {
.custom-#{$name} a.level2,
.custom-#{$name} a.level2:visited {
color: $color;
&:hover {
color: adjust-lightness($color, 10); }
&:active {
color: adjust-lightness($color, -10); } } }
#include menu-color(profile, $foo);
And then in your HTML <div class="custom-profile">.
That way, two years from now when you want to make it black, and underlined (or whatever), you don't have to dig through your html and add a new '.underlined-and-black-color` class to all of those elements. You just change your SCSS in one place.
I'm trying to make a SCSS stylesheet easily configurable by defining a set of constants that will be used in a number of mixins and with the Compass library. Ideally, I'd like to be able to do the following:
$item-bgs: linear-gradient(white, black), #ccc;
#mixin some-mixin() {
#include background-with-css2-fallback($item-bgs*);
}
The background-with-css2-fallback is a Compass mixin that accepts up to 10 params. I'm assuming that SASS does not currently support passing a list parameter as the argument list, otherwise Compass would probably use it, but I'm wondering if I can get the $item-bgs list to be the first 2 arguments to the background-with-css2-fallback mixin. Is there a way to do this currently, or is it even planned for SASS in the future?
It may not be supported by SASS natively, but Compass does support passing a list as the first argument to the background-with-css2-fallback mixin. If you look at the source for the mixin, you'll see that it uses a compact function that handles the logic for collapsing the arguments into a single list, whether passed individually or in a single list parameter.
For example, this works fine for me:
#import "compass";
$item-bgs: (linear-gradient(white, black), #ccc);
.test {
#include background-with-css2-fallback($item-bgs);
}
Examples of useing maps as arguments:
Example 1 (list)
#mixin transition($property...){
#if $property {
transition-property: $property;
}
#else {
transition-property: all;
}
transition-timing-function: ease-in-out;
transition-duration: .3s;
transition-delay: 0;
}
.btn {
color: black;
border: 1px solid black;
#include transition(color, border-color);
&:hover {
color: red;
border-color: red;
}
}
Example 2 (Custom params)
#use 'sass:meta';
#mixin example2($args...) {
#each $key, $value in meta.keywords($args) {
#{$key}: #{$value};
}
}
.shape {
#include example2($width:200px, $height:100px);
}
Example 3 (map)
#mixin colors($args:()) {
#if length($colors) > 0 {
#each $key, $val in $args{
.txt-#{$key} {
color: #{$value};
}
.bg-#{$key} {
background-color: #{$value};
}
}
}
}
$colors_map: (
primary: blue,
secondary: green,
accent: red,
light: white,
dark: black
);
#include colors($colors_map);