Skip to content

Less language Media Bubbling and Merging

Mária Jurčovičová edited this page Mar 6, 2015 · 43 revisions

Conditional directives e.g. css at-rules are used to define rules valid only if specific conditions are met. Css defines three conditional directives: @media, @supports and @document. The most common is media which is used to define rulesets valid only on some media types. For example, it can make marts of stylesheet ignored unless the document is shown on small screen or when it is printed.

Conditional directives must be placed on style sheet top level or inside other conditional directives. They are not allowed inside the rulesets. So, if you use complicated selectors structures, you have to maintain them on multiple places: outside of directives and inside each one.

Example of selector that must be maintained on two places:

.complicated .selector { //place 1
  margin: 4 4 4 4;
}
@media print {
  .complicated .selector {//place 2
    margin: 0 0 0 0;
  }
}

Conditional directives in Less rule can be nested into rulesets, mixins or any other less structures. Compiler interprets nested media as "make exception for this kind of media". The advantage is simple: you do not have to maintain the same rulesets and selectors structures inside multiple media types.

With nested directives:

.complicated .selector {
  margin: 4 4 4 4;
  @media print {
    margin: 0 0 0 0;
  }
}

Nested media rules bubble on to of style sheet and:

  • copy all encountered selectors into their own bodies,
  • merge their own media queries with all media queries encountered on the way up.

Bubbling Through Selectors

As media rule "bubble" on top of style sheet, it collects all encountered selectors and copies them into its own body. As a result, all declarations written inside nested media are going to be applied to the same html elements as normally, but only if their media queries are satisfied.

Example input:

#a {
  color: blue;
  padding: 2 2 2 2;
  // printed document should be rendered differently - it should not be colored
  @media print { 
    color: black;
  }
}

compiles into:

#a {
  color: blue;
  padding: 2 2 2 2;
}
@media print { // all is good except the color
  #a {
    color: black;
  }
}

It is also possible to nest rulesets inside nested media:

#a {
  @media screen { 
    nested {
      color: green;
    }
  }
  color: blue;
}

nested rulesets are combined as usually:

#a {
  color: blue;
}
@media screen {
  #a nested {
    color: green;
  }
}

Merging With Another Media

Media merging happens when the compiler encounters media nested into another media. Whatever is written inside nested media is applied only if both inner and outer media queries are satisfied. It is very similar to rulesets nesting: outer media is compiled as usually, nested media make no difference to it. Inner media queries are combined with outer media queries.

Sample input:

@media print { 
  .class {
    margin: 3 3 3 3;
    color: black;
    @media (max-width: 117px) { // margin should be smaller in small media
      margin: 1 1 1 1;
    }
  }
}

compiles into:

@media print {
  .class {
    margin: 3 3 3 3;
    color: black;
  }
}
@media print and (max-width: 117px) { // print on small media should use smaller margin
  .class {
    margin: 1 1 1 1;
  }
}

Any media can describe multiple mediums. If this is the case, then each medium query described by inner media type is combined with each medium query described by outer media:

@media print, screen { 
  .class {
    // ... whatever ...
    @media (max-width: 117px), (max-device-aspect-ratio: 1367/768) {
      margin: 1 1 1 1;
    }
  }
}

compiles into:

@media print, handheld {
  .class {
    // ... whatever ...  
  }
}
@media print and (max-width: 117px), handheld and (max-width: 117px), 
print and (max-device-aspect-ratio: 1367/768), handheld and (max-device-aspect-ratio: 1367/768) {
 .class {
    margin: 1 1 1 1;
  }
}

Minor Less.js - Less4j Difference

CSS specification allows only one media type inside each media query. That media type can be followed by any number of media expressions joined by "and". If inner media type starts with a media type, resulting less style sheet is invalid. Such input is treated differently by less4j and less.js.

Less.js combines inner and outer media queries as they are and thus produce invalid CSS. Less4j ignores media type in inner media query and produces a warning.

Sample input:

@media print { 
  .class {
    @media screen and (max-width: 117px){
      margin: 1 1 1 1;
    }
  }
}

Less.js generated style sheet:

@media print and screen and (max-width: 117px) {
  .class {
    margin: 1 1 1 1;
  }
}

Less4j generated style sheet:

@media print and (max-width: 117px) {
  .class {
    margin: 1 1 1 1;
  }
}