Basic idea would be to define my media query in one place. My current attempt looks like so:
$mobile: "#media (max-width: 600px):not(#app.force-desktop)";
#{$mobile} {
...
}
However this results in the error: SassError: Invalid CSS after "#": expected selector, was "#media (max-width: " Setting $mobile to (for example) only :not(#app.force-desktop) seems to compile properly.
Maybe there is a different way how to solve this issue, which would be totally fine by me.
You can just remove the #media:
$mobile: '(max-width: 600px):not(#app.force-desktop)';
#media #{$mobile} {
body {
color: blue;
}
}
Related
SCSS variables don't seem to work when used in a container query. For example this code works just fine:
.parent {
container-type: inline-size;
background: yellow;
}
#container (max-width: 800px) {
.child {
background:green;
}
}
See pen: https://codepen.io/pwkip/pen/jOprKya
But when I try to use a sass-variable to define the breakpoint, it fails.
$width: 800px;
.parent {
container-type: inline-size;
background: yellow;
}
#container (max-width: $width) {
.child {
background:green;
}
}
See pen: https://codepen.io/pwkip/pen/BaPzVZW
What's the problem here? Any workaround?
I cannot find the definitive sass lang entry, but hash and curly brace is often used in #media queries.
#container (max-width: #{$width}) {
.child {
background:green;
}
}
In Brave it works in that codepen; and so do the following:
#container (max-width: ${width} ) {
As "A Boston" already pointed out the issue seems to be that you don't use the hash syntax like in his first example.
I use https://www.sassmeister.com/ quite often to check what it compiles to.
In your Codepen you forgot to add a semicolon after
$width: 800px;
^
According to: https://developer.mozilla.org/en-US/docs/Web/CSS/#container
#container queries are not supported for Firefox yet. Only Firefox Nightly supports it.
I've tested it in Chrome and it worked with the tweaks. Make sure your browser version is supported. My current Safari version did not work either (due to the version mismatch).
Suppose I have the following scss variables:
$until-xs: "(max-width: 377px)";
$until-sm: "(max-width: 640px)";
...
$until-xl: "(max-width: 4000px)";
And based on them the following helper css classes are constructed:
.until-sm {
display: none;
#media #{$until-xs} {
display: block !important;
}
}
.until-md {
display: none !important;
#media #{$until-sm} {
display: block !important;
}
}
/* plus a lot of classes like this */
I am trying to create a mixin that would help me define those classes more easily by passing the $until-x variable as an input to the mixin, like so:
#mixin until($x) {
display: none;
#media #{'$until-'#{$x}} {
display: block !important;
}
}
Such that the classes above will be defined simply as:
.until-xs { #include until($until-xs); }
The problem is the media variable inlining part does not evaluate the way I wanted, like:
#{'$until-'#{$x}} (when x is 'xs') =>
#{'$until-xs'} =>
#{$until-xs} =>
(max-width: 377px)
Any way I can achieve this? Since this can be applied in multiple places in my project I am more interested in the possibility of inlining vars like this than the solution to the particular problem from the example.
Instead of defining lots of variables like $until-xs, $until-sm and so on, you can define a map that contains information of your medias like the code below:
#use "sass:map";
$until-var: ("xs": "(max-width: 377px)", "sm": "(max-width: 620px)", "md": "(max-width: 807px)");
#mixin until($x) {
display: none;
#media #{map.get($until-var, $x)} {
display: block !important;
}
}
/* using that in your classes */
.until-xs { #include until("xs"); }
.until-sm { #include until("sm"); }
I'm not sure what you mean by inlining vars! But if you want a single mixin that works for different medias, I think that works.
I'm creating a React application that has a hero display on the landing page that displays one of three images: [hero-1.jpg, hero-2.png, hero-3.png] based on the users viewport screen size.
I have been unsuccessful trying to find resources online that show a DRY method for achieving this, for the sake of participation, I'll leave this code that I attempted that - in theory made sense to me.
N.B. I am extremely new to Sass/Scss
snippet.html
<section className="hero is-fullheight has-background-black">
<div className="hero-body">
<div className="container">
</div>
</div>
</section>
hero.scss
$i: 1;
$breakpoint-phone: 480px;
$breakpoint-tablet: 768px;
$breakpoint-desktop: 1024px;
#mixin modifier ($i:1) {
#content;
#media only screen and (max-width:$breakpoint-phone) { $i: 2; }
#media only screen and (max-width:$breakpoint-tablet) { $i: 3; }
#media only screen and (max-width:$breakpoint-desktop) { $i: 1; }
}
.hero {
background-position: center;
background-size: cover
}
#include modifier {.hero {background-image: url('../assets/hero-#{$i}.jpg');}}
Methodology:
Display content by default (which is pulled from #include).
Mixin modifier will modify the $i passed to the mixin, which is interpolated in the image path.
Expected Result:
Based on each breakpoint, $i will be set to the appropriate value and change the background image dynamically.
Actual Result:
The global $i is used, and the web page displays hero-1.jpg.
There are a few ways you can achieve this. If I was going about this, this is how I would do it.
Also, it would be very wise to practice mobile first development. Use min-width and go up instead of using max-width going down. The way you currently have it structured would mean you wouldn't have a valid URL if that $i variable wasn't set at 1 at the top of your document. Writing SASS or CSS will be much easier this way once you get used to it.
$tablet: 768px;
$desktop: 1024px;
#mixin hero-image() {
.hero {
background-position: center;
background-size: cover;
background-image: url('../assets/hero-2.jpg');
#media screen and (min-width: $tablet) {
background-image: url('../assets/hero-3.jpg');
}
#media screen and (min-width: $desktop) {
background-image: url('../assets/hero-1.jpg');
}
}
}
#include hero-image();
You're still going to have to write the background-image property 3 times. The way you were doing it was close, but you would have had to #include modifier() 3 times in your consuming scss file. At the end of the day SASS compiles to CSS. You could potentially use a SASS function or For Loop to achieve this, but mixins can get really complicated and powerful, but also incredibly difficult to read and understand. Here's what the mixin I just showed you compiles to in CSS.
.hero {
background-position: center;
background-size: cover;
background-image: url("../assets/hero-2.jpg");
}
#media screen and (min-width: 768px) {
.hero {
background-image: url("../assets/hero-3.jpg");
}
}
#media screen and (min-width: 1024px) {
.hero {
background-image: url("../assets/hero-1.jpg");
}
}
I recommend putting your SCSS/SASS into this compiler to see your results before compiling your actual project.
https://www.sassmeister.com/
Even though you are repeating background-image 3 times inside of the mixin this is very much still DRY code because you can include that one mixin everywhere your images will be shown and if you need to edit it, you can edit it in one place.
Searched but can't find an answer..
I have an element which gets generated (by an external platform) with the following classes: p-button and button.
Now the SCSS is like this:
.p-button {
&.button {
margin: 10px;
}
}
But I want to refactor using mixin includes (this is a big project so there is no other way of making this code better except using mixins). The mixin takes the given selector and applies a . to it. I can't change the mixin, as it is used by many other teams, so I can't pass the ampersand together with the selector. I tried this:
.p-button {
& {
#include button-appearance("button") {
margin: 10px;
}
}
}
But that doesn't work (puts a space between it). You can't do this:
.p-button {
&#include button-appearance("button") {
margin: 10px;
}
}
Anyone have a clue?
EDIT: Here is the mixin
#mixin button-appearance(
$appearance-class,
$show,
$background-color,
$background-image,
$background-position) {
$sel: $button-selector;
#if $appearance-class {
$sel: $sel + '.' + $appearance-class;
}
#{$sel} {
#include normalized-background-image($background-image);
#include show($show);
background-color: $background-color;
background-position: $background-position;
}
#content;
}
EDIT 2: Here is the $button-selector (I can not edit this in the platform, but maybe overwrite it in my own project?)
$button-class: 'p-button';
$button-selector: '.#{$button-class}';
Everyone, finally found the solution. I just removed the &.button from the .p-button mixin include and now it works:
#include button-appearance ("button") { *styles* }
#include button-appearance () { *styles* }
Edited the answer after the original question was edited adding the used and un modifiable mixin
The original mixin does not append the ‘#content’ passed to the mixin to the generated selector. So if you cannot modify the original mixin, the only way is to add your properties outside the mixin. According to the mixin the selector will match a predefined ‘$button-selector’ variable, so it won’t use your class.
So, if you want to use the same class defined in ‘$button-class’, try the following:
#{$button-selector}.button {
margin: 10px;
}
Will output:
.p-button.button {
margin: 10px;
}
In our current design, form elements get styled differently on a mobile device:
#media screen and (max-width: 759px) {
form label {
display: block;
float: none;
}
/*There's more...*/
}
Given the limited screen space, we're basically forcing a vertical form layout (#3-4 in this classic uxmatters link).
Because some form labels have to be insanely verbose For sensible reasons, we now want to apply this style to some desktop forms, i.e. outside of scope of the media query. This, however, is invalid SASS syntax:
#media screen and (max-width: 759px), .vertical-form {
/*...*/
}
How can the ruleset be applied on output within the media query and to .vertical-form form label (or, ideally, form.vertical-form label) elements?
Media queries are not selectors, they are special language constructs. You can't combine them with anything other than media queries. You will have to use a mixin to do what you're asking for because extends don't work across media queries either.
#mixin vertical-form {
label {
display: block;
float: none;
}
}
#media screen and (max-width: 759px) {
form {
#include vertical-form;
}
}
.vertical-form {
#include vertical-form;
}