SCSS use parent style for children (texts) - sass

I have next scss code:
.btn {
font-size: 24pt;
color: red;
&-small {
font-size: 17pt;
}
&-meddium {
font-size: 24pt;
}
&-big {
font-size: 36pt;
}
}
and i want that all my buttons (btn, btn-small, btn-meddium, btn-big) will have color RED.
P.S. I want realize it by only one class

Since you're using SCSS, you can use #mixin and #include:
#mixin btn {
color: red;
}
.btn {
#include btn;
}
.btn-smaall {
#include btn;
font-size: 17pt;
}
And to to do that for the rest of the button classes you want to create.
Another way would be to addjust your selectors as such:
.btn {
font-size: 24pt;
color: red;
&.btn-small {
font-size: 17pt;
}
&.btn-meddium {
font-size: 24pt;
}
&.btn-big {
font-size: 36pt;
}
}
And then you can create a small button by adding the class btn and btn-small to a button. e.g. <button class="btn btn-small>Test</button>

You can define classes like this (my preference): btn btn__small
Then you can trigger it with scss like you wanted:
.btn {
font-size: 24pt;
color: red;
&__small {
font-size: 17pt;
}
}

Related

Prevent combination of multiple selectors

I'm trying to group all my vendor-specific stuff into a placeholder selector like this:
%search-bar-placeholder {
color: red;
}
.search-bar::-webkit-input-placeholder {
#extend %search-bar-placeholder;
}
.search-bar:-moz-placeholder {
#extend %search-bar-placeholder;
}
.search-bar::-moz-placeholder {
#extend %search-bar-placeholder;
}
.search-bar:-ms-input-placeholder {
#extend %search-bar-placeholder;
}
And then it compiles to this:
.search-bar::-webkit-input-placeholder, .search-bar:-moz-placeholder, .search-bar::-moz-placeholder, .search-bar:-ms-input-placeholder {
color: red; }
How can I make sure Sass doesn't put all the selectors together ? Like this:
.search-bar::-webkit-input-placeholder {
color: red;
}
.search-bar:-moz-placeholder {
color: red;
}
.search-bar::-moz-placeholder {
color: red;
}
.search-bar:-ms-input-placeholder {
color: red;
}
When looking at Extend/Inheritance at sass-lang.com it seems that the selectors will always be comma separated. Even if you add another property, it will keep the shared properties in the comma separated list, and add another selector just for that overridden value.
The way I achieved what you want is by using a mixin. Though it's not really the purpose of a mixin, it does get the job done. Your style is still centralized and you can print it out in each selector using a one liner too.
#mixin placeholder-properties() {
color: red;
font-weight: bold;
}
.search-bar::-webkit-input-placeholder {
#include placeholder-properties();
}
.search-bar:-moz-placeholder {
#include placeholder-properties();
}
.search-bar::-moz-placeholder {
#include placeholder-properties();
}
.search-bar:-ms-input-placeholder {
#include placeholder-properties();
}
The result will the following.
.search-bar::-webkit-input-placeholder {
color: red;
font-weight: bold;
}
.search-bar:-moz-placeholder {
color: red;
font-weight: bold;
}
.search-bar::-moz-placeholder {
color: red;
font-weight: bold;
}
.search-bar:-ms-input-placeholder {
color: red;
font-weight: bold;
}
Here's a fiddle.

Use a parameter as a tag in a mixin

How can I do that :
#mixin addMargin($el) {
$el {
margin-left: 5px;
}
$el:hover {
margin-left: 10px;
}
}
using sass ?
Thanks for your help
In a mixin, you can not only add properties directly to an element, but you can also add more rules:
#mixin addMargin {
margin-left: 5px;
&:hover {
margin-left:10px;
}
}
Note that you have to prefix the :hover with & so that we get this rule:
#something-with-the-mixin-applied:hover
instead of
#something-with-the-mixin-applied :hover
Use interpolation:
#mixin addMargin($el) {
#{$el} {
margin-left: 5px;
}
#{$el}:hover {
margin-left: 10px;
}
}
#include addMargin(h1);
But Yogu is right, you don't need it here. You may omit selectors, leaving only directives in your mixin, and apply the mixin inside a selector:
#mixin addMargin {
margin-left: 5px;
&:hover {
margin-left:10px;
}
}
h1 {
#include addMargin;
}

Access the parent selector from within a SASS mixin

I have set up a mixin for a button using display:inline-block. I am trying to get to the parent of whatever class that will eventually end up using the mixim, so I can add the font-size: 0px line there to make sure that I don't need to make adjustments to my HTML to avoid unwanted space between each button.
Here's an example... I want the. parent class to receive the font-size: 0px line.
#mixin button() {
display:inline-block;
font-size: 1em;
//other stuff to make a pretty button
&& { font-size: 0px; }
}
.parent{
.child {
#include button();
}
}
As of Sass 3.4 this is now possible.
#mixin parent {
#each $selector in & {
$l: length($selector);
#if ($l == 1) {
#error "Used parent mixin on a top-level selector";
} #else {
$parent: nth($selector,1);
#for $i from 2 to $l {
$parent: append($parent,nth($selector,$i));
}
#at-root #{$parent} {
#content;
}
}
}
}
// Use
.grandparent {
.parent{
.child {
font-size: 1em;
#include parent {
font-size: 0px;
}
}
}
}
// Result
.grandparent .parent .child {
font-size: 1em;
}
.grandparent .parent {
font-size: 0px;
}
// Errors:
.root {
#include parent {
content: "Won't work";
}
}
.grandparent .parent, .root {
#include parent {
content: "Also won't work";
}
}
No, this is not possible. You could do something like this, though:
#mixin button($child: '.child') {
font-size: 0px;
//other stuff to make a pretty button
#{$child} {
display:inline-block;
font-size: 1em;
}
}
.parent{
#include button();
}
Output:
.parent {
font-size: 0px;
}
.parent .child {
display: inline-block;
font-size: 1em;
}
There is a XXX! selector in the draft for the CSS 4 spec, which will act as the way you like. It announces the subject of the CSS style declarations, if the selectors match
So if you have this selector
.a > .b! > .c
It will match e.g. for this
<div class="a">
<div class="b">
<div class="c">
</div>
</div>
</div>
but the style declarations will not take effect on .c, but on .b, because I announced by the exclamation mark, that this element should be the subject of the style
http://dev.w3.org/csswg/selectors4/#subject
You cannot use it right now out of the box. But there is one jQuery plugin, that is a polyfill for that. http://dev.w3.org/csswg/selectors4/
See also this stack: Is there a CSS parent selector?
How to apply?
Well, I don't know exactly in SASS, but in LESS it would be
*! > & {
/* ... */
}
While Karol's answer is near perfect, it doesn't take into account pseudo-elements or pseudo-selectors. Furthermore, code is duplicated if using more than one complex selector. I came up with a simplified version:
#mixin parent {
$parents: ();
$parent: '';
#each $selector in & {
$length: length($selector);
$index: 0;
$last-selector: nth($selector, $length);
#if ($length == 1) {
#error "Used parent mixin on a top-level selector";
} #else {
$index: str-index($last-selector, '::');
#if ($index) {
$last-selector: str-slice($last-selector, 1, $index - 1);
} #else {
$last-selector: null;
}
// Inspect allows us to combine two selectors in one block.
$parent: inspect(set-nth($selector, $length, #{$last-selector}));
$parents: join($parents, $parent, comma);
}
}
#at-root #{$parents} {
#content;
}
}
There's a first loop to iterate over the selector list (selectors with commas at the end). Because complex selectors are also treated as a list, we just need to remove the last element of the list. There's no loop to iterate over the compound or simple selectors since we only need to discard the last one.
There's no function in Sass to remove an element of a list, but we can set the value of an element with set-nth. By making the last element as an empty string and unquoting it, we can remove the last element from the printed representation (string) of the list. Since selectors can be strings, we simply use the new string as a selector.
When using the following:
.grandmother,
.grandfather {
.parent {
.child {
font-size: 10em;
#include parent {
font-size: 5em;
}
&::after {
font-size: 1px;
#include parent {
font-weight: bold;
}
}
}
}
}
We get the following:
.grandmother .parent .child,
.grandfather .parent .child {
font-size: 10em;
}
.grandmother .parent,
.grandfather .parent {
font-size: 5em;
}
.grandmother .parent .child::after,
.grandfather .parent .child::after {
font-size: 1px;
}
.grandmother .parent .child,
.grandfather .parent .child {
font-weight: bold;
}
Note: pseudo-elements and pseudo-selectors are not children of an element but are attached to it and have therefore no parents in themselves. I assumed parents would mean the parent in the sense of Sass nesting.

Something between #include and #extend with sass

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;
}

Using SASS to extend selectors with elements

I'm working on an SCSS stylesheet, and I have a rule that looks something like this:
.footer-link-row {
color: red;
ul& {
padding: 0;
}
}
I want the ul& line compile to the selector ul.footer-link-row. However, this selector returns a compiler error, and using a &ul compiles to .footer-link-row ul. What's the correct way to select something like this?
--Added--
To clarify, the eventual CSS I want out of this is:
.footer-link-row {
color: red;
}
ul.footer-link-row {
padding: 0;
}
You want something like the following:
ul {
padding: 0;
.footer-link-row {
color: red;
}
}
The ampersand is used to require that both selectors match
a { text-decoration: none;
&:hover { border-width: 1px }
}
// compiles to
a {
text-decoration: none;
}
a:hover {
border-width: 1px;
}
If you want the ul.footer-link-row try
ul {
&.footer-link-row {
padding: 0;
}
.footer-link-row {
color: red;
}
}
Your clarification indicates that you need two scopes.
ul {
&.footer-link-row {
padding: 0;
}
}
.footer-link-row {
color: red;
}

Resources