How to declare same style for #media and descendant selector? - less

I need to define same style for elements under a media query and descendant by another class.
Perfect solution in LESS could be the following [pseudo-code]:
.foo
{
color:red;
.example &,
#media (min-width:800px)
{
color:blue;
}
}
that should be desirable that would be compiled into:
.foo {
color: red;
}
.example .foo {
color: blue;
}
#media (min-width: 800px) {
.foo {
color: blue;
}
}
THIS SYNTAX IS INCORRECT but, do you have some suggestion to solve my problem?

Nope, selectors and #media queries are too different language entities (despite having similar {} syntax) so you can't combine those with comma like in your example.
So to get it DRY (assuming that shared style has more than one property of course) you'll need a mixin (or sort of), for example:
.foo {
color: red;
.somename() {
color: blue;
}
.example & {.somename}
#media (min-width: 800px) {.somename}
}
Also see Passing Rulesets to Mixins examples (if you need even more generic solution).

Thanks to #seven-phases-max suggestion, I finally found a possible solution using Detached Ruleset:
#screen-xs: 480px;
#screen-sm: 769px;
#screen-md: 992px;
#screen-lg: 1200px;
.MEDIAQUERY(#only-media, #min-max, #size, #RULES)
{
#screen-width:~"#{screen-#{size}}";
#mediaQuery: ~"screen and (#{min-max}-width: #{screen-width})";
#media #mediaQuery { #RULES(); }
& when (#only-media = false) {
.#{size} & { #RULES(); }
}
}
.foo_media-and-class
{
color:red;
.MEDIAQUERY(#only-media:false, #min-max:max, #size:md,
{
color:blue;
}
);
.MEDIAQUERY(#only-media:false, #min-max:min, #size:lg,
{
color:yellow;
}
);
}
.foo_only-media
{
color:red;
.MEDIAQUERY(#only-media:true, #min-max:max, #size:md,
{
color:blue;
}
);
.MEDIAQUERY(#only-media:true, #min-max:min, #size:lg,
{
color:yellow;
}
);
}
This solution go beyond and offer other options:
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.

I think your comma might be causing the error.
.foo {
color:red;
.example & {
color:blue;
#media (min-width:800px) {
color:blue;
}
}
}
This is proper syntax to output the following:
.foo {
color: red;
}
.example .foo {
color:blue;
}
#media (min-width:800px) {
.example .foo {
color:blue;
}
}

Related

Using Less, can I not output a base class for extend?

Using Less, I can not output a mixin class by putting parens after the class name
.my-mixin()
{
color: red;
}
That way it must be used as a mixin and a developer can't accidentally use it as a class like <div class="my-mixin">something</div>.
If I do something similar with extend instead:
.my-base
{
color: red;
}
.my-class:extend(.my-base)
{
background-color: grey;
}
The generated CSS is:
.my-base, .my-class
{
color: red;
}
.my-class
{
background-color: grey;
}
How can I change my Less so that the .my-base class isn't output so that it can't be accidentally used?

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;
}
}

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).

Lighten color from parent in Less

I am starting out with Less and one of the reasons I wanted to is because of the ligthen() function. So my first attempt was to do something with that.
This is my HTML
<div class="box blue">
<div class="boxbar">Foo</div>
blue
</div>
I finally got it working, but I doubt it's supposed be like this:
#blue: #468ACE;
#green: #41A53D;
#red: #9C2525;
#purple: #8938BF;
div
{
padding: 10px;
}
.blue {
background-color: #blue;
.boxbar { background-color: lighten(#blue, 10%); }
}
.green {
background-color: #green;
.boxbar { background-color: lighten(#green, 10%); }
}
.red {
background-color: #red;
.boxbar { background-color: lighten(#red, 10%); }
}
.purple {
background-color: #purple;
.boxbar { background-color: lighten(#purple, 10%); }
}
.boxbar
{
height: 10px;
}
How can I refactor this? Surely it must be easier to say "get your parent color, and lighten it a bit". I tried a couple of things: inherit (was worth a shot!), have the lightened versions inside .boxcar. But this obviously compiled to .boxcar .blue.. which is not what I want and I ended with what you can see here.. it works.. but it doesn't feel right. Then I would need to write code for every new color I introduce..
I am not completely sure what your desired solution would be ... but maybe something like making a mixin would help you from having to write so much stuff out.
LESS:
.bgmixin(#color) {
(~".#{color}") {
background-color: ##color;
.boxbar {
background-color: lighten(##color, 10%);
}
}
}
#blue: #468ACE;
#green: #41A53D;
#red: #9C2525;
.bgmixin("blue");
.bgmixin("green");
.bgmixin("red");
CSS:
.blue{
background-color: #468ace;
}
.blue .boxbar {
background-color: #6ea3d9;
}
.green{
background-color: #41a53d;
}
.green .boxbar {
background-color: #59c055;
}
.red{
background-color: #9c2525;
}
.red .boxbar{
background-color: #c52f2f;
}
Update:
In LESS>=1.4 you would want to use something like this to interpolate the class name from the color name:
.bgmixin(#color) {
#classname: ~"#{color}";
.#{classname} {
background-color: ##color;
.boxbar {
background-color: lighten(##color, 10%);
}
}
}