Pass properties to less function - css

I'm trying to write a mixin which handles different screen sizes. I want to make it as generic as possible to try follow the DRY principle.
So far I have tried:
.vary_width(#prop, #val1, #val2, #val3) {
#media(max-width: 1023px) {
#{prop}: #val1;
}
#media(min-width: 1024px) {
#{prop}: #val2;
}
#media(min-width: 1080px) {
#{prop}: #val3;
}
}
This is failing to compile. I have also tried a suggestion (although I think it was aimed at a less version >1.4) to use use the Ignore: ~"a;#{prop}:#{value}"; command, this is not working either, compiling with to Ignore: a;margin: 5px; in CSS.
Many thanks.
Edit:
The error being received when running lessc master.less master.css:
ParseError: Unrecognised input in /path/to/file/mixins.less on line 46, column 16:
45 #media(max-width: 1023px) {
46 #{prop}: #val1;
47 }

I was using the wrong version of lessc. Credit to #seven-phases-max for the guidance.

Related

Less media queries don't seem to be compiled

I have a media queries in less file, code:
#phoneMin: 0px;
#tabletMin: 768px;
#smallDesktopMin: 992px;
#phoneMax: (#tabletMin - 1);
#tabletMax: (#smallDesktopMin - 1);
#atLeastTablet: ~"only screen and (min-width: #{tabletMin})";
When I #import this file into another less file and utilize my media queries like so:
.container {
#media #atLeastTablet {
margin-top: 160px;
}
}
Not only does the media query just not work, but it also doesn't seem to compile into the resulting css file, which reads like this:
.container {
margin-top: 160px;
}
EDIT I attempted to run my server and I'm now getting the following error message: "Unexpected token(1:0)" referring to the first character (period) in one of my less files:
.blogPost {
^ .logo {
}
}
The error is being thrown during the babel 6 compilation process. Here is the stack trace:
at Parser.pp.raise (/usr/local/lib/node_modules/babel-cli/node_modules/babylon/lib/parser/location.js:22:13)
at Parser.pp.unexpected (/usr/local/lib/node_modules/babel-cli/node_modules/babylon/lib/parser/util.js:91:8)
at Parser.pp.parseExprAtom (/usr/local/lib/node_modules/babel-cli/node_modules/babylon/lib/parser/expression.js:510:12)
at Parser.<anonymous> (/usr/local/lib/node_modules/babel-cli/node_modules/babylon/lib/plugins/jsx/index.js:404:22)
at Parser.parseExprAtom (/usr/local/lib/node_modules/babel-cli/node_modules/babylon/lib/plugins/jsx/index.js:404:22)
at Parser.pp.parseExprSubscripts (/usr/local/lib/node_modules/babel-cli/node_modules/babylon/lib/parser/expression.js:265:19)
at Parser.pp.parseMaybeUnary (/usr/local/lib/node_modules/babel-cli/node_modules/babylon/lib/parser/expression.js:245:19)
at Parser.pp.parseExprOps (/usr/local/lib/node_modules/babel-cli/node_modules/babylon/lib/parser/expression.js:176:19)
at Parser.pp.parseMaybeConditional (/usr/local/lib/node_modules/babel-cli/node_modules/babylon/lib/parser/expression.js:158:19)
at Parser.pp.parseMaybeAssign (/usr/local/lib/node_modules/babel-cli/node_modules/babylon/lib/parser/expression.js:121:19)
It turns out the issue is in trying to import my less in a subscript vs my webpack entry point. Moving the import here fixed the issue.

Possible Bug in Nested Mixins in Media Queries using LESS

EDIT: RESOLVED
I am working on a way to easily write LESS code that takes parameters but still works with media queries. This is turning out to be rather convoluted, but I have gotten it working – on all sizes except one. The medium and large sizes work, but small is for some reason not printing the parameter, leaving me with css like font-size: ;.
Here I define my media sizes:
#m-small = ~"screen and (max-width: 799px)";
#m-medium = ~"screen and (min-width: 800px) and (max-width: 1299px)";
#m-large = ~"screen and (min-width: 1300px)";
Then, the main function I call, where #attr is the CSS property (e.g. font-size) and #parameter is the variable (e.g. fs-medium). To use this, I can write .media('font-size', 'fs-medium'), which is significantly less verbose than defining every media query.
Edit: There was a bug here, hence the problem; I have fixed it.
.media(#attr, #parameter) {
#media #m-small {
.small(#attr, #parameter);
}
#media #m-medium {
.medium(#attr, #parameter);
}
#media #m-large {
.large(#attr, #parameter);
}
}
These functions store the default values for parameters at various sizes, allowing me to consolidate where I define my variables, grouped by media query:
.small(#attr, #parameter) {
#fs-small : 1.4rem;
#fs-medium : 2.0rem;
#fs-large : 3.4rem;
#logo-width : 10rem;
.guards();
}
.medium(#attr, #parameter) {
#fs-small : 1.4rem;
#fs-medium : 2.4rem;
#fs-large : 3.8rem;
#logo-width : 12rem;
.guards();
}
.large(#attr, #parameter) {
#fs-small : 1.4rem;
#fs-medium : 1.8rem;
#fs-large : 5rem;
#logo-width : auto;
.guards();
}
In the above code, I call .guards() to render the content. This checks through my list of guards for one with a matching attribute, because LESS does not allow variables to be used in CSS property names. In these guards, I dynamically call the parameter, so that if I passed fs-medium, it will render #fs-medium's value.
.guards() when (#attr = 'font-size') {
font-size: ##parameter;
}
.guards() when (#attr = 'width') {
width: ##parameter;
}
Now, as I said, this works fine for the medium and large sizes, so I feel like there is either a typo in my code (I've checked) or a bug in LESS. One piece of code that uses this is as follows:
nav {
.media('font-size', 'fs-medium');
}
Which renders the following content:
#media screen and (max-width: 799px){
nav{ font-size:; }
}
#media screen and (min-width: 800px) and (max-width: 1299px){
nav{ font-size:2.4rem; }
}
#media screen and (min-width: 1300px){
nav{ font-size:1.8rem; }
}
Why is the small font-size missing?
I have discovered that I do indeed have a typo in my question, where I typed 'paremeter' under the .small mixin. I have edited it in the original post, but I am leaving it here for others trying to use media queries in LESS in a generalized way.
Verdict: typo.

Media query not working in one environment, but working in another

I have a LESS environment that is bringing together multiple files and putting everything together into a massive .CSS file (forced to work this way).
However, in one environment the "#media (min-width: 768px) and (max-width: 979px)" declaration is being validated and the custom CSS for it is rendering properly in all instances. However, in another environment with the exact same media query and CSS, it is not even acknowledging it within the CSS file.
Working environment: giving.massgeneral.org
[CSS^] https://www.dropbox.com/s/4hxtevg0ft0hsae/base.css
Non-working environment: secure.massgeneral.org/bootstrap-library
[CSS^] https://www.dropbox.com/s/ncrbgxs2ot184cm/bbnc.css
The most notable issue is the following query that is completely being ignored in the "secure." environment:
// Tablets & small desktops only
#media (min-width: 768px) and (max-width: 979px) {
// Hide everything else
.hidden-desktop { display: inherit !important; }
.visible-desktop { display: none !important; }
// Show
.visible-tablet { display: inherit !important; }
// Hide
.hidden-tablet { display: none !important; }
}
It is successfully generating this code and placing it into the "bbnc.css" file, however, it is not associating the styles with the classes above when in the viewport designated in the "secure." environment.
Any advice outside would be greatly appreciate on getting this to validate.

Media Query grouping instead of multiple scattered media queries that match

I'm experimenting with LESS (not a fan of the SASS syntax) and have been trying to find out what the best way to do media queries with it would be.
I read through this blog post on how to "do" media queries with LESS, but it points out the fact that this causes all the media queries to be separated and scattered throughout the resulting CSS. This doesn't really bother me (I could care less about the result and more about it working). What did bother me was a comment that talked about issues when viewing from iOS devices and the commenter found that once the media queries were consolidated the issue was resolved.
Has anyone found a good solution for using media queries with LESS?
The way I invision this working would be something like...
//Have an overall structure...
.overall(){
//Have ALL your CSS that would be modified by media queries and heavily use
//variables that are set inside of each media queries.
}
#media only screen and (min-width: 1024px){
//Define variables for this media query (widths/etc)
.overall
}
I understand that there could be some issues with this, but the current setup doesn't seem to be that beneficial.
So I guess my question is if there have been any good solutions/hacks to allow for grouped media queries?
(Just incase it matters I use dotless as the engine to parse my .less files)
First, your solution given in the question certainly has some usefulness to it.
One thing I thought, however, was that it would be nice to define all the media query variables "near" one another (your solution would have them under each media query call). So I propose the following as an alternative solution. It also has drawbacks, one being perhaps a bit more coding up front.
LESS Code
//define our break points as variables
#mediaBreak1: 800px;
#mediaBreak2: 1024px;
#mediaBreak3: 1280px;
//this mixin builds the entire media query based on the break number
.buildMediaQuery(#min) {
#media only screen and (min-width: #min) {
//define a variable output mixin for a class included in the query
.myClass1(#color) {
.myClass1 {
color: #color;
}
}
//define a builder guarded mixin for each break point of the query
//in these is where we change the variable for the media break (here, color)
.buildMyClass1() when (#min = #mediaBreak1) {
.myClass1(red);
}
.buildMyClass1() when (#min = #mediaBreak2) {
.myClass1(green);
}
.buildMyClass1() when (#min = #mediaBreak3) {
.myClass1(blue);
}
//call the builder mixin
.buildMyClass1();
//define a variable output mixin for a nested selector included in the query
.mySelector1(#fontSize) {
section {
width: (#min - 40);
margin: 0 auto;
a {
font-size: #fontSize;
}
}
}
//Again, define a builder guarded mixin for each break point of the query
//in these is where we change the variable for the media break (here, font-size)
.buildMySelector1() when (#min = #mediaBreak1) {
.mySelector1(10px);
}
.buildMySelector1() when (#min = #mediaBreak2) {
.mySelector1(12px);
}
.buildMySelector1() when (#min = #mediaBreak3) {
.mySelector1(14px);
}
//call the builder mixin
.buildMySelector1();
//ect., ect., etc. for as many parts needed in the media queries.
}
}
//call our code to build the queries
.buildMediaQuery(#mediaBreak1);
.buildMediaQuery(#mediaBreak2);
.buildMediaQuery(#mediaBreak3);
CSS Output
#media only screen and (min-width: 800px) {
.myClass1 {
color: #ff0000;
}
section {
width: 760px;
margin: 0 auto;
}
section a {
font-size: 10px;
}
}
#media only screen and (min-width: 1024px) {
.myClass1 {
color: #008000;
}
section {
width: 984px;
margin: 0 auto;
}
section a {
font-size: 12px;
}
}
#media only screen and (min-width: 1280px) {
.myClass1 {
color: #0000ff;
}
section {
width: 1240px;
margin: 0 auto;
}
section a {
font-size: 14px;
}
}
For responsive Wordpress sites I use a starter theme called Bones by Eddie Machado ( http://themble.com/bones/ ). I rather like the way it uses media queries, it has different stylesheets for different breakpoints (480+, 768+ etc) which you can change depending on your design.
It then imports these with #import into one stylesheet underneath the appropriate media queries. You edit all of these in LESS and, I use Simpless by Kiss ( http://wearekiss.com/simpless ) to compile my .less stylesheets into .css automatically. I really find it a really good starting point for developing a simple responsive site. Even if you're not developing in Wordpress you may want to check out how they're structured their media queries as it all seems to work fine even with the use if LESS.

SASS 3.2 Media Queries and Internet Explorer Support

I recently implemented this technique with SASS 3.2 using #content blocks on a project I've been working on, and I've just gotten to the point where I need to include support for older browsers such as IE7 and 8.
Example:
.overview {
padding: 0 0 19px;
#include respond-to(medium-screens) {
padding-top: 19px;
} //medium-screens
#include respond-to(wide-screens) {
padding-top: 19px;
} //medium-screens
}
They both don't support media queries, and I've often handled this in the past by serving up all styles to these browsers when I had my media queries separated into separate partial files such as _320.scss, _480.scss and in my IE stylesheet loading them like so:
#import 320.scss;
#import 480.scss;
etc.
Which would load all styles, and always assign IE7 - 8 a 940px (or whatever the max width is) layout and styles. By nesting styles in SASS 3.2 inline like this, it eliminates the need for separate partial stylesheets, but totally screws up how I load styles for IE.
Any ideas or solutions on how to combat this? I could use a polyfill such as respond.js to force IE to use media queries, but would prefer to just serve up a non-flexible site to IE.
Any ideas on either how to best organize these files, or a better solution?
You can generate a separate stylesheet for IE<9 that contains everything your normal sheet has, but with flattened media queries based on a set width.
Full explanation here http://jakearchibald.github.com/sass-ie/, but basically you have this mixin:
$fix-mqs: false !default;
#mixin respond-min($width) {
// If we're outputting for a fixed media query set...
#if $fix-mqs {
// ...and if we should apply these rules...
#if $fix-mqs >= $width {
// ...output the content the user gave us.
#content;
}
}
#else {
// Otherwise, output it using a regular media query
#media screen and (min-width: $width) {
#content;
}
}
}
Which you'd use like this:
#include respond-min(45em) {
float: left;
width: 70%;
}
This would be inside all.scss, which would compile down to all.css with media queries. However, you'd also have an additional file, all-old-ie.scss:
$fix-mqs: 65em;
#import 'all';
That simply imports all, but flattens media query blocks given a fake width of 65em.
I use LESS for a lot of my work, but on larger projects, with many people working across files, I don't like using breakpoint files, such as 1024.less.
My and my team use a modular approach, such as header.less which contains all the code for just the header, including the associated breakpoints.
To get round IE problems (we work in a corporate environment), I use this approach:
#media screen\9, screen and (min-width: 40em) {
/* Media queries here */
}
The code inside the media query is always executed by IE7 and less. IE9 and above obeys the media queries like a proper browser should. The problem is IE8. To solve this, you need to make it behave like IE7
X-UA-Compatible "IE=7,IE=9,IE=edge"
I've found this doesn't always work if set in the metatags in the HTML, so set it using the server headers.
See the gist here:
https://gist.github.com/thefella/9888963
Making IE8 act like IE7 isn't a solution that works for everyone, but it suits my needs.
Jake Archibald has the best technique I've seen to date for achieving this. This technique automatically creates a separate stylesheet for IE, with all the same styles inside of your media queries but without the media query itself.
I also campaigned to get this technique built into the popular breakpoint extension for Sass, if you're interested in using that!
If you wanted to keep everything under one roof and only have a single http request for your older browser visitors you could do something like this
Setting up your initial respondto mixin
// initial variables set-up
$doc-font-size: 16;
$doc-line-height: 24;
// media query mixin (min-width only)
#mixin breakpoint($point) {
#media (min-width: $point / $doc-font-size +em) { #content; }
}
this will create a min-width media query and output your px value ($point) as an em value.
From this you'd need to create this mixin
#mixin rwdIE($name, $wrapper-class, $IE: true) {
#if $IE == true {
.lt-ie9 .#{$wrapper-class} {
#content;
}
.#{$wrapper-class} {
#include breakpoint($name) {
#content;
}
}
}
#else if $IE == false {
.#{$wrapper-class} {
#include breakpoint($name) {
#content;
}
}
}
}
Here if you pass a piece of Sass(SCSS) like this
#include rwdIE(456, test) {
background-color: #d13400;
}
it will return this code
.lt-ie9 .test {
background-color: #d13400;
}
#media (min-width: 28.5em) {
.test {
background-color: #d13400;
}
}
This will give you the you the IE and 'new browser' CSS in one file. If you write -
#include rwdIE(456, test, false) {
background-color: #d13400;
}
You will get -
#media (min-width: 28.5em) {
.test {
background-color: #d13400;
}
}
I hope this helps, I've got this on a codepen here too - http://codepen.io/sturobson/pen/CzGuI
There is a CSS3 Mixin I use that has a variable for IE filters. You could do something similar by having a global variable, $forIE or something, wrap the media query mixin within an if and then generate the stylesheet with or w/o the queries.
#if $forIE == 0 {
// Media Query Mixin
}
Or use the #if to import a 3rd scss (_forIE.scss?) that will override things with your IE specific styles.

Resources