I just finished with the Sass guide.
The guide explains mixins:
..A mixin lets you make groups of CSS declarations that you want to
reuse throughout your site. You can even pass in values to make your
mixin more flexible.
and extend:
.. This is one of the most useful features of Sass. Using #extend lets
you share a set of CSS properties from one selector to another ..
It looks like 'extend' may be implemented in 'mixin' (it seems 'mixin' is extend of 'extend' :-) ).
// #extend
.message {
border: 1px solid #ccc;
padding: 10px;
color: #333;
}
.success {
#extend .message;
border-color: green;
}
.error {
#extend .message;
border-color: red;
}
.warning {
#extend .message;
border-color: yellow;
}
// #mixin
#mixin message($color) {
border: 1px solid #ccc;
padding: 10px;
color: #333;
border-color: $color;
}
.success { #include message(green); }
.error { #include message(red); }
.warning { #include message(yellow); }
and even more because mixins have params.
But on the other hand the processed CSS is not exactly the same. But it will be same style effect on the DOM.
/* extend processed */
.message, .success, .error, .warning {
border: 1px solid #ccc;
padding: 10px;
color: #333; }
.success {
border-color: green; }
.error {
border-color: red; }
.warning {
border-color: yellow; }
/* mixin processed */
.success {
border: 1px solid #ccc;
padding: 10px;
color: #333;
border-color: green; }
.error {
border: 1px solid #ccc;
padding: 10px;
color: #333;
border-color: red; }
.warning {
border: 1px solid #ccc;
padding: 10px;
color: #333;
border-color: yellow; }
My question is how do these features differ?
When should I use one over the other?
From http://blog.nakulrajput.com/mixins-extends-and-placeholders/:
#mixin
Here is how mixins work. Definition and usage:
#mixin awesome {
width: 100%;
height: 100%;
}
body {
#include awesome;
}
p {
#include awesome;
}
The snippets above produce the following CSS:
body {
width: 100%;
height: 100%;
}
p {
width: 100%;
height: 100%;
}
To make things a little bit more interesting, we could make our mixin accept parameters. Even better, we are able to define default values if the mixin is called without arguments.
#mixin awesome($w: 100%, $h: 100%) {
width: $w;
height: $h;
}
body {
#include awesome(960px);
}
p {
#include awesome;
}
The result will be similar, but the width of the body is different.
body {
width: 960px;
height: 100%;
}
p {
width: 100%;
height: 100%;
}
If you use mixins, the styles in them are duplicated for each selector.
Mixins are very helpful if you need to change or calculate something in the final output, for example if you need to apply border-radius to several elements.
However, in some other cases there is a lot of duplicative code, which could be avoided if you use #extend.
**#extend**
.awesome {
width: 100%;
height: 100%;
}
body {
#extend .awesome;
}
p {
#extend .awesome;
}
It's similar, isn't it. In Sass it looks almost identical, but the CSS the result is:
.awesome, body, p {
width: 100%;
height: 100%;
}
Shorter than the version using a mixin. You can't pass parameters during the extending, but that's not the idea actually.
#extend should be used in those places where you want to share properties between the elements.
Well, Mixin is like function that can do some work and output processed result while extend is like pre-defined cop-paste code
In programming terms:
#include is like calling a function with or without parameters
#extend is like Inheritance
Function means, every time we call the function, the body of the function gets duplicated as we might pass dynamic information in the form of parameters. so you would get a Copy of the body.
Inheritance means, there is no duplication and we get a Reference instead of copy. so who ever extends that reference would get the same body.
Related
In sass we can do some kind of class name concatenation with this:
//Sass
.button{
&-1{ background-color: red; }
&-2{ background-color: blue; }
}
//Result
.button-1{ background-color: red; }
.button-2{ background-color: blue; }
Can I somehow do concatenation on top of a prefix selector like this so that I don't have to use a base class or #extend:
*[class^="button-"]{
width: 20px;
height: 20px;
border: 1px solid black;
&-1{
background-color: red;
}
&-2{
background-color: blue;
}
}
I could achieve the same results with defining a base class and then adding specific styles after that like this:
.base-button{
width: 20px;
height: 20px;
border: 1px solid black;
}
.button{
&-1{ background-color: red; }
&-2{ background-color: blue; }
}
But I would then have to go and add that base class to all elements.
Another approach is using the #extend directive like this:
.button{
width: 20px;
height: 20px;
border: 1px solid black;
}
.button-{
&1{
#extend .button;
background-color: red;
}
&2{
#extend .button;
background-color-blue;
}
}
I guess my question is if there is a particular reason why sass doesn't support class concatenation when the parent selector is a class prefix selector. Isn't it safe to make the assumption that the prefix used in the selector can be used for concatenation when that parent selector has nested classes with &? Or am I just doing something wrong with my sass?
Thanks!
SASS does a objective, literal concatenation when you use &, so:
*[class^="button-"]{
width: 20px;
height: 20px;
border: 1px solid black;
&-1{
background-color: red;
}
&-2{
background-color: blue;
}
}
will generate:
*[class^="button-"]{
width: 20px;
height: 20px;
border: 1px solid black;
}
*[class^="button-"]-1{
background-color: red;
}
*[class^="button-"]-2{
background-color: blue;
}
which has invalid syntax, because a selector such as *[class^="button-"]-1 is not valid CSS.
You can create a mixin to get what you want. But frankly, these solutions should be last last resort, like selector by an attribute other than class name or id. Even that, just KISS to keep readability and maintainability.
Question: With SCSS, can we specify two different .main selectors? Say I want another one with margin-top: 50px while also inheriting all other conditions
I have inherited some SCSS from someone else. I have the following SCSS structure:
.main {
margin-top: 74px;
ul.tabs {
position: relative;
li.tab {
/*The rest of nested structure*/
}
}
}
It continues to nest (unfortunately) for many layers.
I have some other options (splitting the structure in two) which is a simple fix. Just curious if there's something better.
Thanks!
You should use a mixin:
#mixin sharedStyles{
//shared nested styles go here
}
.parentA{
margin-top:74px;
#include sharedStyles;
}
.parentB{
margin-top: 50px;
#include sharedStyles;
}
Here is a gist that illustrates the concept:
https://gist.github.com/Ryan-Haines/ba10888d0828d394851d3da6063f70bb
I recommend using sassmeister for rapid prototyping:
https://www.sassmeister.com
If you use a placeholder, as long as one selector is not inside a media query, it should group them together in the CSS. Ie
%mainStyles {
border: 1px solid black;
}
.main1 {
margin-top: 75px;
#extend %mainStyles;
}
.main2 {
margin-top: 50px;
#extend %mainStyles;
}
Should generate
.main1, .main2 {
border: 1px solid black;
}
.main1 {
margin-top: 75px;
}
.main2 {
margin-top: 50px;
}
I've set of styles which I want to use in multiple places in my CSS.
Here is my function:
#function form-element-dimension{
height: 34px;
padding: 3px 10px;
line-height: 18px;
border: solid 1px #e2e7eb;
}
I will use this function anywhere in my .scss page like below:
.dataTables_length{
select{
form-element-dimension();
}
}
---
---
.contact-form-style{
input{
form-element-dimension();
}
}
How to do this in COMPASS SASS framework?
Although it's really not the best way to do what you're doing, this is how you'd achieve it with sass;
#mixin form-element-dimension {
height: 34px;
padding: 3px 10px;
line-height: 18px;
border: solid 1px #e2e7eb;
}
.dataTables_length {
select {
#include form-element-dimension();
}
}
.contact-form-style {
input {
#include form-element-dimension();
}
}
I'm new to LESS and I'm just experimenting with it, using version 1.5. I discovered the useful extend command, but I was wondering if that could be applied to parametric mixins as well as static ones. Apparently, this doesn't seem possible, based on my experiments:
This works
.some-mixin {
}
.child {
&:extend(.some-mixin);
}
This doesn't work and throws an "unexpected token" error:
.some-mixin(#color, #bgcolor) {
color: #color;
background-color: #bgcolor;
}
.child1 {
&:extend(.some-mixin(red, blue));
border: 1px solid blue;
}
.child2 {
&:extend(.some-mixin(red, blue));
border: 1px solid green;
}
.child3 {
&:extend(.some-mixin(red, blue));
border: 1px solid red;
}
Is this a current limitation of LESS, or am I using it incorrectly? Thanks in advance for the answers.
Edit - Added expected output, as per request
What I would expect makes more sense when there are more children extending the parametric mixin:
.child1,
.child2,
.child3 {
color: red;
background-color: blue;
}
.child1 {
border: 1px solid blue;
}
.child2 {
border: 1px solid green;
}
.child3 {
border: 1px solid red;
}
I'm not sure what you are trying to achieve (that is, I am not sure what you expect the :extend() code to actually do if it were extending the parameteric mixin). If your desire is to define the colors of .child, then using it as a straight mixin works:
LESS
.some-mixin(#color, #bgcolor) {
color: #color;
background-color: #bgcolor;
}
.child {
.some-mixin(red, blue);
}
CSS Output
.child {
color: #ff0000;
background-color: #0000ff;
}
This also makes .child itself a mixin for the red and blue color combination, which I think would have been a net result of the extension working if it had worked. That is, I would expect your second set of code to have produced something like this (theoretically; this does not actually work nor is it actually produced in LESS):
.some-mixin(#color, #bgcolor),
.child(#color: red, #bgcolor: blue) {
color: #color;
background-color: #bgcolor;
}
But these two are nearly equivalent as mixins (one has the added parameters):
/* theoretical mixin if extension worked */
.child(#color: red, #bgcolor: blue) {
color: #color;
background-color: #bgcolor;
}
/* code from straight use of .some-mixin in .child */
.child {
color: #ff0000;
background-color: #0000ff;
}
So that either of the above used like so will get the result of mixing in the child values to the new selector:
LESS
.test {
.child; /* or using .child(); */
}
CSS Output
.test {
color: #ff0000;
background-color: #0000ff;
}
No, currently this is not supported. But it's planned to be implemented in future versions.
Hello I am wondering is it possible to do something like this in less. I have this css:
.parent{display: block; color: red; border: yellow 1px solid;}
.parent a, .parent a.special-link{color: blue; border-color: green;}
I would write it in less like this:
.parent{
display: block;
color: red;
border: yellow 1px solid;
a, a.special-link{
color: blue; border-color: green;
}
}
And rules are ok but what if in further developing I have to add something to :hover but only for it eg. padding: 20px; What is the best way to do this? My first thought is that if there is some kind of workaround/hack/selector that allows to inherit all properties of parent.
I doubt I clearly understand your exact needs (":hover" of what? "only" for what "it"?)
But in general it usually goes like this:
.parent {
display: block;
color: red;
border: yellow 1px solid;
a {
// <a> properties:
// ...
&, &.special-link {
// <a> and <a.special-link> properties:
// ...
color: blue;
border-color: green;
}
&.special-link {
// <a.special-link> properties:
// ...
}
&:hover {
// <a:hover> properties:
// ...
}
/// etc. etc. etc.
}
}