LESS compiler magically adds unwanted classes to my selector - css

This is the important part of my LESS file:
input.ng-invalid {
color: #e74c3c;
border-color: #e74c3c;
}
It compiles into this:
input.ng-invalid .form-control {
color: #e74c3c;
border-color: #e74c3c;
-webkit-box-shadow: none;
-moz-box-shadow: none;
box-shadow: none;
}
http://plnkr.co/edit/118uS4RciQYVPa5KH6oU
The form-control class is from Bootstrap and wouldn't break the selector if LESS didn't insert a space (input.ng-invalid.form-control works just fine)
The problem is that the browser is looking for the children of input with the class form-control. Apparently, there are no childrens of input in my HTML.
Is there a setting in bootstrap's LESS files that binds the form-control class to every input?

I've taken a look at the zip package you provided and there your input.ng-invalid is defined as (selfmade.less:L97):
input.ng-invalid {
.form-control-validation(#brand-danger; #brand-danger);
}
which is expected to compile to what you actually get (i.e. appending nested classes defined within .form-control-validation). This is just what this mixin is supposed to do.
-
Is there a setting in bootstrap's LESS files that binds the form-control class to every input?
I can't see any (at least in Bootstrap 3.1.1), so I can only suggest the following trick:
.danger_ {
.form-control-validation
(#brand-danger, #brand-danger);
}
input.ng-invalid.form-control
:extend(.danger_ .form-control all) {}
which will compile to this css (assuming bs-3.1.1).
-
Alternatively there's .has-error class which you can extend the same way:
input.ng-invalid.form-control
:extend(.has-error .form-control all) {}
and get a bit more compact output but with slightly different colours (#state-danger-text instead of #brand-danger).

This is not really an answer, but an investigation of your problem which doesn't fit in the comments box. I did't go through your set of less files since I don't have a 7z uncompressor here, but maybe I can give you some ideas to help you fix the problem or hack it.
One way of obtaining a contextual relationship like this:
input.ng-invalid .form-control { ... }
Is having a block like this somewhere in your Less files:
input.ng-invalid {
...
.form-control { ... }
...
}
Now that association might happen through a mixin so you probably won't find that exact pattern above, but you might find want to discover where .form-control is declared (a mixin, perhaps).
Now if you want this:
input.ng-invalid.form-control { ...}
and you a block like the one I showed above, you can add a & before the .form-control selector so that instead of obtaining a contextual relationship from the nesting blocks, you add a class. The & represents the selectors from the parent block. It would be something like:
input.ng-invalid {
...
&.form-control { ... }
...
}
See if you discover where .form-control is defined and try it out.
(Be aware that if other parts of your code use this mixin or selector, they may not work as before - this was just an analysis of a possible solution using Less and not the Bootstrap framework; add a bootstrap tag to your question and you might attract some Bootstrap specialists who might have a better solution.)

Related

Applying tr:hover but only to a certain class

I have some CSS that colors a row on my table on hover.
tr:hover {
background: gray !important;
}
However, it also highlights the filter row on the table. So I did Inspect and find it has <tr class="MuiTableRow-root MuiTableRow-hover"...etc
So, my question is, how can I modify the above code so that it applies only to that class shown above?
Edit: First attempt at apply class.
.MuiTableRow-root MuiTableRow-hover {
tr:hover {
background: gray !important;
}
}
As pointed out in the comments, please take a look at the documentation for class selectors.
You are having trouble to combine the class with the element's tag.
In this case they are written together like this:
tr.MuiTableRow-hover:hover {
background: gray !important;
}
When the HTML tag has the class: Write the tag and . and then the class
When the HTML tag has some element inside with a certain class, separate them with a space
Do yourself a favor and search for CSS tutorials to teach you the basics. It's not very hard to learn if you can spare the time
A little bit advanced is trusting CSS Specificity and leaving out !important. If your selector is more specific (or your CSS was loaded later) your style will be applied even without use of !important.
tr.MuiTableRow-hover:hover {
background: gray;
}
The css rule should look like this:
tr.MuiTableRow-hover:hover {
background: gray !important;
}
Note that using !important is not best practice so better if you try to avoid it if possible

How to use CSS custom variables for properties

My stylesheets have large amounts of styles declared, often with a lot of repeated values. I read about variables in CSS to solve that problem.
I tried to use them, but it is not working:
element {
--main-bg-color: brown;
}
body {
background-color: var --main-bg-color;
}
What am I doing wrong?
You did everything right, just keep the variables in (put variable here)
element {
--main-bg-color: brown;
}
body {
background-color: var(--main-bg-color);
}
var() notation works like a method
var(<custom-property-name>)
might consider putting your variables in a :root selector...
:root {
--main-bg-color: brown;
}
/* The rest of the CSS file */
body {
background-color: var(--main-bg-color);
}
:root is similar to global scope, but the element itself (ie body { --myvar: ... }) or ancestor elements (ie html { --myvar: ... }) can also be used to define variables
Refer to MDN reference page. A brief, to use custom variables you need to place them inside :root selector:
:root {
--main-bg-color: brown
}
In order to use it in another selector yo use var():
body {
background-color: var(--main-bg-color)
}
For me, the problem was that #charset "UTF-8"; was not the very first characters in the css file, and this messed up the :root{--my-variable: large }.
You need to add var(--my-variable) when using the variables.
But that's not something you should use CSS custom properties (variables) for.
Bear in mind some browser can't understand CSS variables, most noticeably IE. So using any pre-processor instead will be better for compatibility, as they are compiled to regular CSS values. Either SASS, LESS, POSTCSS... whatever floats your boat.
CSS custom properties are much more powerful than pre-processor ones, as they can be changed at runtime with javascript and be used in all sorts of awesome ways, but when you're using them as regular variables, pre-processor variables are always better for compatibility.
If you want to declare them globally, I would recommend to use it in:
* { --var : #colorName; }.
This has actually helped me in Angular application.

SCSS variable class name

On my website, I'm constantly doing style="font-size: #ofpx;". However, I was wondering if there's a way to do it with scss so that, when I declare a class, it would also change the font size. For example:
<div class='col-lg-4 font-20'>whatever here</div>
and this would change my font-size to 20. If I did font-30, it would change my font-size to 30 and etc...
What I have so far:
.font-#{$fontsize} {
font-size: $fontsize;
}
This can't be done for arbitrary sizes. The nature of SCSS is that is needs to be flattened down to CSS before it gets applied to the HTML. What you are asking for, however, is essentially to create rules at run-time rather than compile-time.
In other words, SCSS makes it easier to write some of the repetitive parts of CSS, but it doesn't allow you to do anything new that wasn't already possible with plain old CSS.
What you're asking for is also a code smell. It smells like your markup isn't semantic enough. The purpose of a CSS class is to group objects with similar characteristics, but you're using them instead to describe the styles they impart. I would suggest stepping back and reconsidering what it is that you really want.
You obviously have details of certain elements that are context-dependent. For example, maybe you are applying these rules to buttons when you want to make them smaller or larger than usual. You need to identify the scenarios in which the buttons change. Maybe they are 20% smaller if they are in a modal dialog? Then write your normal .button rules, and also create rules for .modal .button which make it smaller.
If you're positive that you want to define font-size for each element within the HTML (and sometimes there are good reasons for doing so), just continue using inline styles. The only reason inline styling is frowned upon is because it combines model and view logic in a way that harms reusability; however, what you are requesting does so in exactly the same way. This is what inline styles were made for. Don't re-invent the wheel.
With all of that said, you can use sass loops to automatically generate classes for integers within a range. For example:
/* warning: this is generally a bad idea */
#for $i from 1 through 100 {
.font-#{$i} {
font-size: #{$i}px;
}
}
This is not a good idea. Pragmatically speaking it doesn't offer any advantages over just using inline styles and with large ranges your resulting file will be larger (which affects website load times).
Aside: There is a CSS philosophy (or fad, if you're feeling ungenerous) called Atomic CSS (or sometimes Functional CSS) which defies the classical advice given in this answer. I won't give an opinion on its effectiveness at producing clean, maintainable code, but it does typically require more tooling than SCSS alone if used with the degree of specificity requested in this question.
Just going to add, mixins are great, but if you want a util class (attach a class to an element, get that font-size applied to it, do a for-loop in SCSS like so..
#for $i from 1 through 4 {
$fontsize: 10px * $i;
.font-#{$i} {
font-size: $fontsize;
}
}
compiles to
.font-1 {
font-size: 10px;
}
.font-2 {
font-size: 20px;
}
.font-3 {
font-size: 30px;
}
.font-4 {
font-size: 40px;
}
If you want the class to match the # of pixels...
#for $i from 1 through 4 {
$base: 10;
$fontsize: $base * $i;
.font-#{$fontsize} {
font-size: $fontsize + 0px;
}
}
Which compiles to
.font-10 {
font-size: 10px;
}
.font-20 {
font-size: 20px;
}
.font-30 {
font-size: 30px;
}
.font-40 {
font-size: 40px;
}
Codepen example.
When using "words" instead of "numbers" for variables, and the word not being at the end of the classname. I could work something out using CSS Attribute selectors ("wildcard selector"). I can iterate over a map object, and use text values to build CSS selectors.
SASS
//map
$colors: (
primary: #121212,
success: #8bcea8
);
//loop
#each $color, $value in $colors {
//can't do this: div.first-class.is-style-#{$color}-component
//can do this:
div.first-class[class*="is-style-#{$color}-component"] {
background-color: $value;
}
}
HTML
<div class="first-class is-style-primary-component"></div>
This will generate a div.myComponent[class*="is-style-primary-component"] selector and so <div class="first-class is-style-primary-component"></div> (.first-class is not required, selector could be div[class*="is-style-#{$color}-component"] or even [class*="is-style-#{$color}-component"] only).
Yet, in some cases of CSS class naming, it could be limited due to the wildcard selector, which is "larger" than a specific class selector rule.
Of course, inline style tags are bad form. So yes, you should add some classes for font size, or just set font size on the elements you need to as you go. Up to you. If you want, you could use a mixin like so:
#mixin font-size($size) {
font-size: $size;
}
.some-div { #include font-size(10px); }
But that's probably overkill unless you get a group of rules that usually go together.
Just for those of you who might stumble across this question in a more recent time and are new to FrontEnd Development.
What Woodrow Barlow said about using inline-styles instead of rule specific classes isn't quite an up-to-date opinion. For instance, Bootstrap has some of those and Tachyons is entirely built upon them. Actually this practice is called Atomic CSS or Functional CSS.
It's better explained by John Polacek in his CSS Tricks article:
https://css-tricks.com/lets-define-exactly-atomic-css/
You can use mixins like this
#mixin font($fontsize) {
font-size: $fontsize;
}
.box {
#include font(10px);
}

overwrite css items depening on className

I'm having problems with my CSS markup in my code.
I'm building a control and my plan is to add a standard class to it so it has a fixed layout and add any userdefined css classes behind it, to personalise the control. but during my tests I noticed a problem which I can't resolve.
when I have an element like this
<div class="test1 test2"></div>
and underlaying code in another stylesheet file.
.test1
{
width: 200px;
height: 200px;
background-color: red;
}
.test2
{
background-color: yellow;
}
then it doesn't matter if I put test1 first or test2. the div will always be yellow only because test1 is written last on the css file.
if I replace test2 with test1 in the css file itself then the div will always be red.
how can I make the background-color overwrite incase its added a second time depending on the order its written in the className itself?
I also want to take notice I don't want to force users to use the !important tag. I already know about this and yes that works fine but I need it without. Any ideas on how to resolve this issues is welcome. I'm open for alternatives
You could make it so .test2 when combined with .test1 becomes yellow
.test1.test2{
background-color: yellow;
}
a better way tough is not to work like this at all. have a read of this article instead. It explains a technique for CSS called BEM (Block, Element, Modifier) which is pretty awesome. When trying to modify a existing style it will look like:
.test{
width: 200px;
height: 200px;
background-color: red;
}
.test--warning{
background-color: yellow;
}
and your div will look like <div class="test test--warning">
You can twiddle the precedence of the class's selectors like this:
.test2[class*=test2]
{
...
}
This should make class test2 override other classes that have only class name selectors.
(sorry, this part is not correct)
If you want to lower test1's precedence, you could do it like this:
[class*=test1]
{
...
}
(I haven't tested this, you might need to name it *[class*=test1] instead)
I been researching for a long time and posted here because I couldn't find a good answer. thx to the answers and responses here I was able to find an article over the problem I'm facing here CSS howto
What I'm trying to do is not possible because of the order css in generated. What I wanted is my css to work between browser default and external or internal stylesheets. I will look for an alternative solution to my project.

removing item from many css selectors

I have a vague memory, but can't find anything on it, about being able to use a keyword "with" or "like" to do something similar to the following.
using .class1{
#a1, #a4{color:#ffffff;}
#a2{color:#dddddd;}
#a3{color:#eeeeee;}
}
instead of having to write:
.class1 #a1, .class #a4{color:#ffffff;}
.class2 #a2{color:#dddddd;}
.class3 #a3{color:#eeeeee;}
The issue is that I'm including some html/css in a page and the css is screwing up the rest of the page. So, I'd like to modify the css so it only affect the small portion, rather than the whole page. I'm doing all this programmatically on a large number of pages, so it'd be much easier to just wrap all of the new css in something like "using .class1" rather than parsing through the css and add .class1 to the beginning of every selector.
Any ideas? thanks!!
There is no way to achieve what you want unless you use some CSS preprocessor like SASS. Here's how it would look when done using SASS:
.class1 {
#a1, #a4 {
color: #ffffff;
}
#a2 {
color: #dddddd;
}
#a3 {
color: #eeeeee;
}
}
Reference: little link.
Wrap the block of included HTML in its own ID like #overRideCSS
Then if you ever need to over-ride specific styles, you can preface your selector with that ID:
#overRideCSS <other selectors> {etc...}

Resources