Compass: separate sprite declaration for IE8 - compass-sass

In my .scss I'm using CSS3 pseudo classes. For example :
.btn:disabled {
#include assets-sprites(btn_disabled);
}
.btn.disabled {
#include assets-sprites(btn_disabled);
}
Compass combine these two declaration into one :
.btn:disabled, .btn.disabled {
background: url("img/assets.png")
}
But Internet Explorer 8 doesn't read the declaration if a CSS3 pseudo class is present in the selector (like :disabled, :checked, :not, etc).
So how can I output this into something like that ?
.btn:disabled {
background: url("img/assets.png")
}
.btn.disabled {
background: url("img/assets.png")
}
Thanks :)

You can combine placeholders and a mixin to manage this with a DRY approach:
SCSS
#import "compass";
// Generate separate CSS3 pseudo-selector / fallback selector.
//
// #param string $selector
// The CSS3 selector name, without the first colon.
// #param string $sprite
// The sprite name without the file extension.
#mixin sprite-css3-pseudo($selector, $sprite, $map: $assets-sprites) {
// CSS3 selector
&:#{$selector} {
#extend %assets_css3-map;
#include sprite-background-position($map, $sprite);
}
// IE8 fallback
&.#{$selector} {
#extend %assets-map;
#include sprite-background-position($map, $sprite);
}
}
// $<map>-sprite-base-class to customize the base class
// used when we importing the sprite map.
$assets-sprite-base-class: '%assets-map';
// Compass generates the following rule:
// %assets-map {
// background: $assets-sprites no-repeat;
// }
#import "assets/*.png";
// We have to split the CSS3 selectors of the classic selectors (the
// fallback) so we need to declare a new placeholder with the same
// content generated by Compass for the base class.
%assets_css3-map {
background: $assets-sprites no-repeat;
}
.btn {
#include sprite-css3-pseudo('disabled', 'btn_disabled');
}
.fb {
#include sprite-css3-pseudo('checked', 'fb_icon');
}
.icon-alarm {
// We can still use the regular sprite generator
#include assets-sprite('alarm');
// And our mixin :)
#include sprite-css3-pseudo('disabled', 'alarm');
}
CSS
.btn.disabled, .fb.checked, .icon-alarm, .icon-alarm.disabled {
background: url('../images/assets-sacf5a47174.png') no-repeat;
}
.btn:disabled, .fb:checked, .icon-alarm:disabled {
background: url('../images/assets-sacf5a47174.png') no-repeat;
}
.btn:disabled {
background-position: 0 -224px;
}
.btn.disabled {
background-position: 0 -224px;
}
.fb:checked {
background-position: 0 -176px;
}
.fb.checked {
background-position: 0 -176px;
}
.icon-alarm {
background-position: 0 0;
}
.icon-alarm:disabled {
background-position: 0 0;
}
.icon-alarm.disabled {
background-position: 0 0;
}

Here'es the solution, thanks to #pascalduez:
$assets: sprite-map("assets/*.png");
.btn:disabled { background: sprite($assets, user); }
.btn.disabled { background: sprite($assets, user); }

Related

SASS select class that was chained to parent

I have the following HTML <div class="parent green"></div>
The green class may or may not be added. It is dynamic. It may also be another name.
In SASS how do I give properties to a .child element of parent when class green is chained to it?
I tried:
.parent {
.child {
.green & {
color: green;
}
}
}
It doesn't work.
I also tried the following which works but I am looking for something similar to the sass above. The code will become repeatable below because I have to add child each time for every dynamic class.
.parent {
&.green {
.child {
color: green;
}
}
}
I'm trying to get a structure like this if possible with sass:
.parent {
.child {
.green & { /* when .parent.green */
color: green;
}
.blue & { /* when .parent.blue */
color: blue;
}
.text-align-right & { /* when .parent.text-align-right */
text-align: right;
}
etc...
}
}
& is treated as parent selector reference in Sass, because of this your code doesn't work since it refers wrong selector.
Use of & directly will not help here, but your goal can be achieved by using mixins, for example:
#mixin child($class) {
&.#{$class} {
.child {
#content;
}
}
}
.parent {
#include child(green) {
color: green;
}
#include child(blue) {
color: blue;
}
#include child(text-align-right) {
text-align: right;
}
}
This piece of code produces result that you want to get, you can check in by yourself on sassmeister.

SASS: Add pseudo-class to grandparent ampersand

This SASS code...
#mixin test
{
#at-root #{selector-replace(&, '.class1', '.class1:nth-child(odd)')}
{
color:red;
}
}
.class1
{
.class2
{
#include test;
}
}
...compiles to:
.class1:nth-child(odd) .class2
{
color: red;
}
Is this possible when not using selector-replace (because I don't know how class1 is called)?
I just want to add a nth-child selector to the grandparent.
I am only allowed to change the mixin, not the original code.
Ok, this will do the trick:
#mixin test
{
// Find the first selector
$parent : nth(nth(&, 1), 1);
// Defines a list for the rest of the selectors
$rest : ();
// For each selector of &, starting from the second
#for $i from 2 through length(nth(&, 1)) {
// Adds the selector to the list of the "rest of the selectors"
$rest: append($rest, nth(nth(&, 1), $i));
}
// Adds the selector at root
#at-root #{$parent}:nth-child(odd) #{$rest} {
color: red;
}
}
.class1
{
.class2
{
#include test;
}
}
This compiles to:
.class1:nth-child(odd) .class2 {
color: red;
}
Hope it helps!

How to use this Sass Flexbox mixin provided by a theme

I am using Drupal FortyTwo theme. In the FortyTwo base-theme there is a flexbox mixin provided see below:
#mixin flex-order($number) {
order: #{$number};
}
#mixin flex-align($align) {
#if $align == 'start' or $align == 'end' {
align-items: flex-#{$align};
} #else {
align-items: #{$align};
}
}
#mixin flex-flow($direction: none, $wrap: none) {
#if $wrap != none {
flex-wrap: #{$wrap};
}
#if $direction != none {
flex-direction: #{$direction};
}
}
#mixin flex-grow($value) {
flex-grow: #{$value};
}
#mixin flex-shrink($value) {
flex-shrink: #{$value};
}
#mixin flex-child($value) {
flex: #{$value};
}
#mixin flex($wrap: none, $justify: none, $align: none, $flow: none, $direction: none, $inline: none) {
#if $inline != none {
display: inline-flex;
} #else {
display: flex;
}
#if $direction != none {
flex-direction: #{$direction};
}
#if $wrap != none {
flex-wrap: #{$wrap};
}
#if $align != none {
align-items: #{$align};
}
#if $justify != none {
justify-content: #{$justify};
}
}
I am updating the theme. I can't figure out how to use this mixin? In the old theme there is e.g. this part:
#my-block {
html.flexbox & {
#include flex;
#include bvp(flex-direction, column);
}
div.content {
html.flexbox & {
#include bvp(flex, 1);
}
position: relative;
}
}
Also I have to get rid of the bvp mixin. How do I add flexbox here the proper way using above flexbox mixins?
So as you saw, we have a series of mixins.
The last one should be be most helpful, but from playing around with it in Code Pen, I'm not convinced it actually works correctly. And some of the others aren't especially helpful.
For example, we can see that #mixin flex-order simply spits out the order flexbox property with whatever number we pass to it.
So this:
#my-box {
#include flex-order(2);
}
Outputs this:
#my-box {
order: 2;
}
Well unless you just want a visual reminder that order only relates to flex items, that's not exactly helping you much as you could have just as easily done order: 2 in your SCSS in the first place.
The same thing applies to the mixins flex-align, flex-grow, flex-shrink, and flex-child.
So being that the single-property mixins aren't super useful and the last mixin seems broken, I would recommend just specifying your flex properties as needed in your SCSS and maybe using the flex-flow mixin if you want.
#mixin flex-flow
The flex-flow flexbox property requires two values: one for flex wrapping, and one for flex direction. In the mixin, it outputs that shorthand property as two separate properties, or it outputs only the property you pass to it if you only pass one property, that way you don't end up with an invalid CSS rule.
So this:
#my-box {
#include flex-flow(wrap, column);
}
#my-other-box {
#include flex-flow(wrap);
}
Outputs this:
#my-box {
flex-wrap: wrap;
flex-direction: column;
}
#my-other-box {
flex-wrap: wrap;
}
That way you have two acceptable CSS rules. Otherwise if you actually used the flex-flow property, you'd get:
#my-box {
flex-flow: wrap column; /* invalid; flex-direction must come first */
}
#my-other-box {
flex-flow: wrap; /* invalid; missing flex-direction */
}
Final example
Your final SCSS could look something like this, after removing the bvp mixin and specifying the individual flex properties without mixins, as I initially recommended.
#my-block {
html.flexbox & {
#include flex-flow(row, wrap);
align-items: center;
justify-content: center;
}
div.content {
html.flexbox & {
flex: 1 0 auto;
}
position: relative;
}
}

Is it possible to reference a further parent than just the one above?

I have the following sample code:
.level1 {
// css
.level2 {
// css
. level3 {
// css
color: red;
}
}
And then
.level1.blue .level .level3 {
color: blue
}
I would like to put the second rule somehow on the first bit of code, so that I don't repeat the structure again and I have both color possibilities above, is this possible in anyway?
I wasn't planning on answering my own question, but it seems that I found out exactly what I was looking for only it has recently being added to sass and will be available on sass 3.4. I believe there's a prerelease to tried but I havent tried it yet.
Basically what I was looking has been answered to me on github:
https://github.com/sass/sass/issues/286#issuecomment-49112243
So on 3.4 you can do:
.level1 {
.level2 {
.level3 {
#at-root #{selector-append(".blue", &)} {
color: blue;
}
color: red;
}
}
}
which is exactly what I was looking for.
There's a bunch of addition related to the parent selector (&), you can learn more from it at https://github.com/sass/sass/issues/1117
Bear in mind though, that at the time of writing this answer, all of this is rather new.
Also see: https://github.com/sass/sass/blob/master/doc-src/SASS_CHANGELOG.md
And: http://www.phase2technology.com/blog/everything-you-need-to-know-about-sass-3-4/
This:
#mixin level3color($color) {
.level2 {
.level3 {
color: $color;
}
}
}
.level1 {
#include level3color(#FF0000);
&.blue {
#include level3color(#0000FF);
}
}
produces this:
.level1 .level2 .level3 {
color: red;
}
.level1.blue .level2 .level3 {
color: blue;
}
Gotta love mixins!
EDIT:
This is still pretty clean (or at least clean considering what you're trying to do) because you can still have your structure there.
.level1 {
// css
.level2 {
// css
.level3 {
// css
color: red;
}
}
&.blue { #include level3color(blue); }
&.yellow { #include level3color(yellow); }
}
A simple example:
.child{
background-color:red;
.parent:hover &{
background-color:blue;
}
}
goes into
.child {
background-color: red;
}
.parent:hover .child {
background-color: blue;
}
http://sassmeister.com/gist/e994e056d3cc3b342e2c

Sass/Compass Getting variable name from variable

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.

Resources