Translating media queries from LESS to SCSS - sass

I'm trying to update some old LESS style sheets into SCSS but am running into an issue translating media queries.
The LESS variables are as follows:
#lg: ~"(min-width: 1201px)";
#md: ~"(min-width: 993px)";
#sm: ~"(min-width: 769px)";
#xs: ~"(max-width: 768px)";
And are referenced in this manner:
.modal-dialog {
margin: 100px auto;
#media #md {
width: 880px;
}
}
I've translated this into the following SCSS variables:
$lg: "#{min-width: 1201px}";
$md: "#{min-width: 993px}";
$sm: "#{min-width: 769px}";
$xs: "#{max-width: 768px}";
and the following usage:
.modal-dialog {
margin: 100px auto;
#media ($md) {
width: 880px;
}
}
The code in question belongs to a .Vue component and is being compiled using SASS Loader FWIW. The code compiles (no errors) but the actual queries don't seem to be working. Thanks!

In SCSS / SASS the recommended approach to storing full media queries as variables is as follows:
$lg: "(min-width: 1201px)";
.modal-dialog {
margin: 100px auto;
#media #{$lg} {
width: 880px;
}
}
Which compiles to
.modal-dialog {
margin: 100px auto;
}
#media (min-width: 1201px) {
.modal-dialog {
width: 880px;
}
}

Related

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.

Styles for multiple breakpoints in 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%

Bubble up rules in SASS for variation / theme classes

How does one handle making "variation classes" in Sass? Example:
.bookshelf {
color: brown;
height: 100px;
.panel {
trimmed: no;
height: 10px;
}
.door {
height: 100px;
.knob {
shape: circle;
height: 10px;
}
}
}
You want to make a .bookshelf.small variation. Is there a way to write the variation code inside the main element using mixins or something that would "bubble up" the data?
.bookshelf {
color: brown;
height: 100px;
#include small-version {
height: 50px;
}
.panel {
trimmed: no;
height: 10px;
#include small-version {
height: 5px;
}
}
.door {
height: 100px;
#include small-version {
height: 50px;
}
.knob {
shape: circle;
height: 10px;
#include small-version {
height: 5px;
}
}
}
}
And the output of the mixin would be
.bookshelf.small {
height: 50px;
.panel {
height: 5px;
}
.door {
height: 50px;
.knob {
height: 5px;
}
}
Several things looked promising, such as the #at-root function and #content function, but neither would work for this scenario. I know if I write #media settings, they will bubble up. But I do not want this tied to a media query, I want this tied to a specific class (if .bookshelf also has the class small, apply these rules).
There is a small hack about it. But you should work with it really carefully. And it's not so good as you ask.
First of all, it prepends theme class to selector, so you can't use any element selectors. There is actually lot of selector helpers in docs but i didn't found any that could help with real parsing selector string.
Second it's not grouping out selectors. It inserts rules right where mixin were included. But it generates higher priority rules for your styles, so it could be a half a way solution.
You can dig for postcss parser or any other file post processing tool that could help you to separate your styles in a different files.
#mixin small-version {
#at-root .small#{&} {
#content;
}
}
.bookshelf {
color: brown;
height: 100px;
#include small-version {
height: 60px;
}
.panel {
trimmed: no;
height: 10px;
#include small-version {
height: 5px;
}
}
.door {
height: 100px;
.knob {
shape: circle;
height: 10px;
}
}
}
Gist link
You can qualify a selector by putting & to the right of the intended parent of the selector. Wrapping it in #{} allows you to place it directly beside that parent.
The #at-root rule causes everything proceeding it to be emitted at the root instead of using regular nesting.
If you use both, you can achieve what you are looking for.
.flashlight {
.light {
background: yellow;
#at-root .dead-battery#{&} {
background: transparent;
}
.daytime &{
background: transparent;
}
}
}
This would compile to:
.flashlight .light {
background: yellow;
}
.dead-battery.flashlight .light {
background: transparent;
}
.daytime .flashlight .light {
background: transparent;
}

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.

How to convert this SCSS mixin to LESS?

I am used to coding in SCSS but pretty new to LESS.
I have the following code in SCSS but would like to know how to write this in LESS.
Here is the SCSS code...
#mixin posL($property, $value) {
{$property}: $value;
}
.box {
width:200px;
height:200px;
background:red;
position:absolute;
#include posL(left, 100px);
}
So far I have something like this in LESS but I have to declare selectors...
.posL(#property: 100px, #value: 2px) {
left: #property;
-rtl-left: #value;
}
.box {
width:200px;
height:200px;
background:red;
position:absolute;
.posL(200px);
}
Is there a better way to write my LESS code so the selectors in the mixin remain generic (not specified)?
Update for LESS 1.6+
It is almost a direct mapping now with the 1.6 update, like so:
LESS
.posL(#property, #value) {
#{property}: #value;
}
.box {
width:200px;
height:200px;
background:red;
position:absolute;
.posL(left, 100px);
}
CSS Output
.box {
width: 200px;
height: 200px;
background: red;
position: absolute;
left: 100px;
}
Original Answer (pre 1.6)
There is currently no real way to do dynamic property names in LESS (whether for prefixing or for full property names ,like you want), though there is discussion about it.
I recommend a generic mixin with a nested, guarded mixin for the logic. This still gives you selection to specific properties, but does require some more explicit code to set it up. Something like:
.posL(#property, #value) {
.getProp(left) {
left: #value;
}
.getProp(-rtl-left) {
-rtl-left: #value;
}
.getProp(#property);
}
Then use it very similar to how you do the SASS version:
.box {
width:200px;
height:200px;
background:red;
position:absolute;
.posL(left, 100px);
}
Compiles to:
.box {
width: 200px;
height: 200px;
background: red;
position: absolute;
left: 100px;
}

Resources