Combine extend and mixin in with same rules - css

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

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

Sass apply css to media query and class in same time

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

Can you create custom breakpoints with LESS mixins?

Most of the time, I use LESS variables with preset breakpoints for media queries like this:
#s-max : ~"screen and (max-width: 40em)";
#m-max : ~"screen and (max-width: 50em)";
#l-max : ~"screen and (max-width: 60em)";
USAGE
.some-class {
color: red;
#media #s-max {
color: blue;
}
}
But sometimes, I would like to be able to refer to an arbitrary breakpoint in my .less stylesheet without having to set a new preset value in my separate mixin file.
You can do this in SASS. The mixin looks like this:
#mixin bp-min($canvas) {
#media only screen and (min-width:$canvas) {#content;}
}
USAGE
#include bp-min(750px) {
//responsive styling for min-width of 750px
}
In LESS, I'm imagining the equivalent mixin would look something like this:
.bp-min(#min) {
#media only screen and (min-width:#min)...
}
The only problem is, the lack of the {#content} argument in LESS, which grabs the rest of the styling inputted by the developer. I love SASS, but I can't use it at work.
Does anyone know of a LESS-based solution to this problem?
It is now similar to SASS
As of 1.7.0 (2014-02-27) you can now use #rules in place of the sassy #content.
For example:
.breakpoint-small(#rules) {
#media screen and (min-width: 40em) { #rules(); }
}
ul {
width: 100%;
.breakpoint-small({
width: 50%;
});
}
outputs, as expected:
ul {
width: 100%;
#media screen and (min-width: 40em) {
width: 50%;
}
}
The differences being:
function takes #rules as an argument
additional parenthesis when invoking the function
'.' syntax as opposed to '#include'
This can be combined with an additional argument to provide syntax equivalent to a nice bit of sass:
.breakpoint(#size, #rules) {
#media screen and (min-width: #size) { #rules(); }
}
#large: 60em;
ul {
.breakpoint(#large, {
width: 50%;
});
}
edit: To be honest I prefer a way more simple approach in less:
#break-large: ~"screen and (min-width: 60em)";
ul {
#media #break-large {
width: 50%;
}
}
Source: I too use sass at home and less at work
Using Pattern Matching
I believe this achieves what you want:
LESS
/* generic caller */
.bp-min(#min) {
#media only screen and (min-width:#min) {
.bp-min(#min, set);
}
}
/* define them */
.bp-min(750px, set) {
test: (#min - 300px);
}
.bp-min(400px, set) {
test: (#min - 100px);
}
/* call them */
.bp-min(750px);
.bp-min(400px);
Output CSS
#media only screen and (min-width: 750px) {
test: 450px;
}
#media only screen and (min-width: 400px) {
test: 300px;
}
By defining a set pattern mixin for the various sizes, and then using that pattern within the generic .bp-min(#min) mixin, I believe we have the same abstraction in LESS that you have in SCSS, with slightly more code because I believe SCSS defines and calls in one #include statement, whereas here we need two.
(In addition to the prev. answer) Or something like this:
.bp-min(#canvas) {
#media only screen and
(min-width: #canvas) {.content}
}
// usage:
& { .bp-min(900px); .content() {
color: red;
}}
& { .bp-min(600px); .content() {
color: blue;
}}
// more usage examples:
.class-green {
.bp-min(450px); .content() {
color: green;
}}
& { .bp-min(300px); .content() {
.class-yellow {
color: yellow;
}
.class-aqua {
color: aqua;
}
}}
Replace .content with .- if you prefer shorter stuff.
In my case I needed my variables to reference other variables, so some of these solutions did not work. Here is what I went with.
#bp-xs: ~"screen and (max-width:"#screen-xs-max~")";
#bp-sm: ~"screen and (max-width:"#screen-sm-max~")";
#bp-md: ~"screen and (max-width:"#screen-md-max~")";
#bp-lg: ~"screen and (max-width:"#screen-lg-max~")";
and then use them like so
#media #bp-sm {
...
}

Margins Being Ignored. Specificity Issue

I'm using the Foundation 4 framework, and have run into an issue where the margins are being overridden by the Framework's margins, which means I am unable to apply margins to certain elements without having to use the !important keyword.
Below is my _grid.scss file, which applies the layout grid for mobile browsers.
%row {
#include grid-row;
}
%columns-1 {
#include grid-column(1);
}
%columns-2 {
#include grid-column(2);
}
%columns-3 {
#include grid-column(3);
}
%columns-4 {
#include grid-column(4);
}
%columns-5 {
#include grid-column(5);
}
%columns-6 {
#include grid-column(6);
}
%columns-7 {
#include grid-column(7);
}
%columns-8 {
#include grid-column(8);
}
%columns-9 {
#include grid-column(9);
}
%columns-10 {
#include grid-column(10);
}
%columns-11 {
#include grid-column(11);
}
%columns-12 {
#include grid-column(12);
}
header {
#extend %row;
#branding {
#extend %columns-6;
}
#main-navigation {
#extend %columns-6;
position: absolute;
top: 0;
left: 0;
}
#mobile-navigation-toggle {
}
}
#games-list {
#extend %row;
}
#blog-entries {
#extend %row;
.entry {
#extend %row;
img {
#extend %columns-4;
}
.entry-blurb {
#extend %columns-8;
}
}
}
footer {
#footer-links {
#extend %row;
.link-block {
#extend %columns-6;
}
}
}
And here is the affected line in the base.scss file:
.entry {
margin-bottom: 10px;
.entry-blurb {
.entry-description {
display: none;
}
}
}
It will only work if I apply !important to it. Looking at the Web Dev Tools I can see the issue, but no idea how to solve it:
I think the problem may be because I am defining placeholders in SASS for the grid to avoid code bloat. Usually you would use a mixin, and the code would be included directly within the elements in CSS which would override the margins for that element then.
Extend vs a mixin isn't going to make a difference here. Your selector simply has too much specificity to be overridden by such a simple selector: #blog-entries .entry is a more specific instance of .entry.
You have a few options:
Don't nest your selectors (avoids having such a strong selector like #blog-entries .entry in the first place)
Make your second selector have as much specificity (or more) than the first one
Use !important

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