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.