How to use #if within #function to check the orientation of the screen in SCSS? - sass

I've been trying to write conditional SCSS that sets the height of my device to one value if the device is landscape or another if it is in portrait.
I understand I can use a media query to determine the orientation but I don't believe I'm receiving the correct calculation. Currently this is what I have. How can I check that my condition is written properly?
#function calculateRootHeight ($width, $orientation: landscape)
{
$heightPaddedRatio: 1.0;
$heightToWidth: 2/3;
#if (orientation: portrait) {
$heightToWidth: 3/2;
}
#return $heightPaddedRatio * $heightToWidth * $width;
}
#mixin describeRoot($bodyWidth) {
#root {
background-color: #EAE5E5;
}
#media (orientation: portrait) {
#root {
height: calculateRootHeight($bodyWidth, portrait);
}
}
#media (orientation: landscape) {
#root {
height: calculateRootHeight($bodyWidth, landscape);
}
}
}

I think you only need to change the syntax in your #if statement slightly, the rest seems ok.
Using the #debug directive is helpful if you want to check a value in your Sass functions.
#function calculateRootHeight ($width, $orientation: landscape) {
$heightPaddedRatio: 1.0;
$heightToWidth: 2/3;
#if ($orientation == "portrait") {
$heightToWidth: 3/2;
}
#debug "Orientation is '#{$orientation}'";
#return $heightPaddedRatio * $heightToWidth * $width;
}
.portrait {
height: calculateRootHeight(200px, portrait); /* Orientation is 'portrait' */
}
.landscape {
height: calculateRootHeight(200px); /* Orientation is 'landscape' */
}

Related

sass - Changing a variable via a media query

I have a function that calculates the value of vw from px depending on the maximum brackpoint. For the mobile version of the page I use a brackpoint of 360, but starting with a screen size of 768px I need to use a brackpoint of 1440.
Below I gave an example of how this works now, but maybe there is some solution to automate this process. In a real project it becomes very difficult to handle all sizes every time.
variables.scss
$bp-large: 1440;
mixins.scss
#mixin _768 {
#media (min-width: 768px) {
#content;
}
}
functions.scss
#function get-vw($target, $base-vw: 360) {
$vw-context: ($base-vw * .01) * 1px;
#return calc($target / $vw-context) * 1vw;
}
page.scss
.square {
width: get-vw(100px);
height: get-vw(100px);
#include _768 {
width: get-vw(200px, $bp-large);
height: get-vw(200px, $bp-large);
}
}

How to add "orientation media query" to bootstrap 4 sass media query

i am using the "vanilla" bootstrap 4 sass media query in my scss files:
#include media-breakpoint-up(xs){}
#include media-breakpoint-up(sm){}
#include media-breakpoint-up(lg){}
#include media-breakpoint-up(xl){}
i know that if i use the css width media query i can couple it with the orientation media query, but i want to use the sass framework.
I want to add the orientation media query in on of them, the XS one. thus it is specific. Because as you know bootsrap 4 is not supporting orientation query for now (strangely).
i tried to concatenat the "orientation query" with the "SASS bootstrap media query (xs)" in different way but i always have a sass error.
Thus What i did is to nest it in the SASS bootstrap media query (xs):
#include media-breakpoint-up(xs){
... some SCSS rules
#media (orientation: landscape){
header{
display:none !important;
}
.navbar{
display:none !important;
}
}
}
The problem i have even tought it is nested into the XS query is that it apply to all breakpoint. it s like it does nt take into account to be nested.
My question: how to concatenate the "orientation query" with the "SASS bootstrap media query (xs)"? Or how to make it specific to the XS breakpoint by nesting it.
Thank you
I've found the solution.
It's possible to combine sass mixin by nesting them, thus I've created the following mixin in my _mixins.scss file:
#mixin orientation($direction) {
$orientation-landscape: "(orientation:landscape)";
$orientation-portrait: "(orientation:portrait)";
#if $direction == landscape {
#media #{$orientation-landscape} { #content; }
}
#if $direction == portrait {
#media #{$orientation-portrait} { #content; }
}
}
Note: i didn't put the "and" in the variable value: "and (orientation:landscape)". SASS or bootstrap put it automatically i suppose.
Then in my SCCS file I've added the following rules:
#include media-breakpoint-down(sm) {
#include orientation(landscape) {
.path-frontpage header {
display: none !important;
}
.path-frontpage .navbar {
display: none !important;
}
}
}
Note: in my first post i was saying that the CSS rules I've nested was applied to all breakpoints, it s because when the CSS is generated the SASS Bootstrap 4 XS breakpoint of is not written, i suppose it's because the value is 0. thus the orientation media query was not combines with a min-width value. So i changed the value to a max-width instead of a min-width, as the Bootstrap 4 SM breakpoint have the 576px value.
The result in the CSS file is what i wanted:
#media (max-width: 767.98px) and (orientation: landscape) {
.path-frontpage header {
display: none !important;
}
.path-frontpage .navbar {
display: none !important;
}
}
I hope it will help the community.
I use this outside of Bootstrap. You should be able to use it with Bootstrap or any other framework, giving you more flexibility in your media queries.
// Extra map functions by Hugo Giraudel
#function map-deep-get($map, $keys...) {
#each $key in $keys {
$map: map-get($map, $key);
}
#return $map;
}
#function map-has-keys($map, $keys...) {
#each $key in $keys {
#if not map-has-key($map, $key) {
#return false;
}
}
#return true;
}
#function map-has-nested-keys($map, $keys...) {
#each $key in $keys {
#if not map-has-key($map, $key) {
#return false;
}
$map: map-get($map, $key);
}
#return true;
}
These are extra map functions Hugo Giraudel wrote up. map-deep-get is basically a simplified nested map-get function. map-has-keys is just like map-has-key, which is built-in to sass, but checks for multiple keys. map-has-nested-keys expands on that by checking for nested keys. This is crucial for this method. I'd definitely look into the extra Sass functions he's built. I've quite easily found use for just about all of them.
// Map
$sizes: (
null: (
breakpoint: 0,
container: 100%
),
xs: (
breakpoint: 480px,
container: 464px
),
sm: (
breakpoint: 768px,
container: 750px
),
md: (
breakpoint: 992px,
container: 970px
),
lg: (
breakpoint: 1200px,
container: 1170px
)
);
This is a simple breakpoint map. I usually use this as a base map for all settings on my projects, so I'll include things like base font-sizes and whatnot in it.
// Breakpoint mixin
#mixin break($screen-min: null, $screen-max: null, $orientation: null) {
$min: $screen-min;
$max: $screen-max;
$o: $orientation;
$query: unquote("only screen");
#if $min != null and $min != "" {
#if map-has-nested-keys($base, sizes, $screen-min) {
$min: map-deep-get($base, sizes, $screen-min, breakpoint);
}
#else {
$min: $screen-min;
}
#if is-number($min) {
$query: append($query, unquote("and (min-width: #{$min})"));
}
}
#if $max != null and $max != "" {
#if map-has-nested-keys($base, sizes, $screen-max) {
$max: map-deep-get($base, sizes, $screen-max, breakpoint);
}
#else {
$max: $screen-max;
}
#if is-number($max) {
$query: append($query, unquote("and (max-width: #{$max})"));
}
}
#if $orientation == landscape or $orientation == portrait {
$o: $orientation;
$query: append($query, unquote("and (orientation: #{$o})"));
}
#else {
$o: null;
}
#media #{$query} {
#content;
}
};
Here's the mixin. You can use the keys from the sizes map (xs, sm, md, lg) for the first two arguments, or you can use custom values (like 30em). The third argument accepts either landscape or portrait. You could even customize the mixin the make l = landscape and p = portrait if you wanted.
Additionally, if you only wanted, for example, an orientation, you could pass the arguments (null, null, landscape).
For clarity, here's some examples:
#include break(null, md, landscape) {
...
}
#include break(null, null, landscape) {
...
}
#include break(md) {
...
}
#include break(null, md) {
...
}
#include break(480px) {
...
}
Output:
#media only screen and (max-width: 992px) and (orientation: landscape) {
...
}
#media only screen and (orientation: landscape) {
...
}
#media only screen and (min-width: 992px) {
...
}
#media only screen and (max-width: 992px) {
...
}
#media only screen and (min-width: 480px) {
...
}

Sass: Function return value by screen

It's possible create a function that return value based on screen width.
My idea:
#function vw_pc( $num ) {
#media screen and (max-width: 1920)
{
#return a;
}
#media screen and (max-width: 1200)
{
#return b;
}
}
No, since the Sass compiler is creating a static CSS code regardless of your screen.

Avoid repeat the same mixin in Sass

I have this Mixin for padding utility:
Sass code:
$padding: (
top: "top",
right: "right",
bottom: "bottom",
left: "left",
all: "all"
);
#mixin no-padding($map) {
#each $padding-side, $side in $map {
#if $side == 'all' {
& {
padding: 0 !important;
}
} #else {
&-#{$side} {
padding-#{$side}: 0 !important;
}
}
}
}
Use of it:
.u-noPadding {
#include no-padding($padding);
}
I want to use the same Mixin but now for margin, is there any solution to avoid repeating the same mixin and make a good use of best practices?
#mixin no($type,$sides:null) {
$i:0 !important;
#if $sides == null {
#{$type}:$i;
} #else {
#each $side in $sides {
#{$type}-#{$side}:$i;
}
}
}
.u-noPadding {
#include no(padding, top left etc...); // choose any side separated with a space
}
.u-noMargin {
#include no(margin); // instead of 'all', type nothing
}
Like this? Your $sides will be stored in a temporary map automatically if your second parameter is set, no need extra map for this.
About the second parameter: If you want no sides, let it empty and all sides will have 0. Similiar to your 'all' idea.. it's shorter.

Compass: separate sprite declaration for IE8

In my .scss I'm using CSS3 pseudo classes. For example :
.btn:disabled {
#include assets-sprites(btn_disabled);
}
.btn.disabled {
#include assets-sprites(btn_disabled);
}
Compass combine these two declaration into one :
.btn:disabled, .btn.disabled {
background: url("img/assets.png")
}
But Internet Explorer 8 doesn't read the declaration if a CSS3 pseudo class is present in the selector (like :disabled, :checked, :not, etc).
So how can I output this into something like that ?
.btn:disabled {
background: url("img/assets.png")
}
.btn.disabled {
background: url("img/assets.png")
}
Thanks :)
You can combine placeholders and a mixin to manage this with a DRY approach:
SCSS
#import "compass";
// Generate separate CSS3 pseudo-selector / fallback selector.
//
// #param string $selector
// The CSS3 selector name, without the first colon.
// #param string $sprite
// The sprite name without the file extension.
#mixin sprite-css3-pseudo($selector, $sprite, $map: $assets-sprites) {
// CSS3 selector
&:#{$selector} {
#extend %assets_css3-map;
#include sprite-background-position($map, $sprite);
}
// IE8 fallback
&.#{$selector} {
#extend %assets-map;
#include sprite-background-position($map, $sprite);
}
}
// $<map>-sprite-base-class to customize the base class
// used when we importing the sprite map.
$assets-sprite-base-class: '%assets-map';
// Compass generates the following rule:
// %assets-map {
// background: $assets-sprites no-repeat;
// }
#import "assets/*.png";
// We have to split the CSS3 selectors of the classic selectors (the
// fallback) so we need to declare a new placeholder with the same
// content generated by Compass for the base class.
%assets_css3-map {
background: $assets-sprites no-repeat;
}
.btn {
#include sprite-css3-pseudo('disabled', 'btn_disabled');
}
.fb {
#include sprite-css3-pseudo('checked', 'fb_icon');
}
.icon-alarm {
// We can still use the regular sprite generator
#include assets-sprite('alarm');
// And our mixin :)
#include sprite-css3-pseudo('disabled', 'alarm');
}
CSS
.btn.disabled, .fb.checked, .icon-alarm, .icon-alarm.disabled {
background: url('../images/assets-sacf5a47174.png') no-repeat;
}
.btn:disabled, .fb:checked, .icon-alarm:disabled {
background: url('../images/assets-sacf5a47174.png') no-repeat;
}
.btn:disabled {
background-position: 0 -224px;
}
.btn.disabled {
background-position: 0 -224px;
}
.fb:checked {
background-position: 0 -176px;
}
.fb.checked {
background-position: 0 -176px;
}
.icon-alarm {
background-position: 0 0;
}
.icon-alarm:disabled {
background-position: 0 0;
}
.icon-alarm.disabled {
background-position: 0 0;
}
Here'es the solution, thanks to #pascalduez:
$assets: sprite-map("assets/*.png");
.btn:disabled { background: sprite($assets, user); }
.btn.disabled { background: sprite($assets, user); }

Resources