Nested pseudoclasses in Less css - css

I am trying to use LESS CSS to write my CSS but i got a problem with nested pseudoclasses
I
.class1 {
&:nth-of-type(2n) {
.class2{
}
}
}
the output is:
.class1.class2:nth-of-type(2n) {}
but I want to have this:
.class1:nth-of-type(2n) .class2{}
Any ideas?

Not an issue. You probably had a version of LESS CSS that did not produce the correct code. Try the online less converter and see that it works fine. Here is what I get:
(in)
.class1 {
&:nth-of-type(2n) {
.class2{
x:1;
}
}
}
(out)
.class1:nth-of-type(2n) .class2 {
x: 1;
}

Related

SCSS and direct nesting

I'm stuck on this one. I know I have an ability to reach all the way outside of the nested operators to add a prefix class like:
.myEl {
html.no-touch & {
}
}
and that will output:
html.no-touch .myEl {}
but I'm wondering if there is a way to escape by only one level, rather than all of them. Given this sort of input:
.myEl {
.myEl3 {
.myEl2 {} /* direct parent operator goes here? */
}
}
I would expect this sort of output:
.myEl1 .myEl2 .myEl3 {}
Is this possible?
Unfortunately, this is not possible in SASS. You'd probably have to do something like this if you don't want to nest further (which I'm sure you already knew).
.myEl1 {
.myEl3 {
/* Base styles here */
}
.myEl2 .myEl3 {
/* Specific styles here */
}
}

sass, custom selectors based on parent

I have the following mixins to make easy work with BEM syntax, sass 3.3.2 code:
=b($name)
.#{$name}
#content
=e($name)
&__#{$name}
#content
=m($name)
&--#{$name}
#content
+b(menu)
+e(item)
color: grey
+e(item)
+m(alert)
color: red
This gives me the desired result:
.menu__item {color: grey;}
.menu__item--alert {color: red;}
So this works pretty nice for element level modifiers, however when i want to have block level modifiers the problem begins:
+b(menu)
+m(theme-1)
+e(item)
color: blue
css output:
.menu--theme-1__item {color: blue;}
when the thing i really want is this:
.menu--theme-1 .menu__item {color: blue;}
So i need a way to check what the context of an element is, when the context is a block there is no problem but when is a modifier the syntax fails. I tried inside e mixin to take the parent selector as string, so when e parent is b it will not have the -- syntax, in the other way when his parent is m it will have the -- syntax, with that i could decide what syntax use for both context.
I didn't find a way to take the parent selector as a string and i think is not possible, is there a way to make this works?
Update
I found a not very straightforward solution with it works fine, it uses a context argument in the element mixin:
=e($name, $context:null)
#if $context
&
+b($context)
&__#{$name}
#content
#else
&__#{$name}
#content
Now i can call the mixin as follows:
+b(menu)
+m(theme-1)
+e(item, nav)
color: blue
getting:
.menu--theme-1 .menu__item {color: blue;}
Answering a 2 year old question - long shot :) But hopefully could help someone else as well.
So a more robust way would be to improve your Element mixin to check if the parent selector has a modifier.
So you would need 2 functions:
one to check if a selector contains a modifier
one to get the block name from that selector
#function _bem-selector-has-modifier($selector) {
$selector: _bem-selector-to-string($selector);
#if str-index($selector, $bem-modifier-separator) or str-index($selector, ':') {
#return true;
} #else {
#return false;
}
}
#function _bem-get-block-name($selector) {
$selector: _bem-selector-to-string($selector);
$modifier-separator: '--';
$modifier-start: str-index($selector, $modifier-separator) - 1;
#return str-slice($selector, 0, $modifier-start);
}
And then you just need to apply the check in your element mixin
$bem-element-separator: '__';
#mixin element($element) {
$selector: &;
#if _bem-selector-has-modifier($selector) {
$block: _bem-get-block-name($selector);
#at-root {
#{$selector} {
.#{$block + '__' + $element} {
#content;
}
}
}
} #else {
#at-root {
#{$selector +'__' + $element} {
#content;
}
}
}
}
So calling element('item') inside a modifier('with-modifier') should render a .block--with-modifier .block__item selector in your compiled CSS and you won't have to manually pass the context.
The code posted is SCSS, but the idea should be the same with SASS.

Is possible to make an important property value from CSS selector a non important one?

Is possible to make an important property value from CSS selector a non important one?
For example: Bootstrap 3 defines .hide class as:
.hide { display: none !important; }
Is possible to remove the important value without modifying the BS3 source code?
Thinking at somethingl iike
.hide { display: none !remove-important; }
Note that I want to keep the same value! I don't want to set block !important to .hide class because that would not be correct...
I already added a new class .hide-non-important and used it where it was needed:
.hide-not-important { display: none; }
...but the question is: is there any alternative to this?
You don't need to edit the original source code. Just create a stylesheet and place it after the Bootstrap stylesheets and add this to it:
.hide { display: block !important; }
Now, having said this, I would be very careful about doing this. You don't know how many elements across your site have applied this class, and you will almost certainly get unanticipated results.
There is obviously a reason that this class has been applied, I would suggest either:
don't do this
add some other class to the element and add styles to that. Adjust your markup (or use js to apply the class if need be) to something like:
<div class="hide custom-hide-reset"></div>
Then add this style to the stylesheet you've created:
.custom-hide-reset { display: none; }
You can overwrite this with:
body .hide { display: none !important; }
.someclass.hide { display: none !important; }
those two examples have higher priority
The stylesheet objecs are accessible from javascript
var sheets = document.styleSheets
Once you have the stylesheet array, you can iterate over the rules
var rules = sheets[i].cssRules || sheets[i].rules // browser dependency
Each rule has a style property, which is mutable in the usual way.
rule.style[cssPropName] = value;
There is a method on the sheet to delete a rule by index, either deleteRule or removeRule, depending on the browser.
Bottom line, you can find the rule and either edit it or delete and re-add it in a modified form.
Reference: http://www.javascriptkit.com/dhtmltutors/externalcss3.shtml#.Ujsin4ZmjAs
Since the question can be splitted in
how can I remove !important from a rule applied to my page but
without changing its value and
without editing the original CSS file
For pure spirit of adventure only, I think it would be possible in the following way:
load the CSS with jQuery;
perform a replacement of its content, by searching .hide { display: none !important; } and replacing it with .hide { display: none; };
apply the new in-memory altered CSS to the page.
Taking for good the solution posted in this answer, it could be modified with something (totally untested, just to get the idea) like:
$.get(myStylesLocation, function(css)
{
var alteredCss = css.replace(".hide { display: none !important; }",".hide { display: none; }");
$('<style type="text/css"></style>')
.html(alteredCss)
.appendTo("head");
});
You can override the current !important value by another one like
.col{ color:red !important; }
.col{ color:green; } // wont work
.col{ color:blue !important; } // will work and set color blue instead of red
DEMO.
Update :
This question is not about JavaScript but as an alternative you can accomplish the task using these technique, remove the rule using JavaScript and then add a new rule again.
function getCSSRule(ruleName, deleteFlag) {
ruleName=ruleName.toLowerCase();
if (document.styleSheets) {
for (var i=0; i<document.styleSheets.length; i++) {
var styleSheet=document.styleSheets[i];
var ii=0;
var cssRule=false;
do {
if (styleSheet.cssRules) {
cssRule = styleSheet.cssRules[ii];
} else {
cssRule = styleSheet.rules[ii];
}
if (cssRule) {
if (cssRule.selectorText.toLowerCase()==ruleName) {
if (deleteFlag=='delete') {
if (styleSheet.cssRules) {
styleSheet.deleteRule(ii);
} else {
styleSheet.removeRule(ii);
}
return true;
} else {
return cssRule;
}
}
}
ii++;
} while (cssRule)
}
}
return false;
}
function killCSSRule(ruleName) {
return getCSSRule(ruleName,'delete');
}
function addCSSRule(ruleName, v) {
if (document.styleSheets) {
if (!getCSSRule(ruleName)) {
if (document.styleSheets[0].addRule) {
document.styleSheets[0].addRule(ruleName, v,0);
} else {
document.styleSheets[0].insertRule(ruleName+'{'+v+'}', 0);
}
}
}
return getCSSRule(ruleName);
}
// Check the rule before deleting
console.log(getCSSRule('.col')); // .col { color:red !important; }
// At first remove the current rule
killCSSRule('.col');
// Now assign nre rule
addCSSRule('.col', 'color: red');
// Check the rule after deleting
console.log(getCSSRule('.col')); // .col { color:red; }
DEMO. ( Source : Totally Pwn CSS with Javascript )

Defining Variable Variables using LESS CSS

Say I have three separate color schemes that are used on various pages in a site. Each color has a a light, medium and dark tint defined, and the color scheme is defined by a class in the body. Assume that the "red" color scheme is the default. Like this:
Color Definitions:
#red-lt: #121;
#red-md: #232;
#red-dk: #343;
#green-lt: #454;
#green-md: #565;
#green-dk: #676;
#blue-lt: #787;
#blue-md: #898;
#blue-dk: #909;
Basic Default Style Example
body { background-color: #red-dk;
#container { background-color: #red-md;
p { color: #red-dk; }
}
}
Different Color Scheme Style Example
body.green { background-color: #green-dk;
#container { background-color: #green-md;
p { color: #green-dk; }
}
}
I'd like to use variables so that I don't have to re-write all of the color variations for each scheme, so that I can just write something like this:
body.[color-var] { background-color: #[color-var]-dk;
#container { background-color: #[color-var]-md;
p { color: #[color-var]-dk; }
}
}
…but I can't quite wrap my head around how to accomplish that. Help…?
Use interpolation and escaping, parentheses in the selector and parametric mixins to get the desired effect:
Dynamic variables by interpolation: In a string, "#{variable}" is replaced with the value of the variable. They can also be nested: Given #{#{var}-foo} and #var: bar;, the result is "barfoo".
The resulting value is quoted. To remove these quotes, prefix ~.
Dynamic selectors by Selector interpolation: body.#{var} turns into body.bar.
Example:
#red-md: #232;
#red-dk: #343;
.setColor(#color) {
body.#{color} { background-color: ~"#{#{color}-dk}";
#container { background-color: ~"#{#{color}-md}";
p { color: ~"#{#{color}-md}"; }
}
}
}
.setColor(~"red"); // Escape to prevent "red" turning "#FF0000"
//.setColor(~"blue"); etc..
Turns into:
body.red {
background-color: #334433;
}
body.red #container {
background-color: #223322;
}
body.red #container p {
color: #223322;
}
Note: When the answer was originally written, selector interpolation did not exist. See the previous revision for the solution if you're working with an old LESS compiler (before LESS 1.3.1a). Support for the old method will be dropped in LESS 1.4.0.
If those values really follow a predictable format like that, seems like a perfect case for a parametric mixin:
Less:
#red: #232;
#green: #565;
#blue: #898;
.theme (#color) {
background-color: #color - #111;
#container {
background-color: #color;
p { color: #color + #111; }
}
}
body.red {
.theme(#red);
}
Compiled CSS:
body.red{background-color:#112211;}
body.red #container{background-color:#223322;}
body.red #container p{color:#334433;}
I know this question is pretty old, but for those that come to this post my answer maybe can help
I`m not really sure for what you want to use this, but one of my suggestion is based on #ScottS answer. On my real world, I need to create a web app, where it would show several brands and each brand have their own text color, background and so on... so I started to chase a way to accomplish this in LESS, what I could easily do on SASS and the result is below:
LESS
// Code from Seven Phase Max
// ............................................................
// .for
.for(#i, #n) {.-each(#i)}
.for(#n) when (isnumber(#n)) {.for(1, #n)}
.for(#i, #n) when not (#i = #n) {
.for((#i + (#n - #i) / abs(#n - #i)), #n);
}
// ............................................................
// .for-each
.for(#array) when (default()) {.for-impl_(length(#array))}
.for-impl_(#i) when (#i > 1) {.for-impl_((#i - 1))}
.for-impl_(#i) {.-each(extract(#array, #i))}
// Brands
#dodge : "dodge";
#ford : "ford";
#chev : "chev";
// Colors
#dodge-color : "#fff";
#ford-color : "#000";
#chev-color : "#ff0";
// Setting variables and escaping than
#brands: ~"dodge" ~"ford" ~"chev";
// Define our variable
.define(#var) {
#brand-color: '#{var}-color';
}
// Starting the mixin
.color() {
// Generating the loop to each brand
.for(#brands); .-each(#name) {
// After loop happens, it checks what brand is being called
.define(#name);
// When the brand is found, match the selector and color
.brand-#{name} & {
color: ##brand-color;
}
}
}
.carColor {
.color();
}
Te result will be:
CSS
.brand-dodge .carColor {
color: "#fff";
}
.brand-ford .carColor {
color: "#000";
}
.brand-chev .carColor {
color: "#ff0";
}
This is very tricky and I had to use several elements to get what I needed, first used a set of mixins provided by Seven Phase Max and you can find it here and than, the #ScottS answer was the piece that was missing fro my puzzle... hope this helps you and others that need to create a set of Variables to be part of another variable and create a more dynamic less file.
You can copy my entire code and test at http://lesstester.com/
Try this
#red-lt: #121;
#red-md: #232;
#red-dk: #343;
#green-lt: #454;
#green-md: #565;
#green-dk: #676;
#blue-lt: #787;
#blue-md: #898;
#blue-dk: #909;
#color: 'red-lt';
div{
background: ##color;
border: 1px solid lighten(##color,20%);
}
To my knowledge, variable variable names are not supported in LESS. You could however restructure your declarations in a more semantic manner:
/* declare palette */
#red-lt: #121;
#red-md: #232;
#red-dk: #343;
#green-lt: #454;
#green-md: #565;
#green-dk: #676;
#blue-lt: #787;
#blue-md: #898;
#blue-dk: #909;
/* declare variables based on palette colors */
#lt: #red-lt;
#md: #red-md;
#dk: #red-dk;
/* ...and only use them for main declarations */
body { background-color: #dk;
#container { background-color: #md;
p { color: #dk; }
}
}
This should let you switch between palettes quite painlessly by avoiding explicit color references.

Declare a global CSS property ? Is this possible?

I have a very wierd question, I dont know wether if its possible in css or not
Suppose I have say 3 different css classes as shown below, as you can see I have a common property of all these classes, I want to declare this color somewhere else and pass a reference to it here, so if next time I want to change the color I can simply change at one place rather than changing in all the 5 classes.
I know that you can use body{}, or a wrapper for this but that would affect the colors of the entire site right ? Is there a way to do this ?
Is this even possible ?
.abc {
color:red;
}
.abc2 {
color:red;
}
.abc3 {
color:red;
}
.abc4 {
color:red;
}
.abc5 {
color:red;
}
The bad news: you can't do it in CSS.
The good news: you can write in a meta-CSS language like LESS, which then processes a LESS file to pure CSS. This is called a "mixin".
In LESS:
#errorColor: red;
.error-color {
color: #errorColor;
}
#error-1 {
.error-color;
}
.all-errors {
.error-color;
}
More info: http://lesscss.org/#-mixins
if you want to declare all of them at a time, you can use:
.abc, .abc2, .abc3, .abc4, .abc5 {
color:red;
}
Or you can declare an additional class & add to all the .abc, .abc2.... & make its color:red;.
This can not be done with CSS, but that is still a very popular thing to do by using a CSS preprocessor such as LESS, SASS, SCSS, or Stylus.
A preprocessor will let you define a variable (say $red = #F00). It will replace the variable in your CSS document with the variable value for you, allowing you to write very DRY and module CSS.
This functionality is referred to as "CSS variables", which is part of the future spec, but not yet implemented on any browsers.
For now, the best way to do this in pure CSS is to declare an additional class for the desired "global", and then add that class to all relevant items.
.abc_global { color: red; }
.abc1 { /* additional styling */ }
.abc2 { /* additional styling */ }
<div class="abc1 abc_global"></div>
<div class="abc2 abc_global"></div>
With LESS
You are able to define that red color once:
.myRedColor {
color:red;
}
Now you can call that red on any CSS styles. Even NESTED styles! It's a wicked tool!
.abc1 {
.myRedColor;
}
.abc2 {
.myRedColor;
}
.abc3 {
.myRedColor;
}
.abc4 {
.myRedColor;
}
NESTED EXAMPLE:
.abc {
.itsEasyAsOneTwoThree{
.myRedColor;
}
}
Now all of our "itsEasyAsOneTwoThree" classes that are properly nested inside of an "abc" class will be assigned the red style. No more remembering those long #867530 color codes :) How cool is that?!
You can also use PostCSS with the plugin postcss-preset-env and support custom properties/variables, then use the :root selector to add global css variables.
:root {
--color-gray: #333333;
--color-white: #ffffff;
--color-black: #000000;
}

Resources