How to achieve landscape and pixel ration media query with sass-breakpoint - sass

How to achieve this media query with sass breakpoint? ...
#media only screen
and (min-device-width: 375px)
and (max-device-width: 667px)
and (-webkit-min-device-pixel-ratio: 2)
and (orientation: landscape)
I've tried this, but it affects the desktop version as well ...
$mobileLandscape: screen and (min-device-width: 375px) and (max-device-width: 667px) and (-webkit-min-device-pixel-ratio: 2) and (orientation: landscape);
#include breakpoint($mobileLandscape) {
}

This is how to achieve what you want with breakpoint sass (breakpoint-sass bower package).
I have tried it in chrome (and simulate device with web developper tools) and it works.
// With third-party tool
// Breakpoint https://github.com/at-import/breakpoint
// You can find installation instructions here https://github.com/at-import/breakpoint/wiki/Installation
$mobile-landscape-breakpoint: 'only screen' 375px 667px, (-webkit-min-device-pixel-ratio 2), (orientation landscape);
body {
#include breakpoint($mobile-landscape-breakpoint) {
color: blue;
}
}
If breakpoint seems too complicated, You can achieve this with your own code.
For example :
// With Variable
$mobileLandscape: "only screen and (min-device-width: 375px) and (max-device-width: 667px) and (-webkit-min-device-pixel-ratio: 2) and (orientation: landscape)";
#media #{$mobileLandscape} {
body {
color: red;
}
}
// With Mixin
#mixin mq($breakpoint){
#if $breakpoint == "mobile-landscape"{
#media only screen and (min-device-width: 375px) and (max-device-width: 667px) and (-webkit-min-device-pixel-ratio: 2) and (orientation: landscape){
#content;
}
}
}
body{
#include mq("mobile-landscape"){
color: green;
}
}

Related

SASS mapped property doesn't enter in IF else statement

I'm just pulling my hair right know.
I have a mixing that receives a simple object. Depending on the value of one of the properties should enter inside de IF statement or the ELSE one.
However it's always evaluating as TRUE and can't figure why.
Code is compiled using node-sass (libsass v3.5.4 ) and the gist can be seen here:
https://www.sassmeister.com/gist/40eb28fd55173d7534a7162de3c1b960
Both times calculateHeight mixin is invoked evaluates the if to TRUE and creates a CSS with twice color: red, instead of color: red and color: blue
// ----
// libsass (v3.5.4)
// ----
$headerHeight: 150px;
$headerHeightM: 115px;
$headerHeightS: 100px;
#mixin calculateHeight($obj:()){
#if #{map-get($obj, value)} {
color: red;
#media (min-width: 480px) {
#{map-get($obj, property)}: $headerHeightS;
}
#media (min-width: 768px) {
#{map-get($obj, property)}: $headerHeightM;
}
#media (min-width: 1280px) {
#{map-get($obj, property)}: $headerHeight;
}
}
#else {
color: blue;
#media (min-width: 480px) {
#{map-get($obj, property)}: #{map-get($obj, value)} 233px;
}
}
}
.header{
#include calculateHeight((property: 'height', value: false));
#include calculateHeight((property: "background", value: "url('../img/red_header_wave_1.png') no-repeat center top/100% "));
}
Not sure why, but, if I assign the value of the object property to a variable it does the trick and works. Again, not sure why but it's working now:
// ----
// libsass (v3.5.4)
// ----
$headerHeight: 150px;
$headerHeightM: 115px;
$headerHeightS: 100px;
#mixin calculateHeight($obj:()){
// Assign the mapped property to a variable prior to #if
$var: #{map-get($obj, value)};
#if $var == 'false' {
color: red;
#media (min-width: 480px) {
#{map-get($obj, property)}: $headerHeightS;
}
#media (min-width: 768px) {
#{map-get($obj, property)}: $headerHeightM;
}
#media (min-width: 1280px) {
#{map-get($obj, property)}: $headerHeight;
}
}
#else {
color: blue;
#media (min-width: 480px) {
#{map-get($obj, property)}: #{map-get($obj, value)} 233px;
}
}
}
.header{
#include calculateHeight((property: 'height', value: false));
#include calculateHeight((property: "background", value: "url('../img/red_header_wave_1.png') no-repeat center top/100% "));
}
You are interpolating the value from your map into a string, so you are actually checking the string "false", which is truthy (as you already found out). Get rid of the interpolation #{...} and it should work as expected.
- #if #{map-get($obj, value)} {
+ #if map-get($obj, value) {

Media queries in Sass

I am wondering if there is a way to write media queries in sass, so I can give a certain style between let's say: 300px to 900px
in css it looks like this
#media only screen and (min-width: 300px) and (max-width: 900px){
}
I know I can write
#media (max-width: 900px)
in sass but how to make that range?
$small: 300px;
$medium: 900px;
.smth {
//some CSS
#media screen and (max-width: $small) {
//do Smth
}
#media screen and (min-width: $medium) {
//do Smth
}
}
Something like this?
This is what I use for a Mixin with sass, it allows me to quickly reference the breakpoint that I want. obviously you can adjust the media query list to suite your project mobile fist etc.
But it will jin multiple queries for you as I believe you're asking for.
$size__site_content_width: 1024px;
/* Media Queries */ Not necessarily correct, edit these at will
$media_queries : (
'mobile' : "only screen and (max-width: 667px)",
'tablet' : "only screen and (min-width: 668px) and (max-width: $size__site_content_width)",
'desktop' : "only screen and (min-width: ($size__site_content_width + 1))",
'retina2' : "only screen and (-webkit-min-device-pixel-ratio: 2) and (min-resolution: 192dpi)",
'retina3' : "only screen and (-webkit-min-device-pixel-ratio: 3) and (min-resolution: 288dpi)",
'landscape' : "screen and (orientation:landscape) ",
'portrait' : "screen and (orientation:portrait) "
);
#mixin for_breakpoint($breakpoints) {
$conditions : ();
#each $breakpoint in $breakpoints {
// If the key exists in the map
$conditions: append(
$conditions,
#{inspect(map-get($media_queries, $breakpoint))},
comma
);
}
#media #{$conditions} {
#content;
}
}
Use it like this in your scss:
#masthead {
background: white;
border-bottom:1px solid #eee;
height: 90px;
padding: 0 20px;
#include for_breakpoint(mobile desktop) {
height:70px;
position:fixed;
width:100%;
top:0;
}
}
Then this will compile to:
#masthead {
background: white;
border-bottom: 1px solid #eee;
height: 90px;
padding: 0 20px;
}
#media only screen and (max-width: 667px), only screen and (min-width: 1025px) {
#masthead {
height: 70px;
position: fixed;
width: 100%;
top: 0;
}
}
Check this out for scss.
https://github.com/Necromancerx/media-queries-scss-mixins
Usage
.container {
#include xs {
background: blue;
}
#include gt-md {
color: green
}
}
Demo: Stackblitz
Based on Angular FlexLayout MediaQueries
$small: 300px;
$medium: 900px;
#media screen and (min-width: $small) and (max-width: $medium) {
//css code
}

Finding the height of multiple elements in SCSS [duplicate]

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: 960px;}
#media screen and (min-width: 1171px) {$base_width: 1160px;}
$base_width is then defined at various points in the stylesheet width percentage-based measurements to produce fluid layouts.
When I do this, the variable seems to be recognized properly but the conditions for the media query are not. For example, the above code produces an 1160px layout regardless of screen width. If I flip-flop the #media statements like so:
#media screen and (min-width: 1171px) {$base_width: 1160px;}
#media screen and (max-width: 1170px) {$base_width: 960px;}
It produces a 960px layout, again regardless of screen width. Also note that if I remove the first line of $base_width: 1160px; it returns an error for an undefined variable. Any ideas what I'm missing?
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
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);
}
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).
SCSS
$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).
CSS
.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;
}
}
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.
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;
}
}
Two recommendations
1
Write your "default" CSS statements to be for small screens and only use media queries for larger screens. There's usually no need for a max-width media query.
Example (assuming the element has class "container")
#mixin min-width($width) {
#media screen and (max-width: $width) {
#content;
}
}
.container {
width: 960px;
#include min-width(1170px) {
width: 1160px;
}
}
2 Use CSS variables to solve the problem, if you can.
#mixin min-width($width) {
#media screen and (max-width: $width) {
#content;
}
}
:root {
--container-width: 960px;
#include min-width(1170px) {
--container-width: 1160px;
}
}
.container {
width: var(--container-width);
}
Note:
Since it will have the width of 1160px when the window has a width of 1170px, it may be better to use a width of 100% and max-width of 1160px, and the parent element might have a horizontal padding of 5px, as long as the box-sizing property is set to border-box. There are a lot of ways to solve the problem. If the parent is not a flex or grid container you might use .container { margin: auto }.
This is also possible with %placeholders.
%placeholders can be wrapped in media queries. So you could set up multiple variables to use at different screen sizes, and then the placeholders would automagically pre-process accordingly. I'm using some mixins to shorten my media query declarations here also.
In your _vars.scss file:
$width-1: 960px;
$width-2: 1160px;
In your _placeholders.scss file:
%variable-site-width {
#media screen and (max-width: 1170px) { width: $width-1; }
#media screen and (min-width: 1171px) { width: $width-2; }
}
In your page.scss file:
.wrapper. { #extend %variable-site-width; background: red; etc... }
And this will compile to something similar to:
#media screen and (max-width: 1170px) {
.wrapper { width: 960px; }
}
#media screen and (min-width: 1171px) {
.wrapper { width: 1160px; }
}
Voila!
I use this technique extensively for things like variable font sizes and a raft of other things.

Breakpoint-sass: why styles apply at wrong device width?

When check it in Opera Mobile Emulator and on devices, it appears, that styles for wvgaPort apply only at 599px, then for 800 - at 1200, for 1024 at 1533. Why does it happen? And what is a better why to define these media rules?
/* Media */
$wvgaPort: 400px
$wvgaLand: 800px
$wsvgaPort: 600px
$wsvgaLand: 1024px
$desktop: 1280px
=apply-to($media)
#if $media == smartPort
#media only screen and (min-device-width: $wvgaPort) and (max-device-width: $wsvgaPort) and (orientation: portrait)
#content
#else if $media == smartLand
#media only screen and (min-device-width: $wvgaLand) and (max-device-width: $wsvgaLand) and (orientation: landscape)
#content
#else if $media == tabPort
#media only screen and (min-device-width: $wsvgaPort + 1) and (max-device-width: $desktop) and (orientation: portrait)
#content
#else if $media == tabLand
#media only screen and (min-device-width: $wsvgaLand + 1) and (max-device-width: $desktop) and (orientation: landscape)
#content
html, body
+apply-to(smartPort)
font-size: 87.5% !important
#header
+apply-to(smartPort)
background: red
color: #000
+apply-to(smartLand)
background: blue
Here is the output CSS for what you've written.
#media only screen and (min-device-width: 400px) and (max-device-width: 600px) and (orientation: portrait) {
html, body {
font-size: 87.5% !important;
}
}
#media only screen and (min-device-width: 400px) and (max-device-width: 600px) and (orientation: portrait) {
#header {
background: red;
color: black;
}
}
#media only screen and (min-device-width: 800px) and (max-device-width: 1024px) and (orientation: landscape) {
#header {
background: blue;
}
}
Your #header will only, and I do mean only, have the styles background: red; color: black between 400px and 600px when in portrait and will only, and again I mean only, have the style background: blue; applied to it between 800px and 1024px in landscape. You've got some very very stringent media queries there. By specifying min-width, max-width, and orientation for each media query (not to mention the media type), you are locking your styles to only applying at those specific places, and nowhere else. This is very unsustainable and leads to the confused styling you're seeing.
If I were you, I'd take an entirely different approach to this. You should be starting with your content first, choosing breakpoint when your design breaks (not where devices live), and be much more liberal with when a media query can apply. I've done quite a few presentations on this, my Responsive Web Design with Sass+Compass should help you get a better understanding of what tools are already available to you for building responsively with Sass (and how to choose breakpoints), and Style Prototyping will show you a set of tools/techniques/reasons why and how to design content first.

Using Sass Variables with CSS3 Media Queries

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: 960px;}
#media screen and (min-width: 1171px) {$base_width: 1160px;}
$base_width is then defined at various points in the stylesheet width percentage-based measurements to produce fluid layouts.
When I do this, the variable seems to be recognized properly but the conditions for the media query are not. For example, the above code produces an 1160px layout regardless of screen width. If I flip-flop the #media statements like so:
#media screen and (min-width: 1171px) {$base_width: 1160px;}
#media screen and (max-width: 1170px) {$base_width: 960px;}
It produces a 960px layout, again regardless of screen width. Also note that if I remove the first line of $base_width: 1160px; it returns an error for an undefined variable. Any ideas what I'm missing?
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
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);
}
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).
SCSS
$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).
CSS
.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;
}
}
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.
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;
}
}
Two recommendations
1
Write your "default" CSS statements to be for small screens and only use media queries for larger screens. There's usually no need for a max-width media query.
Example (assuming the element has class "container")
#mixin min-width($width) {
#media screen and (max-width: $width) {
#content;
}
}
.container {
width: 960px;
#include min-width(1170px) {
width: 1160px;
}
}
2 Use CSS variables to solve the problem, if you can.
#mixin min-width($width) {
#media screen and (max-width: $width) {
#content;
}
}
:root {
--container-width: 960px;
#include min-width(1170px) {
--container-width: 1160px;
}
}
.container {
width: var(--container-width);
}
Note:
Since it will have the width of 1160px when the window has a width of 1170px, it may be better to use a width of 100% and max-width of 1160px, and the parent element might have a horizontal padding of 5px, as long as the box-sizing property is set to border-box. There are a lot of ways to solve the problem. If the parent is not a flex or grid container you might use .container { margin: auto }.
This is also possible with %placeholders.
%placeholders can be wrapped in media queries. So you could set up multiple variables to use at different screen sizes, and then the placeholders would automagically pre-process accordingly. I'm using some mixins to shorten my media query declarations here also.
In your _vars.scss file:
$width-1: 960px;
$width-2: 1160px;
In your _placeholders.scss file:
%variable-site-width {
#media screen and (max-width: 1170px) { width: $width-1; }
#media screen and (min-width: 1171px) { width: $width-2; }
}
In your page.scss file:
.wrapper. { #extend %variable-site-width; background: red; etc... }
And this will compile to something similar to:
#media screen and (max-width: 1170px) {
.wrapper { width: 960px; }
}
#media screen and (min-width: 1171px) {
.wrapper { width: 1160px; }
}
Voila!
I use this technique extensively for things like variable font sizes and a raft of other things.

Resources