SASS error : Invalid CSS after "": expected media query list, was ""only screen an..." - ruby

If I call SASS command as shown below :
call sass C:\Users\simon\source\repos\Pippo\ClickR\\Styles\main.scss C:\Users\simon\source\repos\Pippo\ClickR\\Styles\main.css
i get the following error :
Error: Invalid CSS after "": expected media query list, was ""only screen an..."
on line 348 of C:/Users/simon/source/repos/Pippo/ClickR/Styles/foundation/components/_top-bar.scss
from line 22 of C:/Users/simon/source/repos/Pippo/ClickR/Styles/_foundation.scss
from line 3 of C:\Users\simon\source\repos\Pippo\ClickR\\Styles\main.scss
Use --trace for backtrace.
Here is the code that generates the error:
_top-bar.scss
....
$topbar-media-query: "only screen and (min-width:"#{$topbar-breakpoint}")" !default;
....
#media #{$topbar-media-query} {
.top-bar {
background: $topbar-bg;
#include clearfix;
overflow: visible;
.toggle-topbar { display: none; }
.title-area { float: $default-float; }
.name h1 a { width: auto; }
input,
.button {
line-height: 2em;
font-size: emCalc(14px);
height: 2em;
padding: 0 10px;
position: relative;
top: 8px;
}
&.expanded { background: $topbar-bg; }
}
....
How can I solve it?
Thanks,
Simone

The problem is just a syntax error on the assignment to $topbar-media-query.
You should escape a double quote inside a string or you should use a single quote.
In your example you do not need a string for the CSS property min-width, so the easier thing to do is:
Instead of
$topbar-media-query: "only screen and (min-width:"#{$topbar-breakpoint}")" !default;
Try
$topbar-media-query: "only screen and (min-width:#{$topbar-breakpoint})" !default;

Related

SASS generates two separate rules for same class using extend and mixins

In this SCSS code, I'm using mixin btn-structure and extend %red-color to get all declarations under one class contrary to my expectation SCSS output two separate rules for the same class as shown in output below:
%red-color{
color: red }
#mixin btn-structure
($text-case: null, $text-shadow: null, $decoration: none ){
display: inline-block;
text: {
decoration: $decoration;
transform: $text-case;
shadow: $text-shadow }
}
.link-btn{
#include btn-structure($text-case: 'uppercase', $decoration: underline);
#extend %red-color
}
OUTPUT
.link-btn {
color: red;
}
.link-btn {
display: inline-block;
text-decoration: underline;
text-transform: "uppercase";
}
I don't want the SASS to output two separate rules belonging to same class how to get SASS to output one rule if that belongs to one class.
This is the actual behaviour and a use-case of Sass #extend.
Explanation
To make it clear, update your code as below
%red-color{
color: red
}
#mixin btn-structure ($text-case: null, $text-shadow: null, $decoration: none ){
display: inline-block;
text: {
decoration: $decoration;
transform: $text-case;
shadow: $text-shadow
}
}
.link-btn{
#extend %red-color;
#include btn-structure($text-case: 'uppercase', $decoration: underline);
}
.test-class{
#extend %red-color;
#include btn-structure($text-case: 'uppercase', $decoration: underline);
}
Which would compile as,
.link-btn, .test-class {
color: red;
}
.link-btn {
display: inline-block;
text-decoration: underline;
text-transform: "uppercase";
}
.test-class {
display: inline-block;
text-decoration: underline;
text-transform: "uppercase";
}
As you could see, #extend is used to "share a set of CSS properties from one selector to another", which can be clubbed together (.link-btn, .test-class). Whereas, #include is used to insert the styles where ever required, which is not clubbed.
Solution
For your requirement, you can resort to #include and declare a mixin #mixin red-color as below,
%red-color{
color: red
}
#mixin red-color{
color: red
}
#mixin btn-structure ($text-case: null, $text-shadow: null, $decoration: none ){
display: inline-block;
text: {
decoration: $decoration;
transform: $text-case;
shadow: $text-shadow
}
}
.link-btn{
#include red-color;
#include btn-structure($text-case: 'uppercase', $decoration: underline);
}
Output
And the compiled css will be,
.link-btn {
color: red;
display: inline-block;
text-decoration: underline;
text-transform: "uppercase";
}
Hope this helps.

How to correctly show the closing } on rules?

I've been playing with SCSS to try and clean up a new stylesheet I'm working on. I love it so far! Simple, yet powerful. One issue I'm finding though, is the closing } brackets. For example, I'm compiling it with:
sass --watch ./main.scss:../main.css
...and with the following SCSS:
#moreFilterOptionsBtn {
text-align: center;font-size: 1.6em;
a {
background: none;
padding: 0;
}
}
You get:
#moreFilterOptionsBtn {
text-align: center;
font-size: 1.6em; }
#moreFilterOptionsBtn a {
background: none;
padding: 0; }
How can I get it to format it better? ie
#moreFilterOptionsBtn {
text-align: center;
font-size: 1.6em;
}
#moreFilterOptionsBtn a {
background: none;
padding: 0;
}
i.e putting the closing } on a new line, instead of squished up on the end of the rule? For me, this is much more readble!
Thanks
Typical! I just found out about the --style value in CLI:
http://sass-lang.com/documentation/file.SASS_REFERENCE.html#output_style
Just add --style expanded to the end, and it will format correctly:
sass --watch ./main.scss:../main.css --style expanded

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%

Appending the parent selector to the end generates the incorrect result with Elixir/Libsass

I have the following SCSS:
.btn {
color: #000;
#at-root {
a#{&} {
display: inline-block;
}
}
}
I'm expecting the following CSS:
.btn { color: #000; }
a.btn { display: inline-block; }
But when I compile it using gulp-sass, I get this instead:
.btn { color: #000; }
.btn a.btn { display: inline-block; }
This appears to be a bug with Libsass, which is what gulp-sass compiles with. If you want to get the correct results, you'll need to switch to using the Ruby compiler for Sass.

Are there "hooks" in SASS?

I was reviewing UiKit, a frontend framework built with LESS, and noticed a rather interesting feature: hooks. Look at the following in the base framework:
.uk-panel-badge {
position: absolute;
top: 0;
right: 0;
z-index: 1;
.hook-panel-badge;
}
.hook-panel-badge() {}
If you want to override that in a theme let's say you are building outside of the core files (files that come later in compilation), then you would do the following:
.hook-panel-badge() {
right:auto;
}
So, in essence it looks like you are able to override/customize selectors without adding in additional selectors, so it keeps your markup as small as possible.
Is anything like this available in SASS? This looks like an awesome feature that I'd love to use as a primarily SASS user, but I haven't found #extend to be the same. Thanks!
Update
The placeholder feature seems to be the closest thing I've found:
.panel {
background:red;
#extend %hook-panel;
}
%hook-panel {
color:blue;
}
Which renders as:
.panel {
background: red; }
.panel {
color: blue; }
and can be defined after (which is awesome), but this still duplicates the selector. Is there anyway to only render the value of the placeholder in the original selector it is included in?
SASS has a similar facility called mixins:
// Define the mixin
#mixin large-text
font-family: Arial
color: #ff0000
// Use it
.page-title
#include large-text
padding: 10px
// Compiled CSS
.page-title {
font-family: Arial;
color: #ff0000;
padding: 10px;
}
The beauty of mix-ins is that they can take arguments, so you don't need to override commonly-changed selectors:
// Define
#mixin sexy-border($color, $width)
border-color: $color
border-width: $width
border-style: dashed
// Paragraphs in general will have a sexy blue 10px dashed border
p
#include sexy-border(blue, 10px)
// Paragraphs of class "plain" will have a plain old black 1px solid border
p.plain
#include sexy-border(black, 1px)
border-style: solid
// Compiled CSS
p {
border-color: blue;
border-width: 10px;
border-style: dashed;
}
p.plain {
border-color: black;
border-width: 1px;
border-style: solid;
}
SASS mixin documentation.
As far as I can see, there's no exact mapping of the LESS behaviour to a SASS equivalent.
You have the following options:
#extend
.uk-panel-badge {
position: absolute;
top: 0;
right: 0;
z-index: 1;
#extend .hook-panel-badge;
}
.hook-panel-badge{
right:auto;
}
Resulting in:
.uk-panel-badge {
position: absolute;
top: 0;
right: 0;
z-index: 1;
}
.hook-panel-badge, .uk-panel-badge {
right: auto;
}
This produces slightly more CSS than the LESS equivalent does, because the original (unhooked) class is preserved.
#mixin
//theme.scss:
#mixin hook-panel-badge(){
}
#import "hooks";
.uk-panel-badge {
position: absolute;
top: 0;
right: 0;
z-index: 1;
#include hook-panel-badge;
}
_hooks.scss:
//theme creator can override hooks in here.
#mixin hook-panel-badge(){
right:auto;
}
This creates the exact same code as your SASS, but the downside is that you need to define a blank mixin for every hookable class, which is a bit of effort. (You could of course put these all in the _hooks.scss file, but that would make the override code harder to read.
EDIT:
I guess there is one more option as below, which saves a little bit of typing on the extendee's side, but moves away from standard CSS syntax for the extender a bit too much for my liking. You could of course use a partial file as in 2.
#mixin hook($class){
//generic override.
#if($class == "uk-panel-badge"){
right:auto;
}
#else if($class== "selector2"){
//override other classes in this way.
}
}
.uk-panel-badge {
position: absolute;
top: 0;
right: 0;
z-index: 1;
#include hook("uk-panel-badge");
}
Overall I still feel 1 is the best approach.

Resources