Calculate in media queries with SCSS - css

Is it possible to calculate in media queries when using SCSS and a variable?
I would like to assign a value to a breakpoint variable and in some cases calculate + 1 directly in the media query SCSS file like this:
$bp-xl: 1024px;
#media (min-width: $bp-xl + 1) { ... } /* MIN-WIDTH = 1025px */
So my new min-width would be 1025px.

you can use calc(#{$bp-xl} + 1px);. calc does the calcuation, the #{} is string interpolation, which lets you insert a variable into calc

Yes, It's Possible!
Have a look for Demo! https://codepen.io/navdeepsingh/pen/qpejKo
h1 {
font-size: 12px;
background: green;
color: white;
}
$bp-xl: 1024px;
#media (min-width: $bp-xl + 6) {
h1 {
font-size: 50px;
background: pink;
color: black;
}
} /* MIN-WIDTH = 1030px */
<h1>HELLO</h1>

Related

Modify CSS variable in media query

Is there a way to modify a previously-declared CSS variable inside a media query with just vanilla CSS? What I'm after would look like this (which of course doesn't work as the variables all get computed in the end):
#container {
--elem-size: 20px;
}
#media only screen and (min-width: 800px) {
#container {
--elem-size: calc(var(--elem-size) * 2);
}
}
I'm aware that it would be possible to declare a "base variable" (e.g. --base-elem-size) and then use it to generate new variable values for different viewports. However, I'm working with a very large number of CSS variables which makes it undesirable to create a duplicate base set out of them. The ideal solution would be able to "modify" a previously-declared value.
This might be far from ideal but to some degrees does define the style in one line. It uses fallback values of CSS variables.
Open full screen and change window size to see the result:
:root {
--elem-size-base: 50px;
}
#container {
/* 👇 Fallback for base value, optional 2nd fallback for no variable value */
width: var(--elem-size, var(--elem-size-base, 50px));
height: var(--elem-size, var(--elem-size-base, 50px));
outline: 2px solid #000;
background-color: pink;
}
#media only screen and (min-width: 768px) {
#container {
/* 👇 This variable for various #media */
--elem-size: calc(var(--elem-size-base) * 2);
background-color: lightblue;
}
}
#media only screen and (min-width: 1024px) {
#container {
/* 👇 This variable for various #media */
--elem-size: calc(var(--elem-size-base) * 4);
background-color: lightgreen;
}
}
<div id="container"></div>
I think having base CSS variables would make your CSS much more readable and easier to maintain, specially if you are working with a big codebase.
May be something like this:
:root {
/* Define you base variables */
--font-size-default: 16px;
--font-size--large: calc(var(--font-size-default) * 1.25);
/* Assign the base variable to the element variables */
--elem-size: var(--font-size-default);
}
#media screen and (min-width: 840px) {
:root {
/* Change base variable used for element variable */
--elem-size: var(--font-size--large);
}
}
This allows you to set a base font-size variable and one (or more) "variants" of that variable, which you can then use on your whole project
I would suggest you look into something like the Open Props (which has some really great ideas for what base variables can be and how to use them)

How to dynamically change values of CSS variables ONLY in CSS? Is it possible?

What I mean is, for example, I want to change the value of variable --color_rgb every time I increase the counter. What line to add to make it happen?
:root {
--color_rgb: 50;
}
body {
counter-set: color 0;
}
p::before {
counter-increment: color 40;
content: "Section. " counter(color) " ";
}
p {
padding: 20px 20px 20px 20px;
background-color: rgba(calc(var(--color_rgb)/2), var(--color_rgb), calc(var(--color_rgb)*2), 0.8);
}
if you want to change a css variable value for particular screensize the it would work with #media queries
#media screen and (max-width: 760px) {
:root {
--ball-width: calc(200px);
}
}
it may work in animations but i haven't tried it out yet, so i think you should give it a try.

how to override #media (max-width) using stylish

Intro
this is similar to this question but unfortunately the answer only applies to greasmonkey (which only works on firefox). Further, this was asked on the stylish forum but the answer was ambiguous.
Question
I want to remove the left column in the azure help page and
expand the main body to make it cover the widht of the screen.
The first part can easily be done by this
#sidebarContent {display:none}
How ever the second part must conver this
media (max-width: 1199.99999px)
to this
media (max-width: 100%)
But I have no idea how to do that using stylish.. ideas?
To override a media query you just need to load another media query - that also applies to your device - after it.
Well...you want a blunt media query that applies to everything. The best way is to use #media (min-width: 1px) since that includes all devices.
Now, put it all together - along with some other CSS cleanups like padding and margin removal and setting a new width for .mainContainer and you get this
#sidebar {
display: none;
}
#media (min-width: 1px) {
.mainContainer {
margin: 0 auto;
width: 100vw;
padding: 0;
}
body>.container {
padding: 0;
}
}
New code: (with different selector for width)
#sidebar {
display: none;
}
#media (min-width: 1px) {
.mainContainer { /*example styles*/
margin: 0 auto;
width: 100vw;
}
body>.container {
padding: 0;
}
body>.mainContainer>main {
max-width: 100vw!important;
}
}
You still have to adjust the padding to your preference as setting the padding to 0 breaks the design a little bit but this should be good starting point.
Before:
After:

Using Less, can I use the current value in a #media section?

I have the following Less code:
#appbar-padding: 10px;
.container {
padding-bottom: #appbar-padding + 10;
}
#media (min-width: 750px) {
.container {
padding-bottom: #appbar-padding + 20;
}
}
Is it possible to take the current value of the padding-bottom in the #media part? So I could do something like:
#media (min-width: 750px) {
.container {
padding-bottom: #this + 10;
}
}
This way, if I change the "normal" .container rules to, say, #appbar-padding + 20, the rules for screens bigger than 750px wide will, in effect, have #appbar-padding + 30 instead of + 20.
As suggested by Harry, you have to pass through an intermediate variable. An example of code could be:
#appbar-padding: 10px;
#default-padding:#appbar-padding + 10;
.container {
padding-bottom: #default-padding;
}
#media (min-width: 750px) {
.container {
padding-bottom: #default-padding + 20;
}
}
The idea is to pre-define "default" (what you call "normal") value for padding, that is calculated starting by #appbar-padding and then apply it to .container.
In Media query, this "default" value is what you change again. In this way, you can simulate your desired behaviour.
NOTE: you must declare #default-padding:#appbar-padding + 10; outside .container class definition because of scope.

Can you create custom breakpoints with LESS mixins?

Most of the time, I use LESS variables with preset breakpoints for media queries like this:
#s-max : ~"screen and (max-width: 40em)";
#m-max : ~"screen and (max-width: 50em)";
#l-max : ~"screen and (max-width: 60em)";
USAGE
.some-class {
color: red;
#media #s-max {
color: blue;
}
}
But sometimes, I would like to be able to refer to an arbitrary breakpoint in my .less stylesheet without having to set a new preset value in my separate mixin file.
You can do this in SASS. The mixin looks like this:
#mixin bp-min($canvas) {
#media only screen and (min-width:$canvas) {#content;}
}
USAGE
#include bp-min(750px) {
//responsive styling for min-width of 750px
}
In LESS, I'm imagining the equivalent mixin would look something like this:
.bp-min(#min) {
#media only screen and (min-width:#min)...
}
The only problem is, the lack of the {#content} argument in LESS, which grabs the rest of the styling inputted by the developer. I love SASS, but I can't use it at work.
Does anyone know of a LESS-based solution to this problem?
It is now similar to SASS
As of 1.7.0 (2014-02-27) you can now use #rules in place of the sassy #content.
For example:
.breakpoint-small(#rules) {
#media screen and (min-width: 40em) { #rules(); }
}
ul {
width: 100%;
.breakpoint-small({
width: 50%;
});
}
outputs, as expected:
ul {
width: 100%;
#media screen and (min-width: 40em) {
width: 50%;
}
}
The differences being:
function takes #rules as an argument
additional parenthesis when invoking the function
'.' syntax as opposed to '#include'
This can be combined with an additional argument to provide syntax equivalent to a nice bit of sass:
.breakpoint(#size, #rules) {
#media screen and (min-width: #size) { #rules(); }
}
#large: 60em;
ul {
.breakpoint(#large, {
width: 50%;
});
}
edit: To be honest I prefer a way more simple approach in less:
#break-large: ~"screen and (min-width: 60em)";
ul {
#media #break-large {
width: 50%;
}
}
Source: I too use sass at home and less at work
Using Pattern Matching
I believe this achieves what you want:
LESS
/* generic caller */
.bp-min(#min) {
#media only screen and (min-width:#min) {
.bp-min(#min, set);
}
}
/* define them */
.bp-min(750px, set) {
test: (#min - 300px);
}
.bp-min(400px, set) {
test: (#min - 100px);
}
/* call them */
.bp-min(750px);
.bp-min(400px);
Output CSS
#media only screen and (min-width: 750px) {
test: 450px;
}
#media only screen and (min-width: 400px) {
test: 300px;
}
By defining a set pattern mixin for the various sizes, and then using that pattern within the generic .bp-min(#min) mixin, I believe we have the same abstraction in LESS that you have in SCSS, with slightly more code because I believe SCSS defines and calls in one #include statement, whereas here we need two.
(In addition to the prev. answer) Or something like this:
.bp-min(#canvas) {
#media only screen and
(min-width: #canvas) {.content}
}
// usage:
& { .bp-min(900px); .content() {
color: red;
}}
& { .bp-min(600px); .content() {
color: blue;
}}
// more usage examples:
.class-green {
.bp-min(450px); .content() {
color: green;
}}
& { .bp-min(300px); .content() {
.class-yellow {
color: yellow;
}
.class-aqua {
color: aqua;
}
}}
Replace .content with .- if you prefer shorter stuff.
In my case I needed my variables to reference other variables, so some of these solutions did not work. Here is what I went with.
#bp-xs: ~"screen and (max-width:"#screen-xs-max~")";
#bp-sm: ~"screen and (max-width:"#screen-sm-max~")";
#bp-md: ~"screen and (max-width:"#screen-md-max~")";
#bp-lg: ~"screen and (max-width:"#screen-lg-max~")";
and then use them like so
#media #bp-sm {
...
}

Resources