I am using lessphp (latest from git)
Is it possible to call a mixin from another mixin in the same "namespace"?
Here is a short sample of code which produces no output (but should give a border to h1)
#test {
.mix() {
border: 1px solid #000000;
}
.mix2() {
.mix();
}
}
h1 {
#test > .mix2();
}
I got it to work by adding this:
#test {
.mix() {
border: 1px solid #000000;
}
.mix2() {
#test .mix();
}
}
h1 {
#test > .mix2();
}
Try:
#test {
...
.mix2() {
.mix;
}
}
h1 {
#test > .mix2;
}
Related
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;
}
}
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'm using LESS CSS and I have the following situation. Can you suggest me if there is a way to further optimize LESS code?
As you can see, there are many objects sharing properties between them but each one has also its own specific customization.
Thank you
footer a
{
font-weight:bold;
&#acme,
&#email_footer,
&#browser_ok,
&#browser_old
{
display:inline-block;
position:relative;
white-space:nowrap;
background:url('footer_items.png') no-repeat;
text-align:left;
text-indent:-9999px;
border:none;
}
&#acme
{
width:130px;
height:25px;
top:1px;
background-position:-90px 0;
&:hover
{
background-position:-90px -25px;
}
&:active
{
top:0px;
}
}
&#email_footer,
&#browser_ok,
&#browser_old
{
width:38px;
height:31px;
top:-3px;
}
&#email_footer
{
background-position:-230px 0;
&:hover
{
background-position:-230px -31px;
}
&:active
{
top:-2px;
}
}
&#browser_ok,
&#browser_old
{
background-position:0 -2px;
&:active
{
top:-2px;
}
}
&#browser_ok
{
background-position:0 -2px;
&:hover
{
background-position:0 -35px;
}
}
&#browser_old
{
background-position:-45px -2px;
&:hover
{
background-position:-45px -35px;
}
}
}
Looks like you could still combine some things together. Specifically some of your :active code and some of the background-position info. In order to keep the newly combined :active after :hover, I moved the definition containing it below the extra definitions, which should not matter for your code. In all it reduced it by 7 lines of code.
footer a
{
font-weight:bold;
&#acme,
&#email_footer,
&#browser_ok,
&#browser_old
{
display:inline-block;
position:relative;
white-space:nowrap;
background:url('footer_items.png') no-repeat;
text-align:left;
text-indent:-9999px;
border:none;
}
&#acme
{
width:130px;
height:25px;
top:1px;
background-position:-90px 0;
&:hover
{
background-position:-90px -25px;
}
&:active
{
top:0px;
}
}
&#email_footer
{
background-position:-230px 0;
&:hover
{
background-position:-230px -31px;
}
}
&#browser_ok,
&#browser_old
{
background-position:0 -2px;
}
&#browser_ok
{
&:hover
{
background-position:0 -35px;
}
}
&#browser_old
{
background-position:-45px -2px;
&:hover
{
background-position:-45px -35px;
}
}
&#email_footer,
&#browser_ok,
&#browser_old
{
width:38px;
height:31px;
top:-3px;
&:active
{
top:-2px;
}
}
}
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%);
}
}
}
This is the mixin I wrote (.scss format), but I'm getting this error:
Invalid CSS after "($x) ": expected expression (e.g. 1px, bold), was "{"
#mixin x_cards_wide($x) {
.card {
&:nth-child(-n + $x) { margin-top: 0; }
&:nth-child($x * n) { margin-right: 0; }
}
}
Check it out on CodePen
You can accomplish this using interpolations:
#mixin x_cards_wide($x) {
.card {
&:nth-child(-n+#{$x}) { margin-top: 0; }
&:nth-child(#{$x}n) { margin-right: 0; }
}
}