Break out of scope - css

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.

Related

Can we nest media queries (SASS) that doesn't add to the overall size of the compiled output via Gulp?

Using Gulp: The idea is to write media queries inline and nest as needed but in the compiled source they are nested under a singular media query. Ideas on if this is currently possible?
Example:
.selector {
background-color: #efefef;
#media screen and (min-width: $break-tabletSmall) {
background-color: #000;
}
}
.selector-2 {
background-color: #ddd;
#media screen and (min-width: $break-tabletSmall) {
background-color: #fff;
}
}
This currently compiles into something like this:
.selector {
background-color: #efefef;
}
#media screen and (min-width: $break-tabletSmall) {
.selector {
background-color: #000;
}
}
.selector-2 {
background-color: #ddd;
}
#media screen and (min-width: $break-tabletSmall) {
.selector-2 {
background-color: #fff;
}
}
The desired outcome: Note the size is a bit smaller as there is a singular media query referenced.
.selector {
background-color: #efefef;
}
.selector-2 {
background-color: #ddd;
}
#media screen and (min-width: $break-tabletSmall) {
.selector {
background-color: #000;
}
.selector-2 {
background-color: #fff;
}
}
This issue in Sass Github is related to this problem. And you have this:
These optimizations are no longer planned. Sass does what it can to eliminate extra whitespace and choose the smallest possible representation for values, but it's primary focus is being the best preprocessing language it can be rather than the best CSS compressor.
So actually you should use PostCSS and maybe postcss-combine-media-query plugin. Or I found this gulp plugin. My recommendation for CSS optimizations and compression is PostCSS.
But if you want to solve this issue only with Sass, you can use output buffering as said by heygrady in the issue linked above.

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 rules not overridden with another rules after them

I have the following code both in two CSS tiles with different values (using LESS).
The CSS is linked in link tag in the header. The all.css is positioned before the override.css. The problem is that when I browse the site, I can't see any changes and it only uses the code in the all.css instead of overriding it with the one in override.css.
#subheader h1 {
font-size: 3vw;
#media screen and (max-width: 39.9375em) {
font-size: 3vw;
}
#media screen and (min-width: 40em) {
font-size: 3vw;
;
}
/* Large and up */
#media screen and (min-width: 64em) {
font-size: 3vw;
}
}
How can I make so that the rules override without using !important?
There is no problem with the LESS compilation and it results in a correct CSS file, this is why I have no idea why it's not working.
You are using completely wrong syntax of writing css #media rule. Follow this w3schools link, the correct syntax should be:
#media not|only mediatype and (media feature and|or|not mediafeature) {
CSS-Code;
}
The correct code will be:
#subheader h1 {
font-size: 3vw;
}
#media screen and (max-width: 39.9375em) {
#subheader h1 {
font-size: 3vw;
}
}
#media screen and (min-width: 40em) {
#subheader h1 {
font-size: 3vw;
}
}
/* Large and up */
#media screen and (min-width: 64em) {
#subheader h1 {
font-size: 3vw;
}
}
Try this :
#subheader h1 {
font-size: 3vw;
}
#media screen and (max-width: 39.9375em) {
font-size: 3vw;
}
#media screen and (min-width: 40em) {
font-size: 3vw;
;
}
/* Large and up */
#media screen and (min-width: 64em) {
font-size: 3vw;
}

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.

Can I set a global variable using a media query?

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.

Resources