Change mixin variable based on media (or some other condition) - less

Say I have a complex mixin function. Something like
.MyMixin(#Count, #ManyOtherVars)
{
.Item
{
width: calc( 100% / #Count);
}
//lot's of other rules not affected by #Count
}
And then I want to call this mixin with different values for different media
e.g.
.SomeClass
{
#media screen (max-width: 1000px)
{
.MyMixin(5, 1);
}
#media screen (min-width: 1000px)
{
.MyMixin(10, 1);
}
}
This works fine, except the generated css duplicates all the stuff which has not changed
#media screen (max-width: 1000px)
{
.SomeClass .Item
{
width: calc( 100% / 5 );
}
.SomeClass
{
/* lot's of other rules not affected by #Count */
}
}
#media screen (min-width: 1000px)
{
.SomeClass .Item
{
width: calc( 100% / 10 );
}
.SomeClass
{
/* lot's of other rules not affected by #Count */
}
}
Which, needless to say, is quite wasteful when only one thing changed.
Are there any workarounds to produce a leaner output that don't require the calling class to know something about what the mixin does, or for the mixin to know about media rules?
I thought maybe a detached rule-set could help, but given variables are not exported from those I'm not sure how it would.
Desired output:
#media screen (max-width: 1000px)
{
.SomeClass .Item
{
width: calc( 100% / 5 );
}
}
#media screen (min-width: 1000px)
{
.SomeClass .Item
{
width: calc( 100% / 10 );
}
}
.SomeClass
{
/* lot's of other rules not affected by #Count */
}

Remove static styles from your mixin and place them directly to SomeClass selector.
.SomeClass {
// Lot's of other rules not affected by #Count
#media screen (max-width: 1000px) {
.MyMixin(5, 1);
}
#media screen (min-width: 1000px) {
.MyMixin(10, 1);
}
}
Better solution:
.MyMixin(#Count, #ManyOtherVars) {
width: calc( 100% / #Count);
}
.SomeClass {
// Lot's of other rules not affected by #Count
.Item {
#media screen (max-width: 1000px) {
.MyMixin(5, 1);
}
#media screen (min-width: 1000px) {
.MyMixin(10, 1);
}
}
}
Now mixin does only one thing. It's simple and reusable.

Related

How to disable Bootstrap 3 mobile responsive?

I was commenting these code at bootstrap.css and my page is now not responsive. But my navbar still responsive. how to disable that?
/*#media (min-width: 768px) {
.container {
width: 750px;
}
}
#media (min-width: 992px) {
.container {
width: 970px;
}
}
#media (min-width: 1200px) {
.container {
width: 1170px;
}*/
Follow Bootstrap's official doc.
Bootstrap made a non-responsive.css template to disable responsiveness for your template. Take a look at this documentation: http://getbootstrap.com/getting-started/#disable-responsive
Example: http://getbootstrap.com/examples/non-responsive
But I see you want to do it your own way, so you could try this:
#media (min-width: 768px) {
.container, .navbar {
width: 750px !important;
}
}
#media (min-width: 992px) {
.container, .navbar {
width: 970px !important;
}
}
#media (min-width: 1200px) {
.container, .navbar {
width: 1170px !important;
}
}
Note that the code above will only apply to the classes container and navbar. There are other components/classes that should have static widths and heights. So I would recommend you to take a look at the example above.

Error when minifying CSS with #keyframes

I'm using the default bundling and minification in MVC 4.
One of our stylesheets starts with this bit of CSS:
#media (max-width: 979px) {
#keyframes sidebarSlideInRight {
from { right: -220px }
to { right: 0 }
}
#-webkit-keyframes sidebarSlideInRight {
from { right: -220px }
to { right: 0 }
}
}
The minification fails with this error: run-time error CSS1019: Unexpected token, found '}' and it points to the first character on line 13 (that's the very last } in the snippet above).
I'm not overly familiar with CSS in general and I was wondering:
Is that valid CSS? It fails validation at
https://jigsaw.w3.org/css-validator/validator
What changes are needed to get the file minified? There are about 300 lines in the file so I would really like to get it minified if possible.
#keyframes declarations must be outside media queries.
#keyframes sidebarSlideInRight {
from { right: -220px }
to { right: 0 }
}
And then you use them in the media query like this:
#media (max-width: 979px) {
.some-class {
animation: sidebarSlideInRight 1s;
}
}
To add to #Flower's answer:
If you need the animation to work differently based on a media query, make multiple keyframes with different names. Then in the media query use the animation-name for the needed keyframe.
#keyframes sidebarSlideInRight-1 {
from { right: -220px }
to { right: 0 }
}
#keyframes sidebarSlideInRight-2 {
from { right: -250px }
to { right: 50 }
}
#media (max-width: 768px) {
.some-class {
animation: sidebarSlideInRight-1 1s;
}
}
#media (max-width: 979px) {
.some-class {
animation: sidebarSlideInRight-2 1s;
}
}
Like #Flower said, just make sure the keyframes are not in the media query.

Set "min-width" or "max-width" in a media query passing a parameter to a mixin

I would like to make dynamic MIN/MAX suffix in properties defined in a Less MediaQuery.
I wrote this code but it does not compile:
#screen-md: 800px;
.MEDIAQUERY(#min-max, #size)
{
#media screen and (#{min-max}-width: #size)
{
#{min-max}-width:100px;
}
}
header
{
background-color: blue;
.MEDIAQUERY ( #min-max: max, #size: #screen-md );
}
While #{min-max}-width:100px; is a correct syntax, equivalent applied in Mediaquery definition is not allowed, but I need to set sometime "max-width" value, and others "min-width" value in my media queries. How to obtain this?
Option 1: (Using a variable and interpolation)
You can do it like below
.MEDIAQUERY(#min-max, #size) {
#mediaQuery: ~"screen and (#{min-max}-width: #{size})";
#media #mediaQuery {
#{min-max}-width:100px;
}
}
Option 2: (Using Guards)
You can use guards in the mixin like below to check what was the value that was passed for the #min-max parameter and then output the appropriate CSS based on it.
.MEDIAQUERY(#min-max, #size){
& when (#min-max = min) {
#media screen and (min-width: #size) {
min-width:100px;
}
}
& when (#min-max = max) {
#media screen and (max-width: #size) {
max-width:100px;
}
}
}
When the above mixin is called like below (with either of the options mentioned above):
header
{
background-color: blue;
.MEDIAQUERY ( #min-max: max, #size: #screen-md );
}
div{
background-color: red;
.MEDIAQUERY ( #min-max: min, #size: #screen-md );
}
it would compile into the below CSS:
header {
background-color: blue;
}
#media screen and (max-width: 800px) {
header {
max-width: 100px;
}
}
div {
background-color: red;
}
#media screen and (min-width: 800px) {
div {
min-width: 100px;
}
}

Does LESS have something comparable to the #content directive in Sass?

I tried to convert a more "advance" mixin from SASS to LESS but unsuccessful.
Here is the mixin:
.breakpoint(#point) {
#if #point == really big{
#media (max-width: 80em) { #content; }
}
#if #point == mid {
#media (max-width: 60em) { #content; }
}
#if #point == small {
#media (max-width: 42em) { #content; }
}
}
and another one, I didn't touch this one:
#mixin keyframes( $animationName )
{
#-webkit-keyframes $animationName {
#content;
}
#-moz-keyframes $animationName {
#content;
}
#-o-keyframes $animationName {
#content;
}
#keyframes $animationName {
#content;
}
}
update
I did not check the sample code provide by #Harry in the comments, before answering this question. This sample code provide a good a clean way to solve your question too. Please also see: http://codepen.io/hari_shanx/pen/ayIej
First notice that Less do not support if / else constructs (alhought mixins libraries such as https://github.com/pixelass/more-or-less adds .if() (if - then - [else]) ), but uses guards to create conditional mixins, also see: http://lesscss.org/features/#mixin-guards-feature
or alternatively consider http://lesscss.org/features/#mixins-parametric-feature-pattern-matching
Your mixins also use the #content; which you call the #content directive, i think you should compare this with "Passing Rulesets to Mixins", see: http://lesscss.org/features/#detached-rulesets-feature.
Your first mixin using pattern-matching:
.breakpoint(reallybig;#content)
{
#media (max-width: 80em) { #content(); }
}
.breakpoint(mid;#ruleset)
{
#media (max-width: 80em) { #content(); }
}
example caller:
.breakpoint(reallybig; {p{color:red;}});
Your first mixins leveraging guards:
.breakpoint(#size;#content) when (#size = 'really big')
{
#media (max-width: 80em) { #content(); }
}
.breakpoint(mid;#ruleset) when (default())
{
#media (max-width: 80em) { #content(); }
}
.breakpoint('really big'; {p{color:red;}});
And your second mixin:
.keyframes(#animationName;#animation)
{
#-webkit-keyframes #animationName {
#animation();
}
#-moz-keyframes #animationName {
#animation();
}
#-o-keyframes #animationName {
#animation();
}
#keyframes #animationName {
#animation();
}
}
#animation: {0% {
left: 0;
transform: translate(10px, 20px);
}
100% {
left: 100%;
transform: translate(100px, 200px);
}};
.keyframes(test;#animation);

LESS function that builds a media query

Can you write a function in LESS that outputs a media query when you pass in values for it's breakpoints?
I'd like to be able to create them on the fly like this:
// Something like this
.media(#min, #max) {
#query: ~"#media (min-width: #{min}) and (max-width: #{max})";
}
.class {
.media(100px, 400px) {
color: red;
}
.media(401px, 500px) {
color: green;
}
}
// Outputs this:
#media (min-width: 100px) and (max-width: 400px) {
.class {
color: red;
}
}
#media (min-width: 401px) and (max-width: 500px) {
.class {
color: green;
}
}
I thought I had this working, but because the mixins are called within the same scope, the variable isn't being assigned in the second call:
.media (#min, #max) {
#query: ~"(min-width: #{min}) and (max-width: #{max})";
}
.class {
width: 100%;
max-width: 300px;
.media(100px, 400px);
#media #query {
color: red;
}
.media(401px, 800px);
#media #query {
color: green;
}
}
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).