SCSS How to create style on the fly - css

I often use styles like next ones:
...
v-slot-padding-top4 {
padding-top: 4px;
}
v-slot-padding-top16 {
padding-top: 8px;
}
...
I can created many styles in cycle, but this way gives me many created styles that I'll never use.
Is there any way in scss to created styles on the fly? Or prepared something like function and call it from html attribute like class?

SCSS (Sass) is a preprocessor scripting language. It will be converted to CSS. You cannot dynamically create styles on the fly (runtime).
But you can use Sass features like #for. To create all your classes in range you need.
your.scss:
#for $i from 1 through 16 {
.v-slot-padding-top#{$i} {
padding-top: #{$i}px
}
}
Result in CSS:
.v-slot-padding-top1 {
padding-top: 1px;
}
.v-slot-padding-top2 {
padding-top: 2px;
}
.v-slot-padding-top3 {
padding-top: 3px;
}
.v-slot-padding-top4 {
padding-top: 4px;
}
/* etc */

Related

How do I create a scoped class without #include?

I managed to create a scoped CSS class like this:
.container {
#import "./baa";
/* other props ... */
}
but since #import is getting depreciated, what are my options to make a scoped CSS class now?
If you want to keep your CSS separated from any "framework" setup, the best way is probably to use the mixins system. It's definitely not the best way, but it's what come the closest as what you want, without going with CSS modules or else.
You can define your mixins in some file and import them where you need.
Exemple:
#mixin reset-list {
margin: 0;
padding: 0;
list-style: none;
}
#mixin horizontal-list {
#include reset-list;
li {
display: inline-block;
margin: {
left: -2px;
right: 2em;
}
}
}
nav ul {
#include horizontal-list;
}

What is right BEM approach to global class inheritance?

I recently started using BEM methodology and I'm confused about class inheritance, or rather - when we talk about BEM - some use cases of modifiers.
Let's look at this example, I have a simple element with few children
.b-content { width: 100%; }
.b-content__image { display: block; }
.b-content__date { font-size: 14px; }
.b-content__title { font-size: 30px; }
.b-content__text { font-size: 16px; }
Now I want to reuse my .b-content block with slightly different styles, so I use modifier .m-compact and now I'm not sure what approach is the right one (in BEM).
Whether I should append modifier class to all elements (which I find more valid according to documentation):
.b-content.m-compact { width: 50%; }
.b-content__image.m-compact { display: none; }
.b-content__date.m-compact { font-size: 12px; }
.b-content__title.m-compact { font-size: 24px; }
.b-content__text.m-compact { font-size: 14px; }
or should I append modifier only to the parent element:
.b-content.m-compact { width: 50%; }
.b-content.m-compact .b-content__image { display: none; }
.b-content.m-compact .b-content__date { font-size: 12px; }
.b-content.m-compact .b-content__title { font-size: 24px; }
.b-content.m-compact .b-content__text { font-size: 14px; }
I find this second method more logical, you know, since I'm writing cascading styles and in real world if I want to write e-mail to 10 people, I would write one and just add more recipients, but on the other hand I realize BEM is practically non-cascading approach.
So what should I use and why?
As you point out in the last lines of your question, when doing BEM you should avoid cascading so, as a corollary to this, you don't have to repeat the modifier where it isn't needed.
For your Modifier I'd write something like this:
.b-content--m-compact {
width: 50%;
}
In your example the Block and the Modifier set only the width, so this is a limited use case. In general it comes handy to use some kind of CSS preprocess to ease the code writing, e.g. in SASS:
.my-block
width: 100%
color: red
&--modifier
#extend .my-block
border: 1px solid red
which will results in:
.my-block, .my-block--modifier {
width: 100%;
color: red;
}
.my-block--modifier {
border: 1px solid red;
}
Modifier in BEM looks like this: .block_modName_modValue
You can add additional class - but it's not BEM. And also modifiers have a name and value.
Block in BEM set namespace
So you set default styles for blocks and all unique(that can be changed) place in css with modifiers. This way your styles don't messed up.
To do this you need:
Place common styles in block styles(.portfolio)
Place unique style(with modifiers) like this.(portfolio_theme_list)
In css you don't need to separate this(preprocessor will be needed).
.portfolio {
/* common styles */
&_theme_list {
/* modifiers style */
}
}
In BEM project-stub(template engine) it would look like this:
If you add modifier to block. Then compile(bemjson) to html.
{
block : 'portfolio',
mods : { theme : 'list' },
}
You will see this code
<div class="portfolio portfolio_theme_list">
</div>
You write elements correctly and understand that they need to be separated(without inheritence).
So now you need just define styles for your block with modifier(portfolio_theme_list).
You have 2 options:
1) If you have 2 different blocks - you need separate common and
unique styles. Unique styles place in styles with modified blocks.
2) If you have only 1 different block & you already have styles on
this blocks. Then you can override and don't separate common
styles(but it can cause pain if you add another modifier/instance)

Name clash between Less mixin and CSS selector

I have this simplified Less script
.placeholder(#color: #333333) {
&::-webkit-input-placeholder { color: #color; }
}
input {
.placeholder();
}
.placeholder {
margin-top: 20px;
}
The output when I run this through my local compiler or winless online less compiler is
input {
margin-top: 20px;
}
input::-webkit-input-placeholder {
color: #333333;
}
.placeholder {
margin-top: 20px;
}
Insted of the desired output
input::-webkit-input-placeholder {
color: #333333;
}
.placeholder {
margin-top: 20px;
}
Is this a bug or am I missing something here?
By the result it looks to me like I can't have CSS-selectors with the same name as mixins with default values.
I'm running into this problem when compiling Bootstrap with my site specific code. In this particular case I can work around it, but as the project grows and I include other projects I can't imaging I have to keep track of any mixins with default values?
Edit: I see now that I should have read the manual and pretty much seen on the first page of the docs that everything can be treated as a mixin.
In Less, everything is technically a mixin irrespective of whether we write it with parantheses (as in with parameters) or without parantheses (as in like a CSS class selector). The only difference between the two is that when the parantheses are present, the properties present within it are not output unless called from within a selector block.
Quoting the Less Website:
It is legal to define multiple mixins with the same name and number of parameters. Less will use properties of all that can apply.
In this case, since the other mixin has a default value for its only parameter, both the properties can apply when called without any parameter and hence there is no way to avoid it from happening.
Workaround Solution: One possible solution to work-around this problem is to enclose all such conflicting rules within a parent selector (like body).
.placeholder(#color: #333333) {
&::-webkit-input-placeholder { color: #color; }
}
input {
.placeholder();
}
body{
.placeholder{
margin-top: 20px;
}
}
Compiled CSS:
input::-webkit-input-placeholder {
color: #333333;
}
body .placeholder {
margin-top: 20px;
}
Option 2: Extracted from the solution posted by seven-phases-max in the Less GitHub Issue thread.
For the particular use-case one of possible workarounds is to isolate conflicting classes in unnamed scope so they won't interfere with external names:
.placeholder(#color: #333333) {
&::-webkit-input-placeholder { color: #color; }
}
input {
.placeholder();
}
& { // unnamed namespace
.placeholder {
background: #ffffff;
}
} // ~ end of unnamed namespace
Note: The above is a straight copy/paste from the GitHub thread without any modifications so as to not tamper with the information.
#mixin placeholder(#color: #333333) {
&::-webkit-input-placeholder { color: #color; }
}
input {
#include placeholder();
}
.placeholder {
margin-top: 20px;
}
that should work.
So if i understood right, you just want to add 20px on top of the placeholder ? Add padding-top to input instead.
input {
padding-top: 20px;
}

How can I simplify this SASS statement?

How can I simplify this SASS so that I only write .question-sector-answer the once? I need to apply different styles to the .question-sector-answer if the parent div has a class of both .question-row and .question-review. This currently seems unwieldy and I'm sure could be simplified and made more elegant:
.question-row {
border-bottom: 1px solid #ddd;
&.question-review {
.question-sector-answer {
padding-top: 30px;
}
}
.question-sector-answer {
padding: 15px;
}
}
I don't see how you can simplify it. You need to use 2 different styles for .question-sector-answer under different parents. Since it's impossible in css to access parent selector, you have no choice but do what you did (well, in SASS you kind of can - see below). Although my personal preference to always put more generic selectors on top and more specific ones to the bottom like so:
.question-row {
border-bottom: 1px solid #ddd;
.question-sector-answer {
padding: 15px;
}
&.question-review {
.question-sector-answer {
padding-top: 30px;
}
}
}
So in SASS you can access parent selector with & using it in certain way, but I don't think you can recreate your styles with it, the best I could come up with was this but it looks uglier than your original way of doing it, but you're welcome to play with it:
.question-row {
border-bottom: 1px solid #ddd;
}
.question-sector-answer
{
.question-row & {
padding-top: 15px;
}
.question-row.question-review &
{
padding: 30px;
}
}
You can read more about accessing parent selectors with & here
.question-row {
border-bottom: 1px solid #ddd;
}
.question-sector-answer {
padding: 15px;
.question-review & {
padding-top: 30px;
}
}
De-nesting here does two things: (1) creates terser, more flexible CSS and (2) allows the parent & selector. To compensate for the decrease in OOP, we slightly indent to imply subjugation. But in SASS you want to avoid the temptation to nest when not totally necessary, because nesting for OOP's sake tends to create more problems than it solves.

LESSCSS - use calculation and return value

H i,
Hoping you can help.
Is there a way for LESS to return just a value - feel like I'm missing something very obvious
Say I have:
#unit:em;
#basevalue:1;
Can I use something to give me a shorthand return for -
.someClass { padding: ~'#{basevalue}#{unit}'; }
Like say:
.returnUnit() { ~'#{basevalue}#{unit}'; }
.someClass { padding: returnUnit(); }
because what I'm ultimately hoping for is:
.returnUnit(#val) { #basevalue*#val#{unit}; }
.someClass { padding:returnUnit(0.5); }
Using a mixing I have to define the style property, however the value of this return function would be used for many different css properties.
Hope I made sense and I am just lacking deeper rtfm.
Many Thanks if you can.
Update as #Chococrocs pointer to the docs, thanks.
.average(#x, #y) {
#average: ((#x + #y) / 2);
}
div {
.average(16px, 50px); // "call" the mixin
padding: #average; // use its "return" value
}
Looks like what I need ? - just seeing if I can always tag on the unit variable to it....
Update: That gets part way ...
.unitRelative(#val) {
#value : #basevalue*#val;
#relative: ~'#{value}#{unit}';
}
/* usage */
.someClass {
.unitRelative(2);
padding: #relative;
}
But not when
.someClass {
.unitRelative(2);
padding:#relative;
.unitRelative(3);
margin:#relative;
}
Is there another way ?
LESS has no way as of yet to create a true "function," so we cope with it.
First
You can just use the unit function, like so:
LESS
.someClass { padding: unit(#basevalue, #unit); }
.someOtherClass { padding: unit(#basevalue*0.5, #unit); }
CSS
.someClass {
padding: 1em;
}
.someOtherClass {
padding: 0.5em;
}
Second
The mixins as functions is okay in some situations, but as you discovered, has the limitation of only setting the value once on the first call (and that is assuming a variable of the same name does not exist in that scope already).
LESS (first works right, second doesn't)
.returnUnit(#val:1) {
#return: unit(#basevalue*#val, #unit);
}
.someThirdClass {
.returnUnit(0.4);
padding: #return;
}
.someOoopsClass {
.returnUnit(0.4);
padding: #return;
.returnUnit(0.3);
margin: #return;
}
CSS Output
.someThirdClass {
padding: 0.4em;
}
.someOoopsClass {
padding: 0.4em;
margin: 0.4em; /* Ooops! Not 0.3em! */
}
Third
Limitation of the Second idea can be avoided by a second wrapping, as it isolates the scope for each variable returned by .returnUnit(), like so:
LESS
.someAccurateClass {
& {
.returnUnit(0.4);
padding: #return;
}
& {
.returnUnit(0.3);
margin: #return;
}
}
CSS Output
.someAccurateClass {
padding: 0.4em;
margin: 0.3em; /* Yes! */
}
Fourth
It may be better to merge ideas from the First and Third by adding some global variables and doing this:
LESS
#unit:em;
#basevalue:1;
#val: 1;
#setUnit: unit(#basevalue*#val, #unit);
.someAwesomeClass {
& {
#val: .2;
padding: #setUnit;
}
& {
#val: .1;
margin: #setUnit;
}
}
CSS Output
.someAwesomeClass {
padding: 0.2em;
margin: 0.1em;
}
So here we are using the unit function still as the First idea, but have assigned it to the variable #setUnit, so each time the variable is called, it runs the function. We still isolate our property blocks using the & {} syntax like in the Third solution, but now we just set the #val to what we want and call the #setUnit where we want.
There is a hack that is mentioned here by fabienevain using a global js function. Seems to be good option if you want a function with actual return value.
#fn: ~`fn = function(a) { return a; }`;
#arg: 8px;
p {
font-size: ~`fn("#{arg}")`;
}
I think you look for this, Mixin as a function
http://lesscss.org/features/#mixins-as-functions-feature
Reading your question, I think is what you're wishing, ;D
// mixin
.parseInt(#string) {
#parseInt: unit(#string, );
}
Usage:
.selector {
.parseInt(100px);
width: #parseInt + 10; // px will automatically be appended
}
Result:
.selector {
width: 110px;
}
one of the simplest work around would be to pass the property and the value.
mixin.less
.lighter(#property, #color) {
#{property}: multiply(white, fade(#color, 10%));
}
use.less
.my-class{
.lighter(background-color, #FF0000);
}
Results:
.my-class{
background-color: #fbe8eb;
}

Resources