Styles for multiple breakpoints in SASS - sass

I've defined two mixins in SASS that allow me to place media queries easily. The problem I'm encountering is that I'm repeating myself frequently across many queries. That is to say, some of my style changes are the same for tablet and mobile breakpoints and others are different. Example:
.foo
float: left
width: 50%
+tablet()
float: none
display: block
width: 100%
+mobile()
float: none
display: block
width: 100%
Where my mixins are defined like this:
=tablet
#media (min-width: #{$mobile-width} + 1) and (max-width: #{$tablet-width})
#content
=mobile
#media (max-width: #{$mobile-width})
#content
I'd love to do something like this:
...
+tablet(), +mobile
float: none
display: block
width: 100%
That doesn't compile, so what is the best way to keep my SASS stylesheets DRY?

You can define mobile and tablet medias as strings and then concatenate these strings.
Scss can be easily converted to sass.
$mobile-width: 320px;
$tablet-width: 760px;
// Media queries as strings
$tablet: "(min-width: #{$mobile-width + 1}) and (max-width: #{$tablet-width})";
$mobile: "(max-width: #{$mobile-width})";
// Converts a list to a string with delimiters between elements
#function join-list($list, $separator: ", ") {
$result-string: "";
#each $item in $list {
// Index of the current item of `$list` list
$index: index($list, $item);
$result-string: $result-string + $item;
// If this is not the last item, adds separator
#if ($index != length($list)) {
$result-string: $result-string + $separator;
}
}
#return $result-string;
}
#mixin get-media($medias...) {
#media #{join-list($medias, " and ")} {
#content;
}
}
.foo {
float: left;
width: 50%;
#include get-media($mobile, $tablet) {
// or #include get-media($mobile) {
// or #include get-media($tablet) {
float: none;
display: block;
width: 100%;
}
}
Css output:
.foo {
float: left;
width: 50%;
}
#media (max-width: 320px) and (min-width: 321px) and (max-width: 760px) {
.foo {
float: none;
display: block;
width: 100%;
}
}
SassMeister demo.

As per #Stefan F's comment, the easiest thing to do in this case was to create a third mixin called (something like): +both() which encapsulated the mobile and tablet sizing. (I'm answering this myself only because he did not and it has been some time.)
Example:
=both
#media (max-width: #{$tablet-width})
#content
Usage:
.foo
float: left
width: 50%
+both()
float: none
display: block
width: 100%

Related

SCSS: Can I only #include in response to a successful #media?

With SCSS files, I am attempting to make a responsive layout by setting variables in response to an #media query.
I currently have two #media queries, and I was hoping that only one of them would proceed to call the #mixin, with the map defined for the specific situation: mobile or desktop.
My code is :
$page-header-height : 45px; // some dummy defaults
$page-subheader-height: 45px;
$page-footer-height : 50px;
$mobile-varmap : (
"page-header-height" : 50px,
"page-subheader-height": 50px
);
$desktop-varmap : (
"page-header-height" : 90px,
"page-subheader-height": 120px
);
#mixin setvariables($map) {
$page-header-height: map-get($map, "page-header-height") !global;
$page-subheader-height: map-get($map, "page-subheader-height") !global;
$page-footer-height: 50px;
}
$screen-size-mobile: 360px;
$screen-size-tablet: 600px;
#media screen and (min-width:$screen-size-mobile) {
body {
#include setvariables($mobile-varmap);
}
}
#media screen and (min-width:$screen-size-tablet) {
body {
#include setvariables($desktop-varmap);
}
}
div.page-wrapper {
display: grid;
grid-template-areas: 'page-header''page-subheader''page-content''page-footer';
grid-template-columns: auto;
grid-template-rows: $page-header-height $page-subheader-height 1fr $page-footer-height;
max-height: calc(100vh - 55px); // TODO: use variables to calc these
min-height: calc(100vh - 50px);
overflow: none;
}
I had expected that this would lead to $page-header-height, etc, being set according to the matching #media query, but the result is that whichever #media query appears last in the code, determines the values which are produced.
What would I need to do in order to call setvariables() with the varmap that corresponds to the screen size?
NB: I only added the body tags to the #media queries in response to viewing some examples - I'm not sure that they are correcty used or indeed necessary.
Your code is fine, but as i understand it, you expect the variables set via #include setvariables($desktop-varmap); to dynamically respond to device width... which will not happen because the two blocks with the media query do not render anything, the variables are just changed at compile time.
A possible way to build what you want is to have only one configuration map which then could be iterated over like
#mixin setvariables($map) {
$page-header-height: map-get($map, "page-header-height") !global;
$page-subheader-height: map-get($map, "page-subheader-height") !global;
$page-footer-height: 50px !global;
}
$responsive-vars: (
mobile: (
min-width: 360px,
page-header-height: 50px,
page-subheader-height: 50px
),
desktop: (
min-width: 600px,
page-header-height: 90px,
page-subheader-height: 120px
)
);
#each $alias, $map in $responsive-vars {
#media screen and (min-width: map-get($map, 'min-width')) {
#include setvariables($map);
div.page-wrapper {
display: grid;
grid-template-areas: 'page-header''page-subheader''page-content''page-footer';
grid-template-columns: auto;
grid-template-rows: $page-header-height $page-subheader-height 1fr $page-footer-height;
max-height: calc(100vh - 55px); // TODO: use variables to calc these
min-height: calc(100vh - 50px);
overflow: none;
}
}
}
However this is not the most practical approach, since mostly you want to tweak only some values and have other declarations for all devices. Instead, i'd recommend to drop the setvariables() mixin entirely and access the maps directly like:
// https://css-tricks.com/snippets/sass/deep-getset-maps/#deep-get
#function map-deep-get($map, $keys...) {
#each $key in $keys {
$map: map-get($map, $key);
}
#return $map;
}
$responsive-vars: (
mobile: (
min-width: 360px,
page-header-height: 50px,
page-subheader-height: 50px
),
desktop: (
min-width: 600px,
page-header-height: 90px,
page-subheader-height: 120px
)
);
div.page-wrapper {
display: grid;
grid-template-areas: 'page-header''page-subheader''page-content''page-footer';
grid-template-columns: auto;
max-height: calc(100vh - 55px); // TODO: use variables to calc these
min-height: calc(100vh - 50px);
overflow: none;
#media screen and (min-width: map-deep-get($responsive-vars, 'mobile', 'min-width')) {
grid-template-rows:
map-deep-get($responsive-vars, 'mobile', 'page-header-height')
map-deep-get($responsive-vars, 'mobile', 'page-subheader-height')
1fr
map-deep-get($responsive-vars, 'mobile', 'page-footer-height');
}
#media screen and (min-width: map-deep-get($responsive-vars, 'desktop', 'min-width')) {
grid-template-rows:
map-deep-get($responsive-vars, 'desktop', 'page-header-height')
map-deep-get($responsive-vars, 'desktop', 'page-subheader-height')
1fr
map-deep-get($responsive-vars, 'desktop', 'page-footer-height');
}
}
This may look like a lot of code at first glance, but it renders far less css.

no style changes without "!important" in media queries

Error with scss code, can't style anything in media queries without "!important". What could be wrong and also everytime I save any scss file other than main.scss it causes an error but when I save the main.scss file then it works fine. Any suggestions? I'm using webpack.
.loading {
width: 100%;
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
.logo {
width: 80%;
}
}
#media screen and (min-width: 8em) and (orientation: landscape) {
.logo {
width: 60% !important;
}
}
#media screen and (min-width: 767px) {
.logo {
width: 40% !important;
}
}
#media screen and (min-width: 1200px) {
.logo {
width: 20% !important;
}
}
The problem seems to be that you are using .logo inside .loading
try to do it like this
.loading {
width: 100%;
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
}
.logo {
width: 80%;
}
This way you should be able to use the media queries without !important.
The nested way has higher complexity than the media query so that's why you had to use !important.

Media queries in Sass

I am wondering if there is a way to write media queries in sass, so I can give a certain style between let's say: 300px to 900px
in css it looks like this
#media only screen and (min-width: 300px) and (max-width: 900px){
}
I know I can write
#media (max-width: 900px)
in sass but how to make that range?
$small: 300px;
$medium: 900px;
.smth {
//some CSS
#media screen and (max-width: $small) {
//do Smth
}
#media screen and (min-width: $medium) {
//do Smth
}
}
Something like this?
This is what I use for a Mixin with sass, it allows me to quickly reference the breakpoint that I want. obviously you can adjust the media query list to suite your project mobile fist etc.
But it will jin multiple queries for you as I believe you're asking for.
$size__site_content_width: 1024px;
/* Media Queries */ Not necessarily correct, edit these at will
$media_queries : (
'mobile' : "only screen and (max-width: 667px)",
'tablet' : "only screen and (min-width: 668px) and (max-width: $size__site_content_width)",
'desktop' : "only screen and (min-width: ($size__site_content_width + 1))",
'retina2' : "only screen and (-webkit-min-device-pixel-ratio: 2) and (min-resolution: 192dpi)",
'retina3' : "only screen and (-webkit-min-device-pixel-ratio: 3) and (min-resolution: 288dpi)",
'landscape' : "screen and (orientation:landscape) ",
'portrait' : "screen and (orientation:portrait) "
);
#mixin for_breakpoint($breakpoints) {
$conditions : ();
#each $breakpoint in $breakpoints {
// If the key exists in the map
$conditions: append(
$conditions,
#{inspect(map-get($media_queries, $breakpoint))},
comma
);
}
#media #{$conditions} {
#content;
}
}
Use it like this in your scss:
#masthead {
background: white;
border-bottom:1px solid #eee;
height: 90px;
padding: 0 20px;
#include for_breakpoint(mobile desktop) {
height:70px;
position:fixed;
width:100%;
top:0;
}
}
Then this will compile to:
#masthead {
background: white;
border-bottom: 1px solid #eee;
height: 90px;
padding: 0 20px;
}
#media only screen and (max-width: 667px), only screen and (min-width: 1025px) {
#masthead {
height: 70px;
position: fixed;
width: 100%;
top: 0;
}
}
Check this out for scss.
https://github.com/Necromancerx/media-queries-scss-mixins
Usage
.container {
#include xs {
background: blue;
}
#include gt-md {
color: green
}
}
Demo: Stackblitz
Based on Angular FlexLayout MediaQueries
$small: 300px;
$medium: 900px;
#media screen and (min-width: $small) and (max-width: $medium) {
//css code
}

Access #mixin variable outside of #mixin

So I've got a #mixinthat lets me define my logo width and gives me an automatic height based on the ratio of my logo image.
#mixin m-logoSize($width) {
width: $width;
height: floor($width / 4.72727272727273);
}
I'm trying to find out if there's a way for me to access the $width variable, so I can assign it to a different property like so.
// sass
.logo {
#include m-logoSize(300px);
background-size: $width $height;
}
// translates to this css
.logo {
width: 300px;
height: 63px;
background-size: 300px 63px;
}
Is there any wizardry that makes this possible. Any help is appreciated.
Thanks in advance!
I think you are better off setting global variables for these two values, then you can reach them anywhere.
Example
// Global variables
$logo-width: 0 !default;
$logo-height: floor($logo-width / 4.72727272727273) !default;
// Mixin
#mixin m-logoSize() {
width: $logo-width;
height: $logo-height;
}
// Sass
$logo-width: 300px;
.logo {
#include m-logoSize();
background-size: $logo-width $logo-height;
}
Update
To change the value at different breakpoints you would just set the variable in the scope of the media query.
Responsive Example
.logo {
#media screen and (max-width: 600px) {
$logo-width: 150px;
#include m-logoSize();
background-size: $logo-width $logo-height;
}
#media screen and (min-width: 601px) {
$logo-width: 300px;
#include m-logoSize();
background-size: $logo-width $logo-height;
}
}

sass code style with media queries

I'm doing a code review for sass code and came across using media queries inside the code. Is it a good practice? Are there better alternatives to writing this code?
.col-md-push-8 {
padding-top: 1.5em;
.btn {
&.btn-block {
border: none;
background-color: $footer-button;
margin: 1em 0 .5em;
width: 100%;
padding: 7px 10px;
border-radius: 8px;
&:hover {
background-color: $footer-button-hover;
}
#media (min-width: $screen-md-min) {
color: #025191;
&:hover .media span p.media-heading {
color: #0070ca;
}
}
}
}
}
Note: The code is for illustration purpose only and is not completely shown here.
I think that what your way to do it is perfectly fine if you're using SASS >= 3.2 (was buggy before).
Just one thing that you could do to define your media queries breakpoints more globally is to create a mixin for that purpose that you will re-use on each element you need responsive.
This way when you have to change let's say your min breakpoint, add another or change your media min-width to max-width, you don't have to do it everywhere.
Some little example assuming you have already defined $screen-md-min and $screen-md-mid :
#mixin custom-media($size) {
#if ($size == $small) {
#media (min-width: $screen-md-min) { #content; }
}
#else if ($size == $middle) {
#media (min-width: $screen-md-mid) { #content; }
}
}
And call it like so :
.btn {
&.btn-block {
...
#include custom-media($small) {
color: #025191;
&:hover .media span p.media-heading {
color: #0070ca;
}
}
}
}
There is no difference if you put Media Query inside or outside. It just depends on your preffered style.
Style 1
.some-class {
#media (min-width: 700px) {
background: red;
}
}
Style 2
#media (min-width: 700px) {
.some-class {
background: red;
}
}
Both will compile as:
#media (min-width: 700px) {
.some-class {
background: red;
}
}
Sass handles this fine, but that code is going to produce overly qualified selectors and is hardly concise.
There are a number of patterns for writing “better” CSS and Sass, such as BEM, OOCSS, OOCSS + Sass, and SMACSS.
There's also a bunch of great information on Media Queries in Sass that is probably worth a read.

Resources