I\'m trying to combine the use of a Sass variable with @media queries as follows:
$base_width:1160px;
@media screen and (max-width: 1170px) {$base_width: 96
This isn't possible with SASS, but it is possible with CSS variables (or CSS custom properties). The only drawback is browser support – but there's actually a PostCSS plugin - postcss-css-variables - that "flattens" the use of CSS variables (which gives you support for older browsers, too).
The following example works great with SASS (and with postcss-css-variables you get support for older browsers too).
$mq-laptop: 1440px;
$mq-desktop: 1680px;
:root {
--font-size-regular: 14px;
--gutter: 1rem;
}
// The fact that we have to use a `max-width` media query here, so as to not
// overlap with the next media query, is a quirk of postcss-css-variables
@media (min-width: $mq-laptop) and (max-width: $mq-desktop - 1px) {
:root {
--font-size-regular: 16px;
--gutter: 1.5rem;
}
}
@media (min-width: $mq-desktop) {
:root {
--font-size-regular: 18px;
--gutter: 1.75rem;
}
}
.my-element {
font-size: var(--font-size-regular);
padding: 0 calc(var(--gutter) / 2);
}
This would result in the following CSS. The repetitive media queries will increase the file size, but I have found that the increase is usually negligible once the web server applies gzip
(which it will usually do automatically).
.my-element {
font-size: 14px;
padding: 0 calc(1rem / 2);
}
@media (min-width: 1680px) {
.my-element {
padding: 0 calc(1.75rem / 2);
}
}
@media (min-width: 1440px) and (max-width: 1679px) {
.my-element {
padding: 0 calc(1.5rem / 2);
}
}
@media (min-width: 1680px) {
.my-element {
font-size: 18px;
}
}
@media (min-width: 1440px) and (max-width: 1679px) {
.my-element {
font-size: 16px;
}
}
With @ronen's great answer and a map, there's some real power available:
@mixin styling($map) {
.myDiv {
background: map-get($map, 'foo');
font-size: map-get($map, 'bar');
}
}
@media (min-height: 500px) {
@include styling((
foo: green,
bar: 50px
));
}
@media (min-height: 1000px) {
@include styling((
foo: red,
bar: 100px
));
}
It's now possible to have lots more DRY media queries targeting .myDiv
with a bunch of different values.
Map docs: https://sass-lang.com/documentation/functions/map
Example map usage: https://www.sitepoint.com/using-sass-maps/
I had the same problem.
The $menu-width
variable should be 240px on the mobile view @media only screen and (max-width : 768px)
and 340px on the desktop view.
So i have simply created two variables:
$menu-width: 340px;
$menu-mobile-width: 240px;
And here is how i have used it:
.menu {
width: $menu-width;
@media only screen and (max-width : 768px) {
width: $menu-mobile-width;
}
}
Similar to Philipp Zedler's answer, you can do it with a mixin. That lets you have everything in a single file if you want.
@mixin styling($base-width) {
// your SCSS here, e.g.
#Contents {
width: $base-width;
}
}
@media screen and (max-width: 1170px) {
@include styling($base-width: 960px);
}
@media screen and (min-width: 1171px) {
@include styling($base-width: 1160px);
}
Edit: Please do not use this solution. The answer by ronen is much better.
As a DRY solution, you can use the @import
statement inside a media query, e.g. like this.
@media screen and (max-width: 1170px) {
$base_width: 960px;
@import "responsive_elements";
}
@media screen and (min-width: 1171px) {
$base_width: 1160px;
@import "responsive_elements";
}
You define all responsive elements in the file included using the variables defined in the media query. So, all you need to repeat is the import statement.
This is simply not possible. Since the trigger @media screen and (max-width: 1170px)
happens on the client-side.
Achieving your expected result would only be possible if SASS grabbed all rules and properties in your stylesheet containing your $base_width
variable and copied/changed them accordingly.
Since it won't work automatically you could do it by hand like this:
@media screen and (max-width: 1170px)
$base_width: 960px // you need to indent it to (re)set it just within this media-query
// now you copy all the css rules/properties that contain or are relative to $base_width e.g.
#wrapper
width: $base_width
...
@media screen and (min-width: 1171px)
$base_width: 1160px
#wrapper
width: $base_width
...
This is not really DRY but the best you can do.
If the changes are the same every time you could also prepare a mixin containing all the changing values, so you wouldn't need to repeat it. Additionally you can try to combine the mixin with specific changes. Like:
@media screen and (min-width: 1171px)
+base_width_changes(1160px)
#width-1171-specific-element // additional specific changes, that aren't in the mixin
display: block
And the Mixin would look like this
=base_width_changes($base_width)
#wrapper
width: $base_width