Using class set in media query as mixin in less
Your problem is a common misconception. LESS does not process the @media
query, the browser does after LESS has done its work. LESS can only create the CSS code that the browser is going to read. So the @media
is "meaningless" to LESS, it is just like any other selector (.someClass div table
, etc.), it only processes what the @media
is going to serve to the browser.
So that means you need to put all your code that changes for the @media
in the @media
block. But you also don't want a bunch of repeated code. So instead, create a master mixin to set your @media
code, and then call that mixin from the media queries:
.makeFooGroup(@w1, @w2) {
.foo {width: @w1}
.foo-2{width: @w2}
.bar{.foo}
.bar-2{.foo}
.bar-3{.foo-2}
}
@media (min-width: 1000px) {
.makeFooGroup(120px, 150px);
}
@media (max-width: 999px) {
.makeFooGroup(110px, 120px);
}
Produces this css:
@media (min-width: 1000px) {
.foo {width: 120px;}
.foo-2 {width: 150px;}
.bar {width: 120px;}
.bar-2 {width: 120px;}
.bar-3 {width: 150px;}
}
@media (max-width: 999px) {
.foo {width: 110px;}
.foo-2 {width: 120px;}
.bar {width: 110px;}
.bar-2 {width: 110px;}
.bar-3 {width: 120px;}
}
For some further info I've given on LESS and @media
related to this, see:
- CSS pre-processor with a possibility to define variables in a @media query
- Media Query grouping instead of multiple scattered media queries that match
LESS: access class inside media query as mixin
I'm not aware of any way that you can except from within the @media
itself, for example:
This LESS
@media screen and (min-width: 768px) {
.navbar {
padding-top: 0;
}
.left-nav {
.navbar; // Use the one from the media query here.
}
}
.navbar {
padding: 20px;
}
Produces this CSS
@media screen and (min-width: 768px) {
.navbar {
padding-top: 0;
}
.left-nav {
padding-top: 0;
}
}
.navbar {
padding: 20px;
}
I'm fairly certain that is not what you are wanting to do.
However, I believe that since the @media
is not itself a selector (it is a query string to the browser), then it cannot be accessed of itself either as a mixin or as a namespace in LESS, and therefore its contents are inaccessible in the way you desire.
If I'm wrong, I hope someone posts an answer otherwise--but I'm not expecting it.
LESS: render content of a media query in class (fallback)
I had the same question and after a suggestion about detached ruleset, I developed a possible solution explained here in details.
Major PROs of this are the following:
- Possibility to set a custom value of screen width for media query,
- Pass
MIN/MAX
value of property used in media query (Try to pass "max
" instead of "min
" calling .MEDIAQUERY mixin) - Toggling generation of simple media query or media query + descendant selector, through
@only-media
boolean.
Can I use mixins to generate new mixins in LESS?
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.
LESS function that builds a media query
The main problem of your first snippet is that you can't use mixin call to set an identifier for a {...}
block. In the snippet the following:
.media(100px, 400px) {
color: red;
}
is actually a new mixin definition and not really a previously defined .media
mixin call (so it simply outputs nothing since this new mixin is never invoked).
And proper mixin call syntax:
.media(100px, 400px); {
color: red;
}
in such context would be an equivalent to:
@query: ~"@media (min-width: 100px) and (max-width: 400px)"; {
color: red;
}
which of course does not make any sense for Less at all and it would throw a error.
-------
Your second snippet is more correct, but yes, since both mixin calls share the same scope there's only one @query
variable. It's possible to isolate them by putting each into unnamed namespace (which is simply a ruleset with &
name so it creates a new scope but then is output as part of the outer ruleset):
.class {
& {.media(100px, 400px);
@media @query {
color: red;
}}
& {.media(401px, 800px);
@media @query {
color: green;
}}
}
This does the trick but obviously it does not look like something really useful (too verbose and unreadable) so for the sake of reference it would make sense to mention other approaches:
-------
Today, the most clean solution for the particular case would be to use ruleset as mixin parameter:
.media(@min, @max, @styles) {
@media (min-width: @min)
and (max-width: @max) {
@styles();
}
}
.class {
.media(100px, 400px, {
color: red;
});
.media(401px, 800px, {
color: green;
});
}
Though I doubt that in a practical project you'd want to explicitly repeat pixel values every time you need the corresponding media so most likely eventually you end with more semantic mixins, e.g.:
.media(@min, @max, @styles) {
@media (min-width: @min)
and (max-width: @max) {
@styles();
}
}
.tiny-screen(@styles) {.media(100px, 400px, @styles)}
.not-so-tiny-screen(@styles) {.media(401px, 800px, @styles)}
.class {
.tiny-screen({
color: red;
});
.not-so-tiny-screen({
color: green;
});
}
------
Passing rulesets to mixins is not the only method to achieve the goal, there're other methods with various pros and cons (some of those can look even more readable if you go the "semantic media blocks" way). See for example https://stackoverflow.com/a/15842048/2712740 (obviously search for [less] media
here at SO will point to more inspirations).
Avoiding multiple @media when using Bootstrap 3 less mixins
There's .make-xs-column
mixin in current Bootstrap version, it generates the same CSS without any media queries.
Related Topics
Setting Svg Element Width/Height Attributes Using CSS in Firefox
Which Screen Reader Would Be Best to Test Site Accessibility and How to Configure That
How to Select Every Other Group of Three in CSS
:Hover Not Working on Svg When Svg Is in External File
How to Add Zig Zag Border to a Box Contains Background Image
Should the Cursor Property Be Set in a Rule with or Without the :Hover Pseudo-Class
Differencebetween :Where() and :Is()
How to Remove the Arrow in Dropdown in Bootstrap 4
Using Class Set in Media Query as Mixin in Less
Style Type="Text/Css" ... What Else Is There
Why Bootstrap 3 Navbar Dropdown Doesn't Work in IE8
Css: Adding a Border Changes the Background-Color (!)
How to Connect a CSS Animation's End to the Beginning So It Smoothly Continues