Using Class Set in Media Query as Mixin in Less

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:

  1. CSS pre-processor with a possibility to define variables in a @media query
  2. 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



Leave a reply



Submit