Special characters causing problems when compiling LESS - css

Has anyone had issues with LESS compiling CSS that utilizes plus signs [+] and/or greater than [>] symbols, whereas the inclusion of these causes compilation errors/fails? (we're using the standard lessc compiler). The LESS below is identical to what we're trying to compile - the first plus after banana.keynote is what sets the compiler error off:
.banana.keynote {
+ {
label:before {
border: 2px solid #CC6633 !important;
}
}
}
.banana.chunga {
+ {
label:before {
border: 2px solid #ffb5ff !important;
}
}
}
.banana.gordita {
+ {
label:before {
border: 2px solid #4067ea !important;
}
}
}
NOTE: admittedly, I'm using an online converter to go from CSS to LESS - could this be producing weird artifacts in code?
Thanks.

Combinators in Less must always be followed by an element identifier, i.e. you can't use + alone on its own. Rewrite your code to:
.banana.keynote {
+ label:before {
border: 2px solid #CC6633;
}
}
If you really need to get it "alone" for some reason you may hack it through selector interpolaton:
#plus: ~'+';
.banana.keynote {
#{plus} {
label:before {
border: 2px solid #CC6633;
}
}
}
---
P.S. Additionally note that the following code:
.banana.keynote + {
label:before {
border: 2px solid #CC6633;
}
}
while compiled w/o any errors, does not produce the proper CSS (invalid + is just silently omitted).

Related

How to set multiple properties in CSS?

I've created CSS for a LineEdit.
LineEdit.cpp
void MyLineEdit::initStyleSheet()
{
QString css = Css::instance().css( m_element );
setProperty( "style", "normal" );
setStyleSheet( css );
}
I have a separate .css file for style:
MyLineEdit.css
....
MyLineEdit[style="Normal"]:focus
{
border: 1px solid red;
}
MyLineEdit[style="Normal"]:disabled
{
border: 1px solid gray;
background: gray;
}
Now there is one weird requirement: MyLineEdit should have a method called setNoFrame, in this function we set one more property for it, and this property is valid for only state disabled.
This is what I did:
MyLineEdit::setNoFrame()
{
setProperty("noFrame","true");
initSyleSheet();
}
And this is my updated .css data
....
MyLineEdit[style="Normal"]:focus
{
border: 1px solid red;
}
MyLineEdit[style="Normal"]:disabled
{
border: 1px solid gray;
background: gray;
}
MyLineEdit[style="Normal", noFrame="true"]:disabled
{
border: none;
background: gray;
}
It doesn't work as I expected, the border is still there for state disabled and noFrame = true. Do I have mistake in combining properties for CSS above?
You're really, really close. Try
MyLineEdit[style="Normal"][noFrame="true"]:disabled
{
border: none;
background: gray;
}
From the CSS2 docs (which Qt StyleSheets supports):
Multiple attribute selectors can be used to refer to several attributes of an element, or even several times to the same attribute.
Here, the selector matches all SPAN elements whose "hello" attribute has exactly the value "Cleveland" and whose "goodbye" attribute has exactly the value "Columbus":
span[hello="Cleveland"][goodbye="Columbus"] { color: blue; }

What is the difference between ampersand and double ampersand in Less?

I am trying to write Less in the context of React.
The following code works:
.rt-tr-group .rt-tr:hover .rt-td {
color: #fff;
&:first-child { /* notice single ampersand */
border-left: 2px solid #007aff;
}
}
This code also works:
.rt-tr-group .rt-tr:hover .rt-td {
color: #fff;
}
.rt-tr-group .rt-tr:hover .rt-td:first-child {
border-left: 2px solid #007aff;
}
However, the following code does not work:
.rt-tr-group .rt-tr:hover .rt-td {
color: #fff;
&&:first-child { /* notice double ampersand */
border-left: 2px solid #007aff;
}
}
I have seen the double ampersand used elsewhere in the codebase, so && does something. Could someone please explain the difference to me?
The double ampersand you've seen might be & + & or & ~ &, not &&, as to the best of my knowledge the latter does nothing in Sass.
Using & + & will allow you to target an adjacent sibling of the same selector, for example this SCSS:
.btn {
...
& + & {
margin-left: 15px;
background: firebrick;
}
}
...will compile to this CSS:
.btn {
...
}
.btn + .btn {
margin-left: 15px;
background: firebrick;
}
Read more about the double ampersand here at Team Treehouse.
&& is redundant to the basic logical operator AND in nearly every popular programming language, while the single & is used specifically in SASS for connecting CSS selectors.
Connecting, or to be more precise in the use case of SASS: Concatenating selectors is very different from combining two conditionals in a logical sense.
Read further:
https://www.sitepoint.com/sass-basics-operators/ and https://javascript.info/logical-operators
It could be to increase specificity: .thing.thing is higher than just .thing

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.

LESS CSS - Change variable value for theme colors depending on body class

Getting to grips with LESS here but one thing is still a little unclear.
Lets say I have multiple color themes for my website, controlled by a class on the body tag. From this I can redefine the various colors for each element within each theme. Easy enough but fairly time consuming if I have a lot of elements to change... and a lot of themes. Every time I add a new theme I need to write out all the selectors again, with different color values.
I am basing my working so far on another post I found:
LESS.css variable depending on class
... However it still seems overly complicated for what I want to do in that I still have to write out all the selectors and include the mixin before dropping in the same CSS with the color variable.
I have created a CODEPEN HERE
I'd appreciate it if anyone had time to take a little look and advise me how I could approach this differently or how I could streamline this process.
Many thanks to anyone who helps out :)
Assuming you remain with wanting to theme it within one style sheet (and not multiple sheets as cimmanon noted in the comments), and assuming you are using LESS 1.3.2+, then the following code works to reduce the amount of duplication by setting up a loop through the classes that need theme changes.
Note that this does not work on Codepen (it is throwing an error uncaught throw #, perhaps because they are running an earlier version of LESS), but you can see it compiling correctly by putting the code into LESS's compiler.
LESS (based off your Codepen code with an added theme for demo)
//////////////////////////////////////////////////////
// CONSTANTS
#lightColour: #fff;
#darkColour: #000;
#lightBg: #fff;
#darkBg: #000;
#numberOfThemes: 3; //controls theme loop
//////////////////////////////////////////////////////
// MIXINS
//Theme Definitions by parametric mixin numbers (1), (2), etc.
.themeDefs(1) {
#lightColour: #f00;
#darkColour: #fff;
#lightBg: #f00;
#darkBg: #fff;
}
.themeDefs(2) {
//inverse of 1
#lightColour: #fff;
#darkColour: #f00;
#lightBg: #fff;
#darkBg: #f00;
}
.themeDefs(3) {
#lightColour: #cfc;
#darkColour: #363;
#lightBg: #cfc;
#darkBg: #363;
}
.curvy {
-moz-border-radius: 5px;
-webkit-border-radius: 5px;
border-radius: 5px;
}
//////////////////////////////////////////////////////
// GENERAL STYLING
* {padding: 0;margin: 0;}
html {text-align: center;}
h2 {padding: 20px 0;}
.box {
.curvy;
color: #lightColour;
background: #darkBg;
display:inline-block; width:10%; padding:20px 5%; margin:0 1% 20px 1%;
}
//////////////////////////////////////////////////////
// THEME BUILDING
.buildThemes(#index) when (#index < #numberOfThemes + 1) {
.theme-#{index} {
.themeDefs(#index);
color: #lightColour;
background: #darkBg;
.box {
color: #darkColour;
background: #lightBg;
}
}
.buildThemes(#index + 1);
}
//stop loop
.buildThemes(#index) {}
//start theme building loop
.buildThemes(1);
CSS Output (only showing the looped theme css for brevity)
.theme-1 {
color: #ff0000;
background: #ffffff;
}
.theme-1 .box {
color: #ffffff;
background: #ff0000;
}
.theme-2 {
color: #ffffff;
background: #ff0000;
}
.theme-2 .box {
color: #ff0000;
background: #ffffff;
}
.theme-3 {
color: #ccffcc;
background: #336633;
}
.theme-3 .box {
color: #336633;
background: #ccffcc;
}

SASS CSS: Target Parent Class from Child

I am using SASS and found an inconvenience. This is an example of what I am trying to do:
.message-error {
background-color: red;
p& {
background-color: yellow
}
}
Expected CSS:
.message-error {
background-color: red;
}
p.message-error {
background-color: yellow ;
}
The idea: all elements with .message-error will be red, except if it is p.message-error. This is not real-life situation, just to show an example.
SASS is not able to compile this, I even tried string concatenation. Is there some plugin that will do exactly the same?
NOTE:
I know I can put another CSS definition like:
p.message-error{....}
...under, but I would like to avoid that and use one place for all .message-error definitions.
Thanks.
As of Sass 3.4, this is now supported. The syntax looks like this:
.message-error {
background-color: red;
#at-root p#{&} {
background-color: yellow
}
}
Note the #at-root directive and the interpolation syntax on the ampersand. Failure to include the #at-root directive will result in a selector like .message-error p.message-error rather than p.message-error.
You can assign the current selector to a variable and then use it at any depth:
.Parent {
$p: &;
&-Child {
#{$p}:focus & {
border: 1px solid red;
}
#{$p}--disabled & {
background-color: grey;
}
}
}
Natalie Weizenbaum (the lead designer and developer of Sass) says it will never be supported:
Currently, & is syntactically the same as an element selector, so it
can't appear alongside one. I think this helps clarify where it can be
used; for example, foo&bar would never be a valid selector (or would
perhaps be equivalent to foo& bar or foo &bar). I don't think this use
case is strong enough to warrant changing that.
Source: #282 – Element.parent selector
To my knowledge, there is no possible workaround.
The best thing to do would be probably this (assuming you have a little more in your .message-error class than just background color.
.message-error {
background-color: red;
}
p.message-error {
#extend .message-error;
background-color: yellow
}
This approach doesn't offer that close grouping, but you can just keep them close to each other.
I had the same problem so I made a mixin for that.
#mixin tag($tag) {
$ampersand: & + '';
$selectors: simple-selectors(str-replace($ampersand, ' ', ''));
$main-selector: nth($selectors, -1);
$previous-selectors: str-replace($ampersand, $main-selector, '');
#at-root {
#{$previous-selectors}#{$tag}#{$main-selector} {
#content;
}
}
}
To make it work, you will need a string replacement function as well (from Hugo Giraudel):
#function str-replace($string, $search, $replace: '') {
$index: str-index($string, $search);
#if $index {
#return str-slice($string, 1, $index - 1) + $replace + str-replace(str-slice($string, $index + str-length($search)), $search, $replace);
}
#return $string;
}
How it works:
SCSS
.foo {
color: blue;
#include tag(p) {
color: red;
}
}
Output
.foo {
color: blue;
}
p.foo {
color: red;
}
Use case
This method works with nested selectors but not whit compound ones.
#Zeljko It is no possible to do what you want via SASS.
See Nex3 comment: https://github.com/nex3/sass/issues/286#issuecomment-7496412
The key is the space before the '&':
.message-error {
background-color: red;
p & {
background-color: yellow
}
}
instead of:
.message-error {
background-color: red;
p& {
background-color: yellow
}
}
I think if you want to keep them grouped by parent selector, you might need to add a common parent:
body {
& .message-error {background-color: red;}
& p.message-error {background-color: yellow}
}
Of course, body could be replaced with some other common parent, such as #Content or another div name that will contain all the error messages.
UPDATE (Another Idea)
If you leverage #for and lists then it seems like this should work (what I don't know for sure is if the list will allow the . (period).
#for $i from 1 to 3 {
nth(. p. ul., #{$i})message-error {
background-color: nth(red yellow cyan, #{$i}));
}
}
Should compile to something like:
.message-error {
background-color: red;}
p.message-error {
background-color: yellow;}
ul.message-error {
background-color: cyan;}
I made a mixin that solves this problem.
Github: https://github.com/imkremen/sass-parent-append
Example: https://codepen.io/imkremen/pen/RMVBvq
Usage (scss):
.ancestor {
display: inline-flex;
.grandparent {
padding: 32px;
background-color: lightgreen;
.parent {
padding: 32px;
background-color: blue;
.elem {
padding: 16px;
background-color: white;
#include parent-append(":focus", 3) {
box-shadow: inset 0 0 0 8px aqua;
}
#include parent-append(":hover") {
background-color: fuchsia;
}
#include parent-append("p", 0, true) {
background-color: green;
}
}
}
}
}
Result (css):
.ancestor {
display: inline-flex;
}
.ancestor .grandparent {
padding: 32px;
background-color: lightgreen;
}
.ancestor .grandparent .parent {
padding: 32px;
background-color: blue;
}
.ancestor .grandparent .parent .elem {
padding: 16px;
background-color: white;
}
.ancestor:focus .grandparent .parent .elem {
box-shadow: inset 0 0 0 8px aqua;
}
.ancestor .grandparent .parent:hover .elem {
background-color: fuchsia;
}
.ancestor .grandparent .parent p.elem {
background-color: green;
}
I created package/mixin with a similar solution :) (Maybe it will help U)
https://github.com/Darex1991/BEM-parent-selector
so writing:
.calendar-container--theme-second-2 {
.calendar-reservation {
#include BEM-parent-selector('&__checkout-wrapper:not(&--modifier):before') {
content: 'abc';
}
}
}
This mixin will add selector only for the last parent:
.calendar-container--theme-second-2 .calendar-reservation__checkout-wrapper:not(.calendar-reservation--modifier):before {
content: 'abc';
}
More info on the repo.
I have ran into this before as well. Bootstrap 3 handles this using a parent selector hack. I've tweaked it slightly for my own purposes...
#mixin message-error() {
$class: '.message-error';
#{$class} {
background-color: red;
}
p#{$class} {
background-color: yellow;
}
}
#include message-error();
wheresrhys uses a similar approach above, but with some sass errors. The code above allows you to manage it as one block and collapse it in your editor. Nesting the variable also makes it local so you can reuse $class for all instances where you need to apply this hack. See below for a working sample...
http://sassmeister.com/gist/318dce458a9eb3991b13
I use an #mixin function like this, when i need change some element in middle
of a sass big tree.
The first parameters is the parent element, the target, and the second the class that should have.
SASS
#mixin parentClass($parentTarget, $aditionalCLass) {
#at-root #{selector-replace(&, $parentTarget, $parentTarget + $aditionalCLass)} {
#content;
}
}
Sample,
like i need to improve font size in a strong tag, when .txt-target had .txt-strong too
HTML
<section class="sample">
<h1 class="txt-target txt-bold">Sample<strong>Bold</strong>Text</h1>
</section>
SASS
section{
.txt-target{
strong{
#include parentClass('.txt-target','.txt-bold'){
font-weight:bold;
font-size:30px;
}
}
}
}
Font:
https://sass-lang.com/documentation/at-rules/at-root
Here you can see a function called #mixin unify-parent($child) that looks like this
This cheat might work
{
$and: .message-error;
#{$and} {
background-color: red;
}
p#{$and} {
background-color: yellow
}
}
You may even be able to use $& as your variable name but I'm not 100% sure it won't throw an error.
And SASS has inbuilt scoping, which removes having to worry about the value of $and leaking out to the rest of your stylesheet
Variables are only available within the level of nested selectors
where they’re defined. If they’re defined outside of any nested
selectors, they’re available everywhere.
In the Current Release: Selective Steve (3.4.14) this is now possible, just need to update a little bit your code:
.message-error {
background-color: red;
p &{
background-color: yellow
}
}
this only works if you are one level nested, for instance it does not work if you have something like this:
.messages{
.message-error {
background-color: red;
p &{
background-color: yellow
}
}
}

Resources