Can I set a global variable using a media query? - css

I have a code smell that looks like this:
$mobile-bg-color: #ddddff;
$desktop-bg-color: #ffdddd;
$mobile-border: solid 2px black;
$desktop-border: solid 2px red;
div {
margin: 50px;
#media screen and (max-width: $mobile_threshold){
background-color: $mobile-bg-color;
border: $mobile-border;
}
#media screen and (min-width: $mobile_threshold + $threshold_step){
background-color: $desktop-bg-color;
border: $desktop-border;
}
}
And I'm having to do this anywhere where details might be different between mobile and desktop.
What I'd really like to do is:
div {
margin: 50px;
border: $responsive-border;
background-color: $responsive-bg-color;
}
This is possible using Sass?

You can achieve this with a mixin. Define a mixin like so:
#mixin responsive-border {
#media screen and (max-width: $mobile_threshold){
background-color: $mobile-bg-color;
border: $mobile-border;
}
#media screen and (min-width: $mobile_threshold + $threshold_step){
background-color: $desktop-bg-color;
border: $desktop-border;
}
}
Then call it like this:
div {
margin: 50px;
#include responsive-border;
}
You can do the same for any set of rules you will use often. Mixins help keep your code DRY.

Expanding on jmargolisvt's answer - you can also pass in the name of a property to the mixin, and have it resolve that.
eg.
#mixin responsive-bg-color ($prop){
#media screen and (max-width: $mobile_threshold){
#{$prop} : #ddddff;
}
#media screen and (min-width: $mobile_threshold + $threshold_step){
#{$prop} : #ffffdd;
}
}
#mixin responsive-margin-value($prop) {
#media screen and (max-width: $mobile_threshold){
#{$prop} : 2px
}
#media screen and (min-width: $mobile_threshold + $threshold_step){
#{$prop} : 20px
}
}
div {
margin: 50px;
border: solid 2px;
#include responsive-bg-color ("background-color");
#include responsive-margin-value("padding-top");
}
p {
#include responsive-margin-value("padding-bottom");
background-color: #ddeedd;
}
This is a little limited, as you won't be able to use shorthand css for example, but it works.

Related

Why don't Sass respect the order of CSS property using nested media query?

Why don't Sass respect the order of CSS property using nested media query?
Input Sass:
margin-top: 3px appears after the media query.
.myContainer {
margin: 1px;
#media only screen and (min-width: 768) {
margin: 2px;
};
margin-top: 3px;
}
Output CSS:
margin-top: 3px now appears before the media query.
.myContainer {
margin: 1px;
margin-top: 3px;
}
#media only screen and (min-width: 768) {
.myContainer {
margin: 2px;
}
}
In this example, you can see that the position of margin-top:3px is changed.
How could this happen and is it expected?
It is the expected result. Otherwise, it will have to create two separate classes like in the second snippet below. This wouldn't make sense. Try this:
.myContainer {
margin: 1px;
#media only screen and (min-width: 768px) {
margin: 2px;
};
& {
margin-top: 3px;
}
}
Output:
.myContainer {
margin: 1px;
}
#media only screen and (min-width: 768px) {
.myContainer {
margin: 2px;
}
}
.myContainer {
margin-top: 3px;
}

CSS: composing class names inside media queries

I have some styles inside a class which can be used standalone, but I would also like to apply these styles to another class when a media query condition is met. Below is an example.
I have two classes: light and dark.
.light {
border: 1px solid;
background-color: white;
}
.dark {
border: 1px solid black;
background-color: black;
color: white;
}
<h2>light</h2>
<div class="light">foo</div>
<h2>dark</h2>
<div class="dark">foo</div>
Now I want to compose these class names to create a new version: light on mobile (i.e. narrow screens), dark on desktop (i.e. wide screens).
The only way I'm aware of doing this is by duplicating my styles:
#media (max-width: 499px) {
.lightOnMobileAndDarkOnDesktop {
border: 1px solid;
background-color: white;
}
}
#media (min-width: 500px) {
.lightOnMobileAndDarkOnDesktop {
border: 1px solid black;
background-color: black;
color: white;
}
}
<h2>light on mobile, dark on desktop</h2>
<div class="lightOnMobileAndDarkOnDesktop">foo</div>
However I would like to achieve this without duplicating the styles for my classes, and without JavaScript.
Here is some pseudo code which illustrates what I would like to achieve:
#media (max-width: 499px) {
.lightOnMobileAndDarkOnDesktop {
#extend .light;
}
}
#media (min-width: 500px) {
.lightOnMobileAndDarkOnDesktop {
#extend .dark;
}
}
If there isn't any way to achieve something to this effect today, my next question would be: are there any proposals for CSS that would allow me to achieve this in the future?

SASS media queries best practise?

Is it ok to nest media queries inside an element? If I want to use min-width: 480px in another places there will be huge repetition. Please look at my code example. Or just use the old way? Any idea?
SASS
.navbar {
height: 500px;
width: 500px;
#media screen and (min-width: 480px) {
background-color: lightgreen;
}
}
.items {
padding: 15px;
color: red;
#media screen and (min-width: 480px) {
border: 1px solid black;
}
}
CSS
#media screen and (min-width: 480px) {
.navbar {
background-color: lightgreen;
}
.items {
border: 1px solid black;
}
}
$pc: 1024px; // PC screen size.
$tablet: 720px; // Tablet screen size.
$phone: 320px; // Phone screen size.
#mixin responsive($media) {
#if $media= phone {
#media only screen and (max-width: $tablet - 1) {
#content;
}
}
#else if $media= tablet {
#media only screen and (min-width: $tablet - 1) and (max-width: $pc) {
#content;
}
}
#else if $media= pc {
#media only screen and (min-width: $pc + 1) and (min-width: $pc) {
#content;
}
}
#else if $media= pc_tablet {
#media only screen and (min-width: $tablet - 1) {
#content;
}
}
}
Examples
body {
#include responsive(pc) {
background: red;
}
#include responsive(tablet) {
background: yellow;
}
#include responsive(phone) {
background: green;
}
}

responsive design - which type of css does it use?

when i have this Code
HTML
<div id = 'bl'>
</div>
CSS
#bl {
font-size: 12px;
Color: #ff0000;
......
}
#media only screen and (min-width: 0px) and (max-width: 799px)
{
#bl {
border: 1px solid #ff0000;
}
}
it's only an example.
which type of Code does it use when the Screen size is between 0 and 799? both or only the one in media query without the other "bl" (font-size...)?
The styles get applied from a top down approach. So, the first style would be read and computed, then the media query styles would overwrite the styles above if the screen is within 0 and 799px.
Both.
but if you had :-
#bl {
font-size: 12px;
Color: #ff0000;
...
border: 2px solid red;
Then the border in media query would then override.

Break out of scope

Ideally, I would like to do this :
#w: 4px;
#media (max-width:900px) {
#r: 3px;
}
#media (min-width:900px) {
#r: 5px;
}
.myclass {
border-radius: #w + #r;
}
This doesn't compile because #r isn't defined in the scope where I define .myclass. The obvious solutions are either to define .myclass inside the #media blocs or to copy the #media queries inside the definition of .myclass.
But as soon as you use #r in many classes, both solutions are messy and involve many duplications.
Is there a clean dry solution ?
Just use a mixin, that calculates the property values according to the mediaquery. It is unnecessary to do this via import.
LESS:
#w: 4px;
.bordermixin(#w,#r) {
.myclass{
border-radius: #w + #r;
}
}
#media (max-width:900px) {
.bordermixin(#w,3px);
}
#media (min-width:900px) {
.bordermixin(#w,5px);
}
CSS:
#media (max-width: 900px) {
.myclass{
border-radius: 7px;
}
}
#media (min-width: 900px) {
.myclass{
border-radius: 9px;
}
}
I found a solution, based on #import, which lets me keep dry.
I make two files :
classes.less
#w: 4px;
.myclass {
border-radius: #w + #r;
}
mediawidth.less
#media (max-width:900px) {
#r: 3px;
#import "classes.less";
}
#media (min-width:900px) {
#r: 5px;
#import "classes.less";
}
Generated CSS :
#media (max-width: 900px) {
.myclass {
border-radius: 7px;
}
}
#media (min-width: 900px) {
.myclass {
border-radius: 9px;
}
}
This way I don't have to repeat the many classes definition but only the import.
I accepted Martin's answer, which is much cleaner in the most common case when there are only a few numbers of variables to pass. My solution might be dryer and cleaner as soon as you have more variables and when your classes are defined in many files.

Resources