Sass apply css to media query and class in same time - css

I use Sass and I want to apply some style with two conditions
first if media query < desktop
second if the container have class "affiliations"
How can I wrote it without duplicate the style
I try the following but its not work
#include media ('<desktop'),.affiliations {
.search
{
color:red;
.icon{
color: blue;
}.........etc
}
}

What you are trying to do can't be done with only sass, usually you would structure your code like this
.someclass {
color: deepskyblue;
#media (max-width: 1023) {
.affiliations & {
color: deeppink;
}
}
}

Related

Is there a way to apply styles to a selector and a media query?

I need to apply some styles to a div for printing. I can use a media query #media print {} to accomplish this easily. But I also sometimes need to apply the same styles on the browser itself, before the print dialog is opened. I'm trying to do this by adding a div .print-view to the page. But can't find a way to do it without code duplication.
I've tried this, but it's invalid css:
.print-view, #media print {
.grey-background {
background-color: white;
}
}
I've also tried this (scss), but it causes an error #extend may only be used within style rules.
.print-view {
.grey-background {
background-color: white;
}
}
#media print {
#extend .print-view;
}
Is there some other way for me to accomplish this?
Edit: changed sample code to more accurately reflect what I'm trying to do
Found the answer here. #include can be used to add a mixin into both a media query and a normal selector.
#mixin print {
.grey-background {
background-color: white;
}
}
.print-view {
#include print;
}
#media print {
#include print;
}
This compiles to the following css:
.print-view .grey-background {
background-color: white;
}
#media print {
.grey-background {
background-color: white;
}
}

Extending in a media query in Sass and Bootstrap 4

I am updating to the new Bootstrap version 4 which now uses Sass over Less, and my application that uses Bootstrap used the Less files directly rather than the fully compiled css distribution.
But now I've hit a snag - I understand that Sass doesn't allow you to use an #extend within a #media query, but what I don't understand is how I get around the simple problem of overloading a style on a larger screen.
For example, a stripped down version of my Sass looks like:
.box {
//mobile styles
background: green;
.logout-button {
//mobile styles for logout button
background: red;
}
}
//everything over 767px
#media (min-width: 768px) {
.box {
.logout-button {
#extend .btn-link; //bring in the Bootstrap button link style here
}
}
}
In this example, I want the .logout-button to use the .btn-link style from Bootstrap. But because you can't #extend like this, I'm totally confused as to how to achieve this.
Is there a completely different approach required in Sass compared to Less? Less allows you to do this so I'd be surprised if this was a limitation considering Bootstrap's recent switch.
Thanks in advance!
You are right, you can not #extend like this.
But you can #include some #mixin.
There is unfortunately no #mixin to create .btn-link variant by default in Bootstrap 4.
If you wanted some other variant, you could use these #mixins which are part of Bootstrap 4:
#include button-variant($background, $border, $active-background: darken($background, 7.5%), $active-border: darken($border, 10%))
or this
#include button-outline-variant($color, $color-hover: #fff)
(Useful list of Boostrap 4 mixins)
But if you need .btn-link you have to make your own #mixin. Something like this (it's copy/paste style of .btn-link in to new mixin):
//
// Link buttons
//
// Make a button look and behave like a link
#mixin btn-link() {
font-weight: $font-weight-normal;
color: $link-color;
background-color: transparent;
#include hover {
color: $link-hover-color;
text-decoration: $link-hover-decoration;
background-color: transparent;
border-color: transparent;
}
&:focus,
&.focus {
text-decoration: $link-hover-decoration;
border-color: transparent;
box-shadow: none;
}
&:disabled,
&.disabled {
color: $btn-link-disabled-color;
pointer-events: none;
}
// No need for an active state here
}
And then you can use it as you wish:
//everything over 767px
#media (min-width: 768px) {
.box {
.logout-button {
#include btn-link;
}
}
}
Nice article about this: SCSS - Extending Classes Within Media Queries

Set a SASS variable depending

I'm searching a way to use a particular color depending on a class on the body tag.
I have a main scss file like this
// variables.scss
$bg-main: white;
$color-first: red;
$color-second: green;
And in my other files, I use the colors
// content.scss
.content {
.some-selector: {
// some styles
color: $color-second;
}
a:hover {
// some styles
color: $color-second;
}
}
// and same goes for menu.scss etc.
Now I have a dynamic class on the body, that changes depending on the current selected menu. I would like $color-second to be different for each body classes, and I don't know how to do that. The only solution I found was to move all the $color-second from each files into one single file, like this:
.body-1 {
.content a:hover, .content .some-selector {
color: green;
}
}
.body-2 {
.content a:hover, .content .some-selector {
color: blue;
}
}
.body-1 {
.content a:hover, .content .some-selector {
color: black;
}
}
So I don't need to write the color in each files. This works well, but if I need to set this $color-second to some other selector, I need to put that in this big file.
Is this possible to do this an other way?
I already checked these answers, but it didn't helped me much:
SASS set variable depending on CSS class
Creating or referencing variables dynamically in Sass
Merge string and variable to a variable with SASS
There are multiple ways to do this. The most obvious two which come to mind are mixins and loops:
Mixins
Just put everything you want into a single mixin, and then use it for every body class:
#mixin colored-content($color) {
.content a:hover, .content .some-selector {
color: $color;
}
/* Any other rules which use $color here */
}
.body-1 {
#include colored-content(green);
}
.body-2 {
#include colored-content('#FF0000');
}
.body-3 {
#include colored-content(darken(red, 20));
}
You can extend this example with any number of arguments (for example, $textColor and $bgColor), conditions or rules.
With this approach you will not have SCSS code repetitions, and any updates will be introduced easily.
Loop
Another way is to use a simple loop:
$body_themes: (
"body-1": green,
"body-2": #FF0000,
"body-3": darken(red, 2)
);
#each $body_class, $color in $body_themes {
.#{$body_class} {
.content a:hover, .content .some-selector {
color: $color;
}
/* Any other rules which use $color here */
}
}
It is even shorter, but imho it is less readable.
P.S. It is possible to combine mixins and loops, by the way :)

Combine extend and mixin in with same rules

Okey!
I have couple of extends in sass like
%heading
%paragraph
%gutter
and so on...
I want to reuse thouse in media queries, but that doesnt work. I know that.
Then i came up with the idea to have all my extends as mixins too. So when i want them in a media query i simply use mixin. for example
.my-widget {
#extend %gutter;
#media.... {
#include gutter-other;
}
}
and because i dont want to write all my rules again. How do i write my sass then?
I tried
%my-extend, #mixin my-extend {
...
}
but that didnt work.
Any ideas how to work with this?
No, you can't combine them that way. You'll have to write a mixin that is invoked by your extend class and anything inside of a media query.
#mixin my-extend {
background: yellow;
}
%my-extend {
#include my-extend;
}
.foo {
#extend %my-extend;
}
.bar {
#extend %my-extend;
}
.baz {
#media (min-width: 30em) {
#include my-extend;
}
}
Output:
.foo, .bar {
background: yellow;
}
#media (min-width: 30em) {
.baz {
background: yellow;
}
}

Extending selectors from within media queries with Sass

I have an item class and a compact "modifier" class:
.item { ... }
.item.compact { /* styles to make .item smaller */ }
This is fine. However, I'd like to add a #media query that forces the .item class to be compact when the screen is small enough.
On first thought, this is what I tried to do:
.item { ... }
.item.compact { ... }
#media (max-width: 600px) {
.item { #extend .item.compact; }
}
But this generates the following error:
You may not #extend an outer selector from within #media. You may only
#extend selectors within the same directive.
How would I accomplish this using SASS without having to resort to copy/pasting styles?
The simple answer is: you can't because Sass can't (or won't) compose the selector for it. You can't be inside of a media query and extend something that's outside of a media query. It certainly would be nice if it would simply take a copy of it instead of trying to compose the selectors. But it doesn't so you can't.
Use a mixin
If you have a case where you're going to be reusing a block of code inside and outside of media queries and still want it to be able to extend it, then write both a mixin and an extend class:
#mixin foo {
// do stuff
}
%foo {
#include foo;
}
// usage
.foo {
#extend %foo;
}
#media (min-width: 30em) {
.bar {
#include foo;
}
}
Extend the selector within a media query from the outside
This won't really help your use case, but it is another option:
%foo {
#media (min-width: 20em) {
color: red;
}
}
#media (min-width: 30em) {
%bar {
background: yellow;
}
}
// usage
.foo {
#extend %foo;
}
.bar {
#extend %bar;
}
Wait until Sass lifts this restriction (or patch it yourself)
There are a number of ongoing discussions regarding this issue (please don't contribute to these threads unless you have something meaningful to add: the maintainers are already aware that users desire this functionality, it's just a question of how to implement it and what the syntax should be).
https://github.com/sass/sass/issues/1050
https://github.com/sass/sass/issues/456
For the record, here is how I ended up solving the problem with only duplicating generated styles once:
// This is where the actual compact styles live
#mixin compact-mixin { /* ... */ }
// Include the compact mixin for items that are always compact
.item.compact { #include compact-mixin; }
// Here's the tricky part, due to how SASS handles extending
.item { ... }
// The following needs to be declared AFTER .item, else it'll
// be overridden by .item's NORMAL styles.
#media (max-width: 600px) {
%compact { #include compact-mixin; }
// Afterwards we can extend and
// customize different item compact styles
.item {
#extend %compact;
/* Other styles that override %compact */
}
// As shown below, we can extend the compact styles as many
// times as we want without needing to re-extend
// the compact mixin, thus avoiding generating duplicate css
.item-alt {
#extend %compact;
}
}
I believe SASS/SCSS does not support the #extend directive inside of a media query. http://designshack.net/articles/css/sass-and-media-queries-what-you-can-and-cant-do/
You might need to use a mixin instead, though the code bloat needs to be weighed against your objective.
This is the cleanest, partial solution I've found. It takes advantage of #extend where possible and falls back to mixins when inside media queries.
Cross-Media Query #extend Directives in Sass
See the article for full details but the gist is that you call a mixin 'placeholder' that then decides whether to output #extend or an #include.
#include placeholder('clear') {
clear: both;
overflow: hidden;
}
.a {
#include _(clear);
}
.b {
#include _(clear);
}
.c {
#include breakpoint(medium) {
#include _(clear);
}
}
Ultimately it may not be better than just using mixins, which is currently the accepted answer.
I use breakpoints, but it's the same idea:
#mixin bp-small {
#media only screen and (max-width: 30em) {
#content;
}
How to use it:
.sidebar {
width: 60%;
float: left;
#include bp-small {
width: 100%;
float: none;
}
}
There is a text about mixins where you can find out more about this option.
Could you restructure?
.compact { //compact-styles }
.item {}
.item.compact { #extend .compact }
#media (max-width: 600px) {
.item { #extend .compact; }
}
If I understand the documentation correctly, that should work. I think the reason the way you're trying won't work is that it doesn't see .item.compact when it's parsing the #extend, but that's an uninformed guess, so take that with a truck load of salt! :)

Resources