Something between #include and #extend with sass - include

Is it possible to include a css rule in sass without duplicate the code?
With extend we are extending the code, but i dont want that eiter. I want include it, without duplicating code.
For example
SCSS:
.heading {
font-size: 16px;
font-family: my-cool-font;
}
.box {
background: red;
h1 {
#extend .heading;
color: white;
}
}
.my-other-box {
.heading {
color: black;
}
}
HTML
<div class="box">
<h1>My heading</h1>
</div>
<div class="my-other-box">
<h1 class="heading">My heading</h1>
</div>
CSS
.heading, .box h1 {
font-size: 16px;
font-family: my-cool-font;
}
.box {
background: red;
}
.box h1 {
color: white;
}
.my-other-box .heading,
.my-other-box .box h1,
.box .my-other-box h1 {
color: black;
}
So the two last rules there are because its extending (I understand the benifits of it).
But if i want to both use classes, and extends i dont want it to extend, just include it. But i dont want it to duplicate the code.
I want:
CSS
.heading, .box h1 {
font-size: 16px;
font-family: my-cool-font;
}
.box {
background: red;
}
.box h1 {
color: white;
}
.my-other-box .heading {
color: black;
}

If you use an extend class (or use a class name that differs from one you're repeating elsewhere), you can get the output you're looking for:
%heading, .heading {
font-size: 16px;
font-family: my-cool-font;
}
.box {
background: red;
h1 {
#extend %heading;
color: white;
}
}
.my-other-box {
.heading {
color: black;
}
}
Output:
.box h1, .heading {
font-size: 16px;
font-family: my-cool-font;
}
.box {
background: red;
}
.box h1 {
color: white;
}
.my-other-box .heading {
color: black;
}

Related

Common styles for elements and modifiers

if I have:
.control-button {
border: 1px solid red;
&--primary {
color: blue;
}
&--secondary {
color: white;
}
}
how do I make sure that border gets set in both button classes? As it is right now it generates following css:
.control-button {
border: 1px solid red;
}
.control-button--primary {
color: blue;
}
.control-button--secondary {
color: white;
}
You apply both classes to the element:
<button class="control-button control-button--primary">Primary button</button>
<button class="control-button control-button--secondary">Secondary button</button>
The block class defines any shared styling and modifier classes can be used to override or extend it.
It seems this is possible using string interpolation:
.control-button {
$c: &; // store classname as a var
border: 1px solid red;
&--primary {
#extend #{$c};
color: blue;
}
&--secondary {
#extend #{$c};
color: white;
}
}
That generates following css:
.control-button, .control-button--primary, .control-button--secondary {
border: 1px solid red;
}
.control-button--primary {
color: blue;
}
.control-button--secondary {
color: white;
}
It works, yet this probably, arguably a stupid way. Makes things a bit cryptic. But it is possible.

How to extract common scss code from multiple files?

After converting a lot of redundant crappy css files into scss files, I have a bunch of scss files. I'm pretty sure there is a lot of common css repeated among these files and I would like to extract this code.
As an example, let's say I have this block of scss code (let's call it block A) :
.test {
color: white;
.toto {
background: red;
font-size: 12px;
}
}
And another block (that we'll call block B) :
.test {
color: black;
.toto {
background: blue;
font-size: 12px;
text-align: center;
}
}
I want to be able to extract the following common scss code from block A and B :
.test {
.toto {
font-size: 12px;
}
}
It seems like a simple task to do, but with a large list of long scss files, it's really painful to do it manually. After searching for a while I didn't find any tool for that.
An intermediary solution could be to convert sass code to a multi-dimensionnal associative array and to process arrays to find intersections, but I could not find any simple solution to do that either, so any help would be appreciated.
There are a few approaches but in this instance, I would opt for a variable:
$base-font-size: 12px;
.test {
color: white;
.toto {
background: red;
font-size: $base-font-size;
}
}
.test {
color: black;
.toto {
background: blue;
font-size: $base-font-size;
text-align: center;
}
}
Or you could add a toto mixin with some defaults and use that:
#mixin toto($background: red, $text-align: left, $font-size: 12px) {
.toto {
background: $background;
text-align: $text-align;
font-size: $font-size;
}
}
.test {
color: white;
#include toto();
}
.test {
color: black;
#include toto(blue, center);
}
EDIT: or use extend:
.font-size-12 {
font-size: 12px;
}
.test {
color: white;
.toto {
#extend .font-size-12;
background: red;
}
}
.test {
color: black;
.toto {
#extend .font-size-12;
background: blue;
text-align: center;
}
}

how to inheritance multiples class through sass

I have a scenario in sass
.A{
background-color: red;
Padding :20px;
h4{ padding-bottom :20px;}
}
// another class
.B{
background-color : blue;
padding : 20px
h4{ padding-bottom:20px}
}
Question: how can i combine padding and h4 together in SASS without to repeating padding and h4 properties
The most straight forward way is to use #extend.
%common_properties {
padding: 20px;
h4 {
padding-bottom: 20px;
}
}
.a {
#extend %common_properties;
background-color: red;
}
.b {
#extend %common_properties;
background-color: blue;
}
You really don't save much by using sass/scss for this small of a redundancy
A solution with scss:
.a, .b {
padding: 20px;
background-color: red;
& h4 {
padding-bottom: 20px;
}
}
.b{
background-color:blue;
}
That solution in plain css:
.a, .b {
padding: 20px;
background-color: red;
}
.a h4, .b h4 {
padding-bottom: 20px;
}
.b {
background-color: blue;
}
Here is what that will look like:
http://codepen.io/cawoelk/pen/Ciqyw

Sass / Scss: Changing the order of nested psuedo selectors for :before and :hover in generated CSS?

Given the following Sass:
div.test {
display: inline-block;
background-color: #ffffff;
color: #000000;
&:before {
& {
&:hover {
border: 1px solid salmon;
}
}
width: 25px;
height: 25px;
content: "";
}
}
The resulting CSS compiles to:
div.test {
display: inline-block;
background-color: #ffffff;
color: #000000;
}
div.test:before {
width: 25px;
height: 25px;
content: "";
}
div.test:before:hover {
border: 1px solid salmon;
}
What I am attempting to do is generate div.test:hover:before (the current output is before:hover).
NOTE: I am able to generate the expected CSS by using the following Sass:
div.test {
display: inline-block;
background-color: #ffffff;
color: #000000;
&:hover {
&:before {
border: 1px solid salmon;
}
}
&:before {
width: 25px;
height: 25px;
content: "";
}
}
However I would like to know if it is possible using the first nested approach or some modification of it.
The goal was to avoid having to repeat &:before if there was such a way to do so using Sass syntax. I am also OK with knowing it isn't possible.
While initially the plan was to have '&' available in SassScript as a string that could be manipulated so that you could insert values wherever you wanted, those plans have been abandoned for 3.3 due to complication. Unfortunately you'll have to wait a while to be able to do this. At the moment '&' is immutable and just means "whatever the selector chain up to this point is".
EDIT (2020.02.15):
it is now technically possible to achieve this with recent versions of dart-sass:
#use "sass:selector";
#mixin unify-parent($child) {
#at-root #{selector.unify(&, $child)} {
#content;
}
}
div.test {
display: inline-block;
background-color: #ffffff;
color: #000000;
&:before {
width: 25px;
height: 25px;
content: "";
#include unify-parent(":hover") {
border: 1px solid salmon;
}
}
}
Sources:
https://sass-lang.com/blog/the-module-system-is-launched
https://sass-lang.com/documentation/style-rules/parent-selector#advanced-nesting

Can SASS merge properties?

Maybe a better question would be, Is there a more efficient way to override parts of a mixin?
This piece of SCSS:
#mixin button {
.button {
background-color: red;
color: white;
}
}
.container {
#include button;
.button {
background-color: green;
}
}
compiles to:
.container .button {
background-color: red;
color: white;
}
.container .button {
background-color: green;
}
I wish it could compile to:
.container .button {
background-color: green;
color: white;
}
Pass an argument into the mixin instead:
#mixin button($color: red) {
background-color: $color;
color: white;
}
.container {
.button {
#include button(green);
}
}

Resources