SASS rule reuse - css

I have a set of icons with different colors and each color is used with different status declared with CSS classes. For example, <span class="icon icon--app"><span> gives a gray app icon while <span class="icon icon--app icon__light icon__selected"><span> gives a white app icon.
The following code is written in SCSS.
span.icon {
display: inline-block;
width: 32px;
height: 32px;
&.icon--app {
background: url(../images/app_gray.png);
&.icon__selected {
background: url(../images/app.png);
}
&.icon__light {
background: url(../images/app_gray.png);
&.icon__selected {
background: url(../images/app_white.png);
}
}
}
&.icon--device {
background: url(../images/device_gray.png);
&.icon__selected {
background: url(../images/device.png);
}
&.icon__light {
background: url(../images/device_gray.png);
&.icon__selected {
background: url(../images/device_white.png);
}
}
}
}
The problem is, there's a long list of CSS rules as above, which shares much similarity for app and device and other icons. I wonder if I can simplify these CSS rules using SASS?

I think you can use mixin in Sass:
e.g.
#mixin icon($type) {
.icon-#{$type} {
background: url(../images/#{$type}_gray.png);
}
}
#include icon(app);
#include icon(device);

I created a mixin for you:
#mixin icon($type) {
&.icon--#{$type} {
background: url(../images/#{$type}_gray.png);
&.icon__selected {
background: url(../images/#{$type});
}
&.icon__light {
background: url(../images/#{$type});
&.icon__selected {
background: url(../images/#{$type}_white.png)
}
}
}
}
span.icon {
display: inline-block;
width: 32px;
height: 32px;
#include icon(app);
#include icon(device);
}

Related

SCSS Nesting and extend

When I do a yarn build of the scss below I can only see the .select-list__item:hover in the compiled css, I am not seeing anything else from the class such as .select-list__item--selected I am not sure what the issue here is.
%select-list__item {
&:hover {
background: red;
}
&--selected,
&--selected:nth-child(2n),
&--selected:hover {
background: #00FF00;
}}
.select-list__item {
#extend %select-list__item;}
I believe it is to do with how placeholders (ie: %chosen-name) are meant to be used.
Although this is not explicitly pointed out in the documentation they are meant to be small bits that are reusable.
At my company, we use one for our generic button styles (margin, padding, font) and we extend that into all of our buttons (primary, secondary, tertiary).
A potential solution for your use case:
%select-list__item {
&:hover {
background: red;
}
&:focus{
background: blue;
}
}
.select-list__item {
#extend %select-list__item;
&--selected,
&--selected:nth-child(2n),
&--selected:hover {
background: #00FF00;
}
}
Or here's another - bit of an OTT solution for the example but you get the idea:
%select-list__item {
&:hover {
background: red;
}
&:focus{
background: blue;
}
}
%selected-list__item {
background: #00FF00;
&:nth-child(2n),
&:hover {
background: #00FF00;
}
}
.select-list__item {
#extend %select-list__item;
&--selected {
#extend %selected-list__item
}
}

SASS mixin : how to add class before?

I'm struggling with creating a mixin with sass and I can't seem to find a solution. If anyone has any ideas...
I have something like this:
.tata {
font-size: 12px;
.toto{
display: block;
.tutu {
text-align: left;
#include mixin_test{
background: red;
}
}
}
}
and I'd like to have something like this when compiled:
html .tata .toto .tutu {background:red}
I've tried this, but the result is not what I expected:
#mixin mixin_test {
html{
#content;
}
}
Does anyone have a solution?
You need to edit your mixin. Missing & after the selector:
#mixin mixin_test {
html & {
#content;
}
}
.tata {
font-size: 12px;
.toto{
display: block;
.tutu {
text-align: left;
#include mixin_test{
background: red;
}
}
}
}
On this page you can read more about parent selector: Parent Selector

Using only CSS is it possible to set a property based on class name?

Say I have some css like:
.modal-350 {
width: 350px;
}
.modal-400 {
width: 400px;
}
.modal-500 {
width: 500px;
}
etc. Using only CSS is it possible to set the width (or other property) just from the class name?
I know in javascript this is easy and also I could just use:
.modal-auto {
display: inline-block;
width:auto;
}
It's not production code, I'm just curious.
No. Even though we can use variables in CSS, we can only do so in property values and not in selector names. So something like this will not work:
.modal-$size {
width: ${size}px;
}
You can, however, use a CSS preprocessor such as LESS or SASS, and generate such rules automagically, given the requested sizes.
A SASS example:
$modal-sizes: 50 100 200 500;
%modal-default {
border-radius: 50%;
color: red;
background: green;
border-color: blue;
}
#mixin modals {
#each $size in $modal-sizes {
.modal-#{$size} {
#extend %modal-default;
width: #{$size}px;
}
}
}
#include modals;
This will compile as:
.modal-50, .modal-100, .modal-200, .modal-500 {
border-radius: 50%;
color: red;
background: green;
border-color: blue;
}
.modal-50 {
width: 50px;
}
.modal-100 {
width: 100px;
}
.modal-200 {
width: 200px;
}
.modal-500 {
width: 500px;
}

Trigger hover state in a mixin

I've got a Less mixin with a default state and a hover state.
Now I need to activate the hover state in the mixin when I'm hovering over the parent element.
Less
#icons () {
.settingsIcon() {
background: url("settings.png");
&:hover {
background: url("settings_hover.png");
}
}
}
.SettingsButton {
height: 50px;
width: 200px;
.icon {
#icons > .settingsIcon();
}
}
HTML:
<div class="SettingsButton" >
<span>Settings</span>
<div class="icon"></div>
</div>
I need to make sure that the same effect that happens on settingsIcon hover is triggered on the button hover also.
So I think I need to do something like this, where I 'call' the hover of settingsIcon somehow. Something like this (not valid Less code)
.SettingsButton:hover {
.icon {
#icons > .settingsIcon():hover;
}
}
How would I do that?
It would probably be better to re-write your mixins like in the below example. Essentially we are splitting your base setting and hover setting into two different mixins within the same namespace (#icons()) and then call them as required.
#icons () {
.settingsIcon() {
background: url("settings.png");
}
.settingsIconHover(){
background: url("settings_hover.png");
}
}
.SettingsButton {
height: 50px;
width: 200px;
.icon {
#icons > .settingsIcon();
&:hover{
#icons > .settingsIconHover();
}
}
&:hover .icon{
#icons > .settingsIconHover();
}
}
Another way to achieve this while still maintaining only a single entry in #icons for all the states is to move the .icon selector also to be within the mixin like in the below snippet.
#icons () {
.settingsIcon() {
.icon{
background: url("settings.png");
}
&:hover .icon, & .icon:hover{ /* & here means .SettingsButton */
background: url("settings_hover.png");
}
}
}
.SettingsButton {
height: 50px;
width: 200px;
#icons > .settingsIcon();
}
It is my understanding that you can solve this issue by using extend too.
.settingsIcon {
background: url("settings.png");
&:hover {
background: url("settings_hover.png");
}
}
.SettingsButton {
height: 50px;
width: 200px;
&:extend(.settingsIcon all);
.icon {
&:extend(.settingsIcon all);
}
}
outputs:
.settingsIcon,
.SettingsButton,
.SettingsButton .icon {
background: url("settings.png");
}
.settingsIcon:hover,
.SettingsButton:hover,
.SettingsButton .icon:hover {
background: url("settings_hover.png");
}
.SettingsButton {
height: 50px;
width: 200px;
}
Notice that the above generate a not used .settingsIcon selector in your CSS. Cause Less does not enable you to extend mixins (see: https://github.com/less/less.js/issues/1177) which do not output, you can only solve this by putting the .settingsIcon declaration in a different file a #import that file by using the reference keyword:
settingsicon.less:
.settingsIcon {
background: url("settings.png");
&:hover {
background: url("settings_hover.png");
}
}
project.less:
#import (reference) "settingsicon.less";
.SettingsButton {
height: 50px;
width: 200px;
&:extend(.settingsIcon all);
.icon {
&:extend(.settingsIcon all);
}
}
Now compiling project.less generates:
.SettingsButton,
.SettingsButton .icon {
background: url("settings.png");
}
.SettingsButton:hover,
.SettingsButton .icon:hover {
background: url("settings_hover.png");
}
.SettingsButton {
height: 50px;
width: 200px;
}
--
NB aren't you looking for CSS for hover that includes all child elements in the first place?
update
#harry wrote:
My understanding was that the same background needed to be applied for .SettingsButton:hover .icon and .SettingsButton .icon:hover only.
I think that makes sense. You can do that by using extend too, but i also agree that extending the same class twice is not so DRY too.
With settingsicon.less being again:
.settingsIcon {
background: url("settings.png");
&:hover {
background: url("settings_hover.png");
}
}
You can use:
#import (reference) "settingsicon.less";
.SettingsButton {
height: 50px;
width: 200px;
&.icon {
&:extend(.settingsIcon);
}
&:hover, & .icon:hover {
&:extend(.settingsIcon:hover);
}
}
or:
#import (reference) "settingsicon.less";
.SettingsButton {
height: 50px;
width: 200px;
& .icon {
&:extend(.settingsIcon all);
}
&:hover {
&:extend(.settingsIcon:hover);
}
}
which both compile into:
.SettingsButton.icon {
background: url("settings.png");
}
.SettingsButton:hover,
.SettingsButton .icon:hover {
background: url("settings_hover.png");
}
.SettingsButton {
height: 50px;
width: 200px;
}

How to make Sass mixin that extends parent?

You could hard-code extending a selector in Sass like:
.box {
width: 100px;
height: 100px;
color: red;
}
.box-green {
#extend .box;
color: green;
}
And then .box-green has all the properties of .box, with its own additional ones. What I want to do is write a generic mixin that does that - takes a class, adds all its properties with its own and adds a modifier to the class name. If something like this pseudo-code worked (which it doesn't), it would be ideal.
.box {
width: 100px;
height: 100px;
color: red;
#include make-modifier(&, green) {
color: green;
}
}
#mixin make-modifier(parent, modifier-name) {
.#{$parent}-#{$modifier-name} {
#content;
}
}
Is there a way to do it? Even if only in the latest version it's fine.
I would suggest a simpler solution like this
#mixin box($color:"") {
width: 100px;
height: 100px;
color: red;
#if $color !="" {
&-#{$color} {
color: $color;
}
}
}
.box {
#include box(green);
}
The output will be:
.box {
width: 100px;
height: 100px;
color: red;
}
.box-green {
color: green;
}
An example: http://sassmeister.com/gist/04cb6a6fe14972c3ffe4

Resources