I'm new to Sass, so if this isn't the best way of doing this type of thing, I apologise!
So, I've got a mixin for button style, like so:
#mixin button ($bg, $color, $padding, $display: inline, $radius: 0, $transition: 0.2s) {
background: $bg;
#if $radius > 0 {
#include border-radius($radius)
}
color: $color;
#if $display != inline {
display: $display;
}
#if $padding > 0 {
padding: $padding;
}
text-decoration: none;
#include transition(all, $transition, linear);
&:hover {
#if lightness($bg) > 50% {
background: darken($bg, 10%);
} #else {
background: lighten($bg, 10%);
}
}
}
and a button, like so:
.btn {
#include button(#095d94, #fff, 10px, inline-block);
}
But, now I need another button with a different background colour. So what I'm wondering is: is there a way to extend a class, and also just change an argument of the mixin that that class includes, without having to do this:
.btn2 {
#extend .btn;
background: #bad78d;
&:hover {
background: darken(#bad78d, 10%);
}
}
Is it possible to feed in another background colour? Something like,
.btn2 {
$bg: #bad78d; //i know this doesn't work
#extend .btn;
}
or like,
.btn2 ($bg: #bad78d) {
#extend .btn; //this one doesn't even make sense, but I think I'm explaining what I need... ish.
}
I think you have two options here.
Also you try to keep it dry, there is nothing too wrong about repading sometimes. So if your mixin is not too huge it'll be ok to this:
.btn {
#include button(#095d94, #fff, 10px, inline-block);
}
.btn2 {
#include button(#bad78d, #fff, 10px, inline-block);
}
But This will only be required if the difference between .btn and .btn2 is big.
If you just want to change certain properties, you may also just use the classig cascading.
.btn,.btn2 {
#include button(#095d94, #fff, 10px, inline-block);
}
.btn2 {
background-color:#bad78d;
...
}
Related
Imagine a set of rules like the ones shown below:
span, div { color: red; }
span { background: white; }
div { background: black; }
Is it possible to wrap them under 1 SCSS rule? Something in the form of:
span, div {
& { color: red; }
&:not(div) { background: white;}
&:not(span) { background: black; }
}
Unfortunately an approach like this could very easily get quite large. So I'm hoping for an SCSS implementation of the code shown at the top but without the use of :not(<every other selector>).
Preferably something looking like (invalid code):
span, div {
& { color: red; }
&(span) { background: white;}
&(span) { background: black; }
}
I don't think that it is possible to do what you want this way (but I may be wrong).
The code below achieve the result you are looking for but uses a map, a #mixin and #extend instead of a single selector. Maybe it's a bit too complex for want you want to achieve but I hope it can help:
#mixin setSelectors($elements) {
%commonProperties {
#content;
}
#each $selector, $properties in $elements {
#{$selector} {
#extend %commonProperties;
#each $property, $value in $properties {
#{$property}: #{$value};
}
}
}
}
#include setSelectors((
span: (background: white),
div: (background: black)
)) {
color: red; // Common properties
}
Will return:
div, span { color: red; }
span { background: white; }
div { background: black; }
The first argument is a map containing all your selectors and their specific properties. The #content of the #mixin contains shared properties.
If you need to add a selector that doesn't have any specific property, you can add it to the map with null as key. Such as:
#include setSelectors((
span: (background: white),
div: (background: black),
i: null
)) {
color: red;
}
However, this solution doesn't allow nested selectors so I believe that separating the selectors is the best way to go.
I am using the Bourbon modal reset. Its close button comes with the following styling:
.modal-close {
#include position(absolute, ($modal-padding /2) ($modal-padding /2) null null);
#include size(1.5em);
background: $modal-background;
cursor: pointer;
&:after,
&:before {
#include position(absolute, 3px 3px 0 50%);
#include transform(rotate(45deg));
#include size(0.15em 1.5em);
background: $modal-close-color;
content: '';
display: block;
margin: -3px 0 0 -1px;
}
&:hover:after,
&:hover:before {
background: darken($modal-close-color, 10%);
}
&:before {
#include transform(rotate(-45deg));
}
}
This makes it look like a grey × in the upper right of the modal. However, I would like to change it to look like a button that says "Save and Close". I'm wondering what the best method of overriding these styles is. On properties like margin, I can simply set it to whatever I want. However on #include position(....);, I am not really sure how I can reset that to none, initial, or unset. What is the best method for doing something like this? I don't want to simply remove the properties in the original refill file; I would like to keep a separate _modalOverride.scss, so I can include it where I want, but keep the original in tact. How can I override these "custom" #include properties?
Refills was designed to be overwritten so I'd just do the following to the HTML:
...
<div class="modal-close" for="modal-1">Close and Save</div>
...
and for the Scss:
...
.modal-close {
#include position(absolute, ($modal-padding /2) ($modal-padding /2) null null);
#include size(8em 1.5em);
background: tomato;
cursor: pointer;
}
...
But if you want to do an overwrite file it might be a bit trickier. You could do something like this in a file that comes after the modal.scss:
.modal-close {
position: inherit;
&:after,
&:before {
background: transparent;
}
&:hover:after,
&:hover:before {
background: transparent;
}
}
tldr: how to avoid repetition of ".well" selector in below example.
I am using bootstrap and sass to display a "well" div with a shape and with a gradient fill. This may not be a proper use of wells and I'd welcome other suggestions as to how to draw circular/rectangular divs with X% shaded (ideally where X is any integer. [0, 100]) but, for now, I am most interested in whether it's possible in SASS to get rid of the repetition of ".well". I tried using "&" but it would reverse .some_container too and I only wanted to reverse the immediate .inner_container parent to apply there (e.g. .inner_container.round). [There is one outer_container and multiple inner_containers. Each inner_container has one well.]
.outer_container {
.inner_container {
&.round .well {
border-radius: 50%;
}
&.barely_filled .well {
#include gradient-horizontal(sienna, $well-bg, 0%, 25%);
}
&.half_filled .well {
#include gradient-horizontal(sienna, $well-bg, 0%, 50%);
}
&.fairly_filled .well {
#include gradient-horizontal(sienna, $well-bg, 0%, 75%);
}
&.mostly_filled .well {
background-color: sienna;
}
}
}
The most terse way to write it would be like this:
#mixin well($sel) {
&#{$sel} .well {
#content;
}
}
.outer_container {
.inner_container {
#include well('.round') {
border-radius: 50%;
}
#include well('.barely_filled') {
test: 1;
}
#include well('.half_filled') {
test: 2;
}
#include well('.fairly_filled') {
test: 3;
}
#include well('.mostly_filled') {
background-color: sienna;
}
}
}
However, in addition to being more verbose, I feel that this decreases readability over what you currently have.
I want to add !important to a mixin. I tried both the following ways, and they return an error:
#include linear-gradient(hsl(68%, 94%, 90%), hsl(68%, 90%, 80%)); !important
#include linear-gradient(hsl(68%, 94%, 90%), hsl(68%, 90%, 80%)) !important;
Is there a way to do this correctly?
For some situations, I use a optional parameter named $important which I can pass in true.
Example:
my-mixin($important: true);
It would look something like that, with a helper function to avoid repetition on the properties that I have to toggle important:
#function if-important($important){
#return #{if($important, '!important', '')};
}
#mixin my-mixin($important: false) {
border-radius: 0; //whatever
border: 1px solid #ccc if-important($important);
background-color: #fff if-important($important);
color: #000 if-important($important);
}
!important cannot be used in a mixin. Refer the following links.
Adding !important using a Compass Mixin
https://github.com/cloudhead/less.js/issues/547
):
You cannot use !important on a Mixin.
it will end up giving you a SASS syntax error.
See this question for more information
Try passing it as a parameter:
#mixin anim($params...){
$values: null;
#for $i from 0 to length($params) {
#debug #{nth($params, $i + 1)};
#if '#{nth($params, $i + 1)}' != '!important' {
$values: #{nth($params, $i + 1)} $animation__time $animation__easing, $values;
}
}
#if '#{nth($params, length($params))}' != '!important' {
transition: $values;
}
#else {
transition: $values !important;
}
}
Usage:
#include anim(background-color, color, !important);
Is there a way to add scope to sass variables?
I want to be able to attach a class to my body element. The class will refer to a set of colours that the rest of the stylesheets can access.
I have tried:
#mixin theme_one{
$color: #000;
}
.theme_one{
#include theme_one;
}
and
.theme_one{
$color: #000;
}
I've just come across the same issue myself. I wanted to have different colour themes for different sections of my site.
Using a mixin seems like the best way to go. It's nicely DRY, and easy to use. The trick is not setting your colours in your main styles blocks, but rather using only the mixin for this.
I've set up the theme colours as variables at the top so they can be edited nicely, and I've set them as lists so that multiple values can be passed without hordes of variable being defined.
So:
// Variable Definitions
$defaultColor: black white grey;
$color2: blue green brown;
$color3: red white blue;
#mixin colorSet($color: $defaultColor) {
$link: nth($color, 1);
$border: nth($color, 2);
$background: nth($color, 3);
border-color: $border;
background-color: $background;
.column {
border-color: lighten($border, 10%);
}
a {
color: $link;
&:hover {
color: darken($link, 15%);
}
}
}
// Default colours
body {
#include colorSet();
}
// Scoped colours
.my-theme-3 {
#include colorSet($color3);
}
.my-theme-2 {
#include colorSet($color2);
}
Will produce something like this:
body {
border-color: white;
background-color: grey; }
body .column {
border-color: white; }
body a {
color: black; }
body a:hover {
color: black; }
.my-theme-3 {
border-color: white;
background-color: blue; }
.my-theme-3 .column {
border-color: white; }
.my-theme-3 a {
color: red; }
.my-theme-3 a:hover {
color: #b30000; }
.my-theme-2 {
border-color: green;
background-color: brown; }
.my-theme-2 .column {
border-color: #00b300; }
.my-theme-2 a {
color: blue; }
.my-theme-2 a:hover {
color: #0000b3; }
Edit: Updated to use default mixin values.
In your case no need to use mixin, If you have set of many styles then use mixin,
ie. if you have
#mixin theme_one{
$color: #000;
height: 50px;
}
then use Mixin
otherwise for single property use only variable
$color: #fff;
.some_class01{
color: $color;
background: $color;
}
.some_class22{
border-color: $color;
}
IMP: Variable should assign at the top of your code, it means don't use it after/below where you assigned it :)
Not sure if this is what you are looking for. It looks like you may have tried something similar to this,
which should probably work. (it may just be a matter of using !default)
Your body tag with a class on it..
<body class="theme_one">
</body>
Sass variables defined in stylesheet..
//THEME ONE VARIABLES
.theme_one{
$borderColor:#333 !default;
$fontColor:#999 !default;
}
//THEME TWO VARIABLES
.theme_two{
$borderColor:#CCC !default;
$fontColor:#000 !default;
}
Pre-existing CSS which will be overwritten depending on which class is used on the body tag.
h1.someheader {
color:$fontColor;
border-bottom:1px solid;
border-color:$borderColor;
}
Otherwise you could maybe try something like this. It looks like you may have tried something similar, however there seems to be an error with your mixin ... see note below.
//mixin used to set variables for properties
#mixin themeOne($fontColor,$borderColor) {
color:$fontColor;
border-color:$borderColor;
}
#include themeOne(#000,#CCC);
Pre-existing CSS
h1.someheader {
color:$fontColor
border-color:$borderColor;
border-bottom:1px solid;
}
Also note in your mixin example you are using $color:#000; ... This won't be interpreited properly as it should be color:#000; You can't use variables as selectors
unless you do something like #{$color}:#000;
I haven't quite tested this yet, so some things might need to be adjusted. If this doesn't solve your problem I hope it at least gives you some ideas.