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.
Related
I'm trying to use LESS to dynamically generate a set of mixins that would help me write cleaner media query code. So far in my limited knowledge of the language I've put together code that looks like this:
#sizes: xxs, xs, sm, md, lg;
.mediaQueries(#iterator:1) when(#iterator <= length(#sizes)) {
//Extract name
#sizeName: extract(#sizes, #iterator);
//Attempt to build min-width query
.MQ-min-#{sizeName} (#content) {
#media (min-width: #screen-#{sizeName}) {
#content();
}
}
//Attempt to build max-width query
.MQ-max-#{sizeName} (#content) {
#media (max-width: #screen-#{sizeName}) {
#content();
}
}
.mediaQueries((#iterator + 1));
}
.mediaQueries();
The goal is to have a set of mixins that would allow me to easily and cleanly define some CSS properties for a specific breakpoint, like so:
.generic-class {
background: black;
//Sizes #screen-sm and up
.MQ-min-sm({
background: transparent;
})
}
It doesn't work. Something to note, I'm trying to interpolate the size name into a variable name that would then output me a the px value of that variable into the #media query. Is something like this even possible?
Otherwise my compiler currently breaks on the start of the nested mixin (.MQ-min-#{sizeName} (#content) {) with the error:
Potentially unhandled rejection [2] Missing closing ')' in file ../mixins.less line no. 43
Is something like what I'm trying to achieve possible?
I think the simplest way for you to achieve this is by using a single parametric mixin like given below. This avoids the need for all those iterations, dynamic mixin creations etc.
#sizes: xxs, xs, sm, md, lg;
#screen-xxs: 100px;
#screen-sm: 200px;
.MQ(#content, #sizeName, #max-min) { /* get ruleset, size name and min/max as input */
#selector: ~"(#{max-min}-width: #{screen-#{sizeName}})"; /* form the media selector */
#media #selector { /* use it */
#content();
}
}
.generic-class {
background: black;
.MQ({
background: transparent;
}, /* ruleset */
sm, /* screen size */
max /* min/max */
);
}
If the mixins are for your own usage then this is all that you need. If it is for distribution as library then you may want to put some guards on #sizeName and #max-min variables to restrict invalid values.
Note: Less compiler always had a problem with the interpolation here - #media (min-width: #screen-#{sizeName}) also (I am not sure if it has been addressed) and that's why I created a temp variable.
So you see a lot of code examples do something like
#media all and (max-width:640px) {
div {
background-color:red;
}
}
Now afaik, the keywords "all" and "screen" and some others are for selecting the device type this applies to and the line is just supposed to provide a boolean output.
Since "all" applies to every device, one would imagine that its always 1 and (1 && x) always equals x so "all and" should make no difference whatsoever.
I tried out
#media (max-width:640px) {
div {
background-color:red;
}
}
and at least my browsers agree. Is there anything else I should know about?
See the spec: https://www.w3.org/TR/css3-mediaqueries/
The ‘print’ and ‘screen’ media types are defined in HTML4. The complete list of media types in HTML4 is: ‘aural’, ‘braille’, ‘handheld’, ‘print’, ‘projection’, ‘screen’, ‘tty’, ‘tv’. CSS2 defines the same list, deprecates ‘aural’ and adds ‘embossed’ and ‘speech’. Also, ‘all’ is used to indicate that the style sheet applies to all media types.
...
A shorthand syntax is offered for media queries that apply to all media types; the keyword ‘all’ can be left out (along with the trailing ‘and’). I.e. if the media type is not explicitly given it is ‘all’.
/* I.e. these are identical: */
#media all and (min-width:500px) { … }
#media (min-width:500px) { … }
/* As are these: */
#media (orientation: portrait) { … }
#media all and (orientation: portrait) { … }
In addition, the following media types: 'tty', 'tv', 'projection', 'handheld', 'braille', 'embossed', 'aural' have been deprecated in Media Queries Level 4.
all refers to: all media type devices, print: used for printing, screen: used for desktop screens, mobiles, tablets etc and speech: used for screen-readers that "reads" the page out loud.
In your case where you have specified media type as all, you can try printing the page by right clicking. The printed page will have all the styles applied in short it will exactly look the same.
Now take another example where you specify the media type as screen. If you try to print the page you will not see all the styles getting applied to the page as the styles were defined for screen alone.
If one does not specify all in media query it is by default taken as all.
#media screen {
div {
color: blue;
}
.print{
display: none;
}
}
#media print and (min-width: 200px){
div{
color: tomato;
}
div.not('.example'){
display:none !important;
}
.print{
display: block;
}
}
<div class="example">
<div>Try printing me. See if this blue color appears while printing</div>
<div class="print">I am only visible while printing.</div>
</div>
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.
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.
I am having a philosophical debate with myself over the best place to put media queries within style sheets. I am attempting to structure my CSS modularly (like OOCSS or SMACSS, etc). Given that context, I see two choices:
Put all media queries together in a separate stylesheet or section of the main stylesheet.
Put media queries below their base counterparts. For example, if I have a module called "news-item", I could put any necessary media query styles right below the definition of that module.
I am leaning towards the latter, but it would mean I'd have many more separate media queries (separate ones for each logical block of CSS requiring a responsive adjustment).
Any thoughts on this?
How about using media queries just to load device specific stylesheets
like:
#import url(mydevice.css) this and (that);
or:
<link rel="stylesheet" media="only this and (that)" href="mydevice.css" />
...if you're looking at the device specific adjustments as a kind of "subthemes" to a main layout (just overwriting some properties), this would make sense to me, too.
Approach #2 works better for me.
When I was a newbie, I was using Approach #1 - I was writing my media queries together (at the bottom of my stylesheet or in another file).
.header { ... }
.news-item { ... }
.footer { ... }
/**
* ...
*
* bla bla, imagine a huge amount of styles here
*
* ...
*/
/** All style tweaks for screens < 1024px */
#media screen and (max-width: 1024px) {
.header { ... }
.news-item { ... }
}
This approach has a few downsides. Based on my experience, the most notable one is that the maintainability is a hard. The main reason: .news-item logic is spread across multiple unrelated lines of CSS.
Later on, naturally, I decided to keep the related styles together. Approach #2:
/** Header's styles and media queries */
.header {
...
}
#media screen and (max-width: 1024px) {
.header { ... }
}
#media screen and (max-width: 720px) {
.header { ... }
}
/** News-item's styles and media queries */
.news-item {
...
}
#media screen and (max-width: 1024px) {
.news-item { ... }
}
#media screen and (max-width: 720px) {
.news-item { ... }
}
/** ... and so on */
However, in this approach, repeating media queries max-width values all-around doesn’t look maintainable enough. I solved this issue by using a CSS pre-processor (like SASS) that allows me to replace all them with variables and define them once.
To boost up the maintainability and to make these definitions a lot more elegant I started to use an abstraction on top of the Media Queries.
If you're interested in more details, please read on my blog post :-)
With Sass it's easier to use the media queries directly below the counterparts. But if your CSS is well commented in your modules, I don't see a problem to put the queries bellow since that would be easy to find.
You'll end up writing a little more code retyping the queries, but not a big deal.
May be you can try css variables, which is native support reuse your css!
:root {
--main-color: #F06D06;
}
.main-header {
color: var(--main-color);
}
.main-footer {
background-color: var(--main-color);
}
https://developer.mozilla.org/en-US/docs/Web/CSS/Using_CSS_variables
https://developers.google.com/web/updates/2016/02/css-variables-why-should-you-care
https://css-tricks.com/difference-between-types-of-css-variables/