Can you create custom breakpoints with LESS mixins? - css

Most of the time, I use LESS variables with preset breakpoints for media queries like this:
#s-max : ~"screen and (max-width: 40em)";
#m-max : ~"screen and (max-width: 50em)";
#l-max : ~"screen and (max-width: 60em)";
USAGE
.some-class {
color: red;
#media #s-max {
color: blue;
}
}
But sometimes, I would like to be able to refer to an arbitrary breakpoint in my .less stylesheet without having to set a new preset value in my separate mixin file.
You can do this in SASS. The mixin looks like this:
#mixin bp-min($canvas) {
#media only screen and (min-width:$canvas) {#content;}
}
USAGE
#include bp-min(750px) {
//responsive styling for min-width of 750px
}
In LESS, I'm imagining the equivalent mixin would look something like this:
.bp-min(#min) {
#media only screen and (min-width:#min)...
}
The only problem is, the lack of the {#content} argument in LESS, which grabs the rest of the styling inputted by the developer. I love SASS, but I can't use it at work.
Does anyone know of a LESS-based solution to this problem?

It is now similar to SASS
As of 1.7.0 (2014-02-27) you can now use #rules in place of the sassy #content.
For example:
.breakpoint-small(#rules) {
#media screen and (min-width: 40em) { #rules(); }
}
ul {
width: 100%;
.breakpoint-small({
width: 50%;
});
}
outputs, as expected:
ul {
width: 100%;
#media screen and (min-width: 40em) {
width: 50%;
}
}
The differences being:
function takes #rules as an argument
additional parenthesis when invoking the function
'.' syntax as opposed to '#include'
This can be combined with an additional argument to provide syntax equivalent to a nice bit of sass:
.breakpoint(#size, #rules) {
#media screen and (min-width: #size) { #rules(); }
}
#large: 60em;
ul {
.breakpoint(#large, {
width: 50%;
});
}
edit: To be honest I prefer a way more simple approach in less:
#break-large: ~"screen and (min-width: 60em)";
ul {
#media #break-large {
width: 50%;
}
}
Source: I too use sass at home and less at work

Using Pattern Matching
I believe this achieves what you want:
LESS
/* generic caller */
.bp-min(#min) {
#media only screen and (min-width:#min) {
.bp-min(#min, set);
}
}
/* define them */
.bp-min(750px, set) {
test: (#min - 300px);
}
.bp-min(400px, set) {
test: (#min - 100px);
}
/* call them */
.bp-min(750px);
.bp-min(400px);
Output CSS
#media only screen and (min-width: 750px) {
test: 450px;
}
#media only screen and (min-width: 400px) {
test: 300px;
}
By defining a set pattern mixin for the various sizes, and then using that pattern within the generic .bp-min(#min) mixin, I believe we have the same abstraction in LESS that you have in SCSS, with slightly more code because I believe SCSS defines and calls in one #include statement, whereas here we need two.

(In addition to the prev. answer) Or something like this:
.bp-min(#canvas) {
#media only screen and
(min-width: #canvas) {.content}
}
// usage:
& { .bp-min(900px); .content() {
color: red;
}}
& { .bp-min(600px); .content() {
color: blue;
}}
// more usage examples:
.class-green {
.bp-min(450px); .content() {
color: green;
}}
& { .bp-min(300px); .content() {
.class-yellow {
color: yellow;
}
.class-aqua {
color: aqua;
}
}}
Replace .content with .- if you prefer shorter stuff.

In my case I needed my variables to reference other variables, so some of these solutions did not work. Here is what I went with.
#bp-xs: ~"screen and (max-width:"#screen-xs-max~")";
#bp-sm: ~"screen and (max-width:"#screen-sm-max~")";
#bp-md: ~"screen and (max-width:"#screen-md-max~")";
#bp-lg: ~"screen and (max-width:"#screen-lg-max~")";
and then use them like so
#media #bp-sm {
...
}

Related

version AEM 6.5, is it possible to combine classes?

I am working on AEM V.6.5 and writing properties for responsive.
I need to include every GridColumn here as code below.
#media (max-width: 768px) {
.aem-Grid.aem-Grid--default--12 > {
.aem-GridColumn.aem-GridColumn--default--12,
.aem-GridColumn.aem-GridColumn--default--11,
.aem-GridColumn.aem-GridColumn--default--10,
.aem-GridColumn.aem-GridColumn--default--8,
.......
.aem-GridColumn.aem-GridColumn--default--1 {
width: 100%;
}
}
}
It is very long! I am looking for a short way to write. I try code (below), but somehow it doesn't work.
#media (max-width: 768px) {
.aem-Grid.aem-Grid--default--12 > {
.aem-GridColumn.aem-GridColumn--default--* {
width: 100%;
}
}
}
Please give me a hand. Thanks!
If you're able to use LESS CSS you could use a Recursive Mixin.
#media (max-width: 768px) {
.aem-Grid.aem-Grid--default--12 > {
.generate-columns(12);
}
}
.generate-columns(#n, #i: 1) when (#i =< #n) {
.aem-GridColumn.aem-GridColumn--default--#{i} {
width: 100%;
}
.generate-columns(#n, (#i + 1));
}
We have an OOTB file present to make any changes for the AEM grid templates. That will be way easier for you to do.
File is : grid.less
Path: ui.apps/src/main/content/jcr_root/apps/{client-name}/clientlibs/clientlib-site/less/grid.less
Here's a helpful article

Deduplicating CSS rules when using #media queries

I've noticed more and more that my stylesheets generally have repeated rules as a normal selector as well as inside a #media ... {} query and generates quite a lot of CSS bloat.
Here's a simple use-case of the problem that I see popping up ad nauseam:
.big-red {
color:red;
font-size: 3em;
... lots of other stuff
}
.dynamic-uber-class {
color:green;
font-size:2em;
}
#media only screen and (min-width: 48em) {
.dynamic-uber-class {
color:red;
font-size: 3em;
... lots of other .big-red duplicated stuff
}
}
I notice that the problem becomes increasingly problematic when I use mixins in less or scss (because it's really easy to add), but what's really needed is mixins in CSS (for which I won't be holding my breath!). That said, I've noticed CSS-Properties, with some support and #apply that has no support.
Has anyone stumbled on a CSS only way of not having this duplication?
I'm aware that with a bit of Javascript I can simply add/remove classes, but I like my sites working properly with javascript disabled (as much as possible).
Edit:
For those struggling to understand the problem, take a real-world example from bootstrap's grid:
.col-xs-12 {
width: 100%;
}
.col-xs-11 {
width: 91.66666667%;
}
.col-xs-10 {
width: 83.33333333%;
}
...
#media (min-width: 768px) {
.col-sm-12 {
width: 100%;
}
.col-sm-11 {
width: 91.66666667%;
}
.col-sm-10 {
width: 83.33333333%;
}
}
If you've ever looked at the generated CSS of bootstrap it is very fat indeed due to the problem.
Why not something like this:
.uber-class, .dynamic-uber-class {
color:red;
font-size: 3em;
... lots of other duplicated stuff
}
#media only screen and (min-width: 48em) {
.dynamic-uber-class {
... only unique styles
}
}

less :extend() with media queries

I am trying to extend a simple class
.positionAbsolute {
position: absolute;
}
My issue here is that I can extend it like:
#something:extend(.positionAbsolute) {
something else
}
But from inside the media query itself, If i try from outside no rule is extended at all.
Is this the normal behaviour?, why is doing that?, In such case I will have to create like four equal classes to extend in each media query case, is there some workaround?
Thank you
I'm not sure I understand it right (it's always hard to guess w/o seeing an exact CSS output you need to achieve), but it looks like you need something like:
.positionAbsolute {
position: absolute;
}
#something:extend(.positionAbsolute) {
#media only screen and (min-width: 1024px) {
something: else;
}
}
The other way around is:
.positionAbsolute {
position: absolute;
}
#class-1,
#class-2 {
&:extend(.positionAbsolute);
}
#media only screen and (min-width: 1024px) {
#class-1 {
something: else;
}
#class-2 {
something-even: more else;
}
}
That way you will have to repeat selectors instead of media queries.
I was trying to do this, and was quite disappointed I couldn't put the extend within a media query. Fortunately I was able to use a mixin for what I wanted. This may work for some situations. I can't really tell what you're actually doing with your case.
.centerVertically()
{
content: '';
display: inline-block;
height: 100%;
vertical-align: middle;
margin-right: -0.25em;
border: 2px solid red;
.content
{
display: inline-block;
vertical-align: middle;
}
}
used in media query
#media screen and (min-width: #break_tablet)
{
/* doesn't work
&:before:extend(.centerVertically_wrapper){}
.content:extend(.centerVertically_child){}
*/
.centerVertically();
The best I came up with I turned into a GIST here. Basically, I created an externalized reference mixin for the query and imported all the possible contexts into it. LESS sees through the query when you are referencing a class to extend but it will export it.
Reference:
.narrow {
#media screen and (max-aspect-ratio: 1/1) {
#import "position";
#import "z";
}
}
Export:
#import (reference) "narrow";
.style-1:extend(.position .abs, .narrow .position .rel) {
}
.style-2:extend(.narrow .position .rel) {
}
.style-3:extend(.narrow .z .index-1) {
}

Combine extend and mixin in with same rules

Okey!
I have couple of extends in sass like
%heading
%paragraph
%gutter
and so on...
I want to reuse thouse in media queries, but that doesnt work. I know that.
Then i came up with the idea to have all my extends as mixins too. So when i want them in a media query i simply use mixin. for example
.my-widget {
#extend %gutter;
#media.... {
#include gutter-other;
}
}
and because i dont want to write all my rules again. How do i write my sass then?
I tried
%my-extend, #mixin my-extend {
...
}
but that didnt work.
Any ideas how to work with this?
No, you can't combine them that way. You'll have to write a mixin that is invoked by your extend class and anything inside of a media query.
#mixin my-extend {
background: yellow;
}
%my-extend {
#include my-extend;
}
.foo {
#extend %my-extend;
}
.bar {
#extend %my-extend;
}
.baz {
#media (min-width: 30em) {
#include my-extend;
}
}
Output:
.foo, .bar {
background: yellow;
}
#media (min-width: 30em) {
.baz {
background: yellow;
}
}

Media Queries - In between two widths

I'm trying to use CSS3 media queries to make a class that only appears when the width is greater than 400px and less than 900px. I know this is probably extremely simple and I am missing something obvious, but I can't figure it out. What I have come up with is the below code, appreciate any help.
#media (max-width:400px) and (min-width:900px) {
.class {
display: none;
}
}
You need to switch your values:
/* No less than 400px, no greater than 900px */
#media (min-width:400px) and (max-width:900px) {
.foo {
display:none;
}
}​
Demo: http://jsfiddle.net/xf6gA/ (using background color, so it's easier to confirm)
#Jonathan Sampson i think your solution is wrong if you use multiple #media.
You should use (min-width first):
#media screen and (min-width:400px) and (max-width:900px){
...
}
just wanted to leave my .scss example here, I think its kinda best practice, especially I think if you do customization its nice to set the width only once! It is not clever to apply it everywhere, you will increase the human factor exponentially.
Im looking forward for your feedback!
// Set your parameters
$widthSmall: 768px;
$widthMedium: 992px;
// Prepare your "function"
#mixin in-between {
#media (min-width:$widthSmall) and (max-width:$widthMedium) {
#content;
}
}
// Apply your "function"
main {
#include in-between {
//Do something between two media queries
padding-bottom: 20px;
}
}
.class {
display: none;
}
#media (min-width:400px) and (max-width:900px) {
.class {
display: block; /* just an example display property */
}
}

Resources