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?
Related
When using Sass I would do something global like this (which I got from CSS-tricks btw)
// Variables for MQ's
$mq-mobile-portrait : 320px !default;
$mq-mobile-landscape : 480px !default;
$mq-tablet-portrait : 768px !default;
$mq-tablet-landscape : 1024px !default;
$mq-desktop : 1382px !default;
Then I would create mixins for the media queries like this (I'll only include a few to give you an idea
// Mixins
// Both portrait and landscape
#mixin mobile-only {
#media (max-width : $mq-mobile-landscape) {
#content;
}
}
// Everything up to and including the portrait width of the phone
// Since it's the smallest query it doesn't need a min
#mixin mobile-portrait-only {
#media (max-width : $mq-mobile-portrait) {
#content;
}
}
So Sass has this #content which is great because it means that I don't have to declare the content within the mixin but can do an #include mixinName and it creates the parent wrapper for any CSS properties I need to put into it across different files. I discovered that this worked well for my work flow.
So here's an example of that in a partial .scss file:
section.footer {
height: 90px;
padding: 0 10px;
#include mobile-portrait-only {
padding-top: 10px;
background: $gum;
div.ftrLogo {
display: inline-block;
margin: 0;
height: 70px;
width: 45%;
div.smlLogo {
display: block;
background: url('../images/svg/small-logo2.svg');
width: 106px;
height: 49px;
margin: 0 auto;
padding: 0;
}
p.footer {
font-size: .375em;
color: $white;
text-align: center;
}
}
}
So as you can probably gather the #content allows you to just call an empty media query wrapper anywhere in your files (obviously you have to import all of your partials into one main file) but this is great.
Today I'm using LESS on a project and I like it a lot the problem is I can't seem to find an equivalent solution in LESS-land.
I was reading up on passing rulesets http://lesscss.org/features/#detached-rulesets-feature which looks like it's close to what I want but my brain is not understanding it today; I'm optimistic about tomorrow.
If anyone has tried anything like this or can immediately see the error in my ways; please provide your two cents. I really want to figure it out and thought to ask this gifted community of SO'ers.
Thank you in advance you're a baller!
// Variables for MQ's
#mq-mobile-portrait: 320px;
// Mixins
.mobile-portrait-only(#rules) {
#media (min-width: #mq-mobile-portrait) {
#rules();
}
}
Now you can use the following code:
div {
color: white;
.mobile-portrait-only({
color: white;
width: 100%;
max-width: 500px;
});
}
The above will compile into CSS code as follows:
div {
color: white;
}
#media (min-width: 320px) {
div {
color: white;
width: 100%;
max-width: 500px;
}
}
So detached rules are rules between {} assigned to a variable:
#detached: {};
Detached rules can be used as an argument for a mixin:
.mixin(#detached){}
You as call the above mixin with a detached rule as a parameter:
.mixin({color: red;});
or
#detached: {color: red;} // watch out for the last declaration wins rule for variables
.mixin(#detached);
Inside the mixin you should call the detached rules set to copy its properties and selectors (in fact you don't copy but insert them read for processing):
.mixin(#detached-rules) {
#detached-rules(); // parenthesis are required here
}
Finally for your example your code should look like that shown below:
#gum: url();
#white: white;
// Variables for MQ's
#mq-mobile-portrait: 320px;
// Mixins
.mobile-portrait-only(#rules) {
#media (min-width: #mq-mobile-portrait) {
#rules();
}
}
section.footer {
height: 90px;
padding: 0 10px;
.mobile-portrait-only( {
padding-top: 10px;
background: #gum;
div.ftrLogo {
display: inline-block;
margin: 0;
height: 70px;
width: 45%;
div.smlLogo {
display: block;
background: url('../images/svg/small-logo2.svg');
width: 106px;
height: 49px;
margin: 0 auto;
padding: 0;
}
p.footer {
font-size: .375em;
color: #white;
text-align: center;
}
}
});
}
I hadn't thought of doing it like Bass Jobsen suggested (although I've now seen that his approach is basically how the less docs do it), but I invented a mixin which I think is a bit more flexible. Though they are similar in result, I think the following solution allows for more customization and is easier to implement on the fly.
First I define the different sizes I want to use - to keep it simple, I'll just do two using a 'mobile first approach' (meaning if I don't include a media query, the rules will apply to all sizes and I should only include queries for sizes larger than mobile).
#tablet:~"(min-width:768px)";
#desktop:~"(min-width:1100px)";
Then the mixin:
.respond(#_size;#_rules){
#media #_size {
#_rules();
}
}
And Used Like the following:
.selector {
background:green;
.respond(#tablet,{
color:red;
background:blue;
});
}
And That Outputs:
.selector {
background:green;
}
#media (min-width:768px){
.selector{
color:red;
background:blue
}
}
With only two sizes to remember, it is easy enough just to do it the way Bass Jobsen suggested, but in practice, depending on how fine-grained I want my control to be, I may define up to 8 different media sizes (though I rarely use them all), and my approach above makes the process like calling one function rather than defining 8 different functions ( as I would do were I using the alternate approach ).
Hope this helps someone. It saves me a ton of time.
I like to use :extend() in Less like I can do it in Sass.
Example in SCSS: http://codepen.io/Grawl/pen/qEeQPG
Example in Less: http://codepen.io/Grawl/pen/qEeQpz (not worked)
Expected output:
.datalist-item {
display: block;
}
.datalist-item-term {
font-weight: normal;
}
.datalist-item-description {
font-weight: bold;
}
.datalist-float .datalist-item {
display: inline-block;
}
.datalist-float .datalist-item:not(:last-of-type) {
margin-right: 1em;
padding-right: 1em;
border-right: 1px solid;
}
The purpose is to not self-repeat, so if I rename one class in Sass I have not to rename others.
I know I can put root class in a variable and use it twice with it http://codepen.io/Grawl/pen/qEeQpz but it looks ugly :(
Your Sass (SCSS) example uses #extend-Only Selectors which is some special form of extending which does not exists in Less.
Firstly a "normal" extend:
SCSS:
.class {
p: 1;
}
.class2 {
#extend .class;
}
and Less:
.class {
p: 1;
}
.class2 {
&:extend(.class);
}
both compile into:
.class,
.class2 {
p: 1;
}
In Less .class2 { &:extend(.class); } can also be written as .class2:extend(.class1){}
Now consider the following SCSS code which uses #extend-Only Selectors:
%class {
p: 1;
}
.class2 {
#extend %class;
}
The preceding code compile into CSS code as follows:
.class2 {
p: 1; }
Sass documentation tells you:
#extend-Only Selectors
Sometimes you’ll write styles for a class that you only ever want to
#extend, and never want to use directly in your HTML. This is
especially true when writing a Sass library, where you may provide
styles for users to #extend if they need and ignore if they don’t.
If you use normal classes for this, you end up creating a lot of extra
CSS when the stylesheets are generated, and run the risk of colliding
with other classes that are being used in the HTML. That’s why Sass
supports “placeholder selectors” (for example, %foo).
Placeholder selectors look like class and id selectors, except the #
or . is replaced by %. They can be used anywhere a class or id could,
and on their own they prevent rulesets from being rendered to CSS.
In Less you will have two options to have code that does not generate output:
1) use a mixin, mixins do not generate output:
.class() {
p: 1;
}
.class2 {
.class();
}
outputs:
.class2 {
p: 1;
}
2) put your classes which should not output in a different file and import this file with the reference kewyword:
file1.less:
.class {
p: 1;
}
file2.less:
#import (reference) "file1";
.class2 {
&:extend(.class);
}
lessc file2.less will output now:
.class2 {
p: 1;
}
But i agree with #seven-phases-max in the comments in the first place. In your example there is no need to use extend. #seven-phases-max shows you some examples to solve this use case. Alternatively you can consider; changing selector order with parent reference, which should work in both Less and SASS:
.datalist-item {
display: block;
&-term {
font-weight: normal;
}
&-description {
font-weight: bold;
}
.datalist-float & {
display: inline-block;
&:not(:last-of-type) {
margin-right: 1em;
padding-right: 1em;
border-right: 1px solid;
}
}
}
Compile into:
.datalist-item {
display: block;
}
.datalist-item-term {
font-weight: normal;
}
.datalist-item-description {
font-weight: bold;
}
.datalist-float .datalist-item {
display: inline-block;
}
.datalist-float .datalist-item:not(:last-of-type) {
margin-right: 1em;
padding-right: 1em;
border-right: 1px solid;
}
Finally notice that you are using nesting of properties such as:
border: {
right: 1px solid;
};
which should compile into:
border-right {
1px solid;
}
Less does NOT support nesting of properties.
How can I inherit from a class which name is composed using the & character (e.g. &-rule), please?
Desired Output
.prefix-rule-extended,
.prefix-rule {
color: white;
}
.prefix-rule-extended {
background-color: black;
}
or
.prefix-rule {
color: white;
}
.prefix-rule-extended {
color: white;
background-color: black;
}
Non-working Approaches
.prefix {
&-rule {
color: white;
}
}
plus
.prefix-rule-extended:extend(.prefix-rule) {
background-color: black;
}
or
.prefix-rule-extended {
.prefix-rule();
background-color: black;
}
Ideal Approach
.prefix {
&-rule {
color: white;
}
&-rule-extended:extend(&-rule) {
background-color: black;
}
}
Note 1: I know :extend(&-rule) is currently not supported.
Note 2: .prefix-rule is not so simple, i.a. there are nested rules inside so the following will not work:
.prefix {
&-rule {
color: white;
&-extended {
background-color: black;
}
}
}
Thank you.
(Ok, so as always to not leave this one w/o an answer - a summary of comments above):
Currently it's impossible to extend that kind of things. For the moment extend can't match selector identifiers generated via "concatenation" so .prefix {&.rule { ... would be a valid extend target (as it's "two elements" -> "two identifiers") but .prefix {&-rule { ... won't (since it's "two elements" -> "one identifier").
So if you plan to use extend don't be keen on such kind of nesting, keep it more simple.
Here are three valid Less snippets (each having its pros and cons) to get the desired CSS output.
1:
.prefix-rule {
color: white;
&-extended:extend(.prefix-rule) {
background-color: black;
}
}
2:
.prefix-rule {
&, &-extended {
color: white;
}
&-extended {
background-color: black;
}
}
3:
.rule-base {
color: white;
}
.prefix-rule {
&:extend(.rule-base);
&-extended:extend(.rule-base) {
background-color: black;
}
}
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%);
}
}
}
How can I create this class with less?
.class {
display: none;
}
a:hover .class {
display: block;
}
Like this?
.class {
display: none;
a:hover & {
display: block;
}
}
.class {
display: none;
&:hover {
display: block;
}
}
I am assuming from your given CSS code that your HTML structure is like so:
<a>
<div class="class">Content</div>
</a>
You'll be happy to know that what you want to achieve is fairly easy using Less; here's the code shown below:
a {
&:hover {
.class {
//Apply styling here
}
}
}
I hope this helps.