Sass #content directive includes parent selector - css

I've written a Sass mixin which works as anticipated, except for one problem: the #content directive seems to be including the parent selector, rather than just the content included in parentheses to the mixin.
The mixin:
#mixin breakpoint($parameters){
$query: 'screen and ';
#each $variable, $value in $parameters {
$query: $query + '(' + $variable + ':' + $value + ') and ';
};
$query: str-slice($query, 0, -5);
#media #{$query} { #content; };
}
I'm trying to use it as in the following:
#div {
background-color: blue;
#include breakpoint((max-width:500px)) {
background-color: purple;
};
}
However, this compiles to the following, with the #div id repeated:
#div {
background-color: blue; }
#media screen and (max-width: 500px) {
#div {
background-color: purple; } }
The desired output is:
#div {
background-color: blue;
#media screen and (max-width: 500px) {
background-color: purple;}
}
Any help in fixing this problem is very appreciated!

Related

PostCSS compiling SASS media queries out of order?

I'm using a simple webpack build with PostCSS. If I don't declare a specific media query mixin in the first section of the page's SCSS, but use that specific media query mixin in a following section, that media query outputs after the other breakpoints (even though I have them defined in a specific order in my mixins file). Here's my code:
_variables.scss
$sm-screen: 576px;
$md-screen: 768px;
$lg-screen: 992px;
$xl-screen: 1200px;
_mixins.scss
#mixin sm-screen {
#media screen and (min-width: #{$sm-screen}) {
#content;
}
}
#mixin md-screen {
#media screen and (min-width: #{$md-screen}) {
#content;
}
}
#mixin lg-screen {
#media screen and (min-width: #{$lg-screen}) {
#content;
}
}
#mixin xl-screen {
#media screen and (min-width: #{$xl-screen}) {
#content;
}
}
#mixin screen-size($screen) {
#media screen and (min-width: $screen) {
#content;
}
}
_page.scss
// ————————————————————————————————————————————————————————————
// HERO SECTION
// ————————————————————————————————————————————————————————————
#hero-section {
.hero-heading {
font-size: 2rem;
}
#include sm-screen {
.hero-heading {
font-size: 5rem;
}
}
#include lg-screen {
.hero-heading {
font-size: 6.5rem;
}
}
#include xl-screen {
.hero-heading {
font-size: 6.5rem;
}
}
}
// ————————————————————————————————————————————————————————————
// INTRO SECTION
// ————————————————————————————————————————————————————————————
#intro-section {
.icon-group {
background: red;
}
#include md-screen {
.icon-group {
background: yellow;
}
}
#include xl-screen {
.icon-group {
background: blue;
}
}
}
main.scss (importing files)
#import "/base/variables";
#import "/base/mixins";
#import "page";
As you can see in _page.scss, I like to declare breakpoints right within each section (or row) as I go down the page. The problem is since I didn't declare the #include md-screen breakpoint on the first section, HERO SECTION, it comes after the #include xl-screen breakpoint in the output CSS and overrides the styles of the largest breakpoint:
output CSS:
body.home #intro-section .icon-group {
background: red;
}
#media screen and (min-width:1200px) {
body.home #intro-section .icon-group {
background: blue;
}
}
#media screen and (min-width:768px) {
body.home #intro-section .icon-group {
background: yellow;
}
}
Does this mean that my practice of declaring the breakpoints on each section is not the best way? Should I declare all breakpoints at the end of each file, that way if nothing changes in one section at a specific breakpoint, I don't need to declare that breakpoint at all to get it to compile in the correct order? Is there a way to get media queries to output in the order they're declared in the mixins file, regardless of when the mixins are called in the CSS?
My intent is to get the breakpoints to output from smallest to largest since I'm using the mobile-first, min-width approach. I would love to apply the media queries like I'm doing, but if there's a better way (such as at the end of files), so be it.

Wrap class list with media queries and suffix in SASS

I'm looking for a way to generate responsive utility classes in SASS. I had this CSS
.text-left { text-align: left; }
.text-right { text-align: right; }
#media (min-width: 480px) {
.text-left-sm { text-align: left; }
.text-right-sm { text-align: right; }
}
#media (min-width: 800px) {
.text-left-md { text-align: left; }
.text-right-md { text-align: right; }
}
and I would like to add some more, but I don't want to repeat myself. It would be best if SASS could generate all those responsive (media query) variants for me. So far I was able to write a mixin that I could call with suffix param and get what I want
#mixin textalign($suffix: "") {
.text-left#{$suffix} { text-align: left; }
.text-right#{$suffix} { text-align: right; }
}
#include textalign();
#media (min-width: 480px) {
#include textalign("-sm");
}
#media (min-width: 600px) {
#include textalign("-lg");
}
but I would like to go one step further and be able to do something like this
/* Unfortunatelly this doesn't work */
#include generate-responsive() {
.text-left { text-align: left; }
.text-right { text-align: right; }
}
Is there a way to achieve something like this? Having a general purpose mixin that I can use to generate all kind of utility classes?
I don't think you can accomplish your goal when nesting your selector in the #include, but you can do it when nesting the #include inside the selector.
SCSS input:
#mixin generate-responsive() {
// Create a list of sizes and widths
$sizes: (
sm: "480px",
md: "600px",
lg: "800px"
);
// Base style, without a suffix
#content;
// Responsive styles
// Loop over each size
#each $suffix, $width in $sizes {
#media (min-width: $width) {
&-#{$suffix} { #content; }
}
}
}
.text-left {
#include generate-responsive() {
text-align: left;
}
}
// You'll have to include the mixin for every class
.text-right {
#include generate-responsive() {
text-align: right;
}
}
CSS output:
.text-left {
text-align: left;
}
#media (min-width: 480px) {
.text-left-sm {
text-align: left;
}
}
#media (min-width: 600px) {
.text-left-md {
text-align: left;
}
}
#media (min-width: 800px) {
.text-left-lg {
text-align: left;
}
}
.text-right {
text-align: right;
// Etc...

How to create Sass mixin aliases with support for content blocks?

How can I define multiple names for the same mixin, with support for content blocks?
Definition
#mixin desktop-breakpoint {
#media only screen and (min-width: 769px) {
#content;
}
}
#mixin large-breakpoint {
#include desktop-breakpoint;
}
Usage
.my-class {
font-size: small;
#include desktop-breakpoint {
font-size: big;
}
}
.my-other-class {
color: red;
#include large-breakpoint {
color: blue;
}
}
Error message
Mixin "large-breakpoint" does not accept a content block.
You're not passing any #content when using #include desktop-breakpoint in your large-breakpoint mixin. Doing this will fix your compilation error:
#mixin large-breakpoint {
// Remember to pass content received by mixin to #include
#include desktop-breakpoint {
#content;
}
}
Then your CSS will be compiled properly, as intended:
.my-class {
font-size: small;
}
#media only screen and (min-width: 769px) {
.my-class {
font-size: big;
}
}
.my-other-class {
color: red;
}
#media only screen and (min-width: 769px) {
.my-other-class {
color: blue;
}
}
See proof-of-concept example based on your modified code: https://www.sassmeister.com/gist/3109af060293eed0b89a22c27fa20527

Sass maps - Responsive Typography

I'm trying to write a Sass map to make my headers responsive.
I often use http://type-scale.com/ to set my header font sizes so for e.g. using that my h1 would be 3.998rem.
The problem with that is at mobile sizes it's too big.
You could write media queries for h1 to h6 but that would be too much code.
I've written an example which works for just h1 tags but how could I make it work h1 through to h6 without writing multiple maps?
Cheers
SASS
$headers-responsive: (
null: 1rem,
480px: 1.5rem,
768px: 2rem,
992px: 3rem,
1200px: 4rem
);
#mixin font-scale($font-scaler) {
#each $breakpoint, $value in $font-scaler {
#if($breakpoint == null) {
font-size: $value;
} #else {
#media (min-width: $breakpoint) {
font-size: $value;
}
}
}
}
h1 {
#include font-scale($headers-responsive);
}
CSS
h1 {
font-size:1rem;
}
#media (min-width:480px) {
h1 {
font-size:1.5rem;
}
}
#media (min-width:768px){
h1 {
font-size:2rem;
}
}
#media (min-width:992px){
h1 {
font-size:3rem;
}
}
#media (min-width:1200px){
h1 {
font-size:4rem;
}
}
How about adding a "multiplier" parameter to font-scale()?
Say you want h2 to be 80% of h1, and h3 to be 60% of h1:
...
#mixin font-scale($font-scaler, $multiplier: 1) {
#each $breakpoint, $value in $font-scaler {
#if($breakpoint == null) {
font-size: $value * $multiplier;
} #else {
#media (min-width: $breakpoint) {
font-size: $value * $multiplier;
}
}
}
}
h1 {
#include font-scale($headers-responsive);
}
h2 {
#include font-scale($headers-responsive, .8);
}
h3 {
#include font-scale($headers-responsive, .6);
}

SCSS - best way to organize

Im working with SCSS and I want to structure the code proberly..
In LESS it wasnt a problem, but would you say it is okay to structure the code like below..
imagine that button has its own file.
#mixin button-basic {
.button {
font-size: 14px;
}
}
#mixin button-max-480 {
.button {
color: red;
}
}
#mixin button-max-767 {
.button {
color: green;
}
}
#mixin button-max-959 {
.button {
color: blue;
}
}
#mixin button-min-960 {
.button {
font-size: 34px;
color: purple;
}
}
#media print, screen {
#include button-basic();
}
in my media-query file.. (imagine having multiple includes within each media Query type.)
#media (min-width: 960px) {
#include button-min-960();
}
#media (max-width: 959px) {
#include button-max-959();
}
#media (max-width: 767px) {
#include button-max-767();
}
#media only screen and (max-width:480px) {
#include button-max-480();
}
You could work with #mixins but I would not recommend this approach because this gets really confusing.
I suggest using modifier classes for each variation and use your media-query inside your declaration.
.button {
&--red {
color: red;
}
&--green {
color: green;
}
&--blue {
color: blue;
}
#media (min-width: 768px) {
font-size: 1.125rem;
}
#media (min-width: 960px) {
font-size: 1.25rem;
}
}
This way you have a really clean code base and can split up each component / module into it's own file.

Resources