LESS CSS - Not reinventing the wheel - css

By “wheel” I mean the nested selector path.
I’ve converted a somewhat large CSS file to LESS for the most part, nesting rules in DOM order. However, some of my styles are being overridden. Basically, all of the “plain” styles have been nested making their output CSS rules extremely specific (which I want). What’s not so specific are the rules where the parent elements have classes attached. Example:
Regular nested rules:
.grandparent {
some: style;
.parent {
other: style;
.child {
you: get;
.grandchild {
the: picture;
}
}
}
}
So, the issue I’m having is adding styles to the grandchild if the grandparent has a specific class attached. Something like:
.grandparent.visiting .grandchild {
visibility: hidden;
}
Is there a way to neatly add .visiting to the big hierarchy I’ve already built? Or do I have to redo the entire nesting order for all the child element selectors affected by .grandparent.visiting?
Not sure if this a noob thing. I just started with LESS a couple weekends ago. But I can’t seem to find any solutions using :not and the & selector (as superb as it is) doesn’t seem to help here either.

You can reference the current selector using the & symbol, then write selectors after it as it was in one line.
.grandparent {
some: style;
&.visiting {
.grandchild{
visibility: hidden;
}
}
}

Related

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.

CSS grouping :hover & :active

When I want to define css selector with :hover and :active I have to do:
#mainPage #content div.group:hover, #mainPage #content div.group:active {}
As one can see it contians repeated #mainPage #content div.group and can get messy. Is there a way to group it somehow like:
#mainPage #content div.group:hover:active {}
In pure CSS there is not much of a better way to handle both more succinctly without adding a class or ids.
You could consider a CSS pre-compiler (like LESS or SASS/SCSS).
In LESS or SCSS:
#mainPage #content div.group {
&:hover, &:active {
color: red;
}
}
I suggest add ID for the element has class group and write below code will reduce the effort:
#idname.group:hover, #idname.group:active{}
Is there a reason why you're using #mainPage #content before div.group?
Generally, it's not necessary to add that much 'specificity' to your selectors - it's better to instead, have unique classes. So make sure that the class .group is only used for elements that you want to have the same styles.
If you do that, you should be able to style those elements just using
.group { styles here}
You might run into an issue now where if you try to override any of the styles you set like #mainPage #content, those will be more specific and so in effect 'stronger' than styles where you don't use the full list of parents. If possible, change all your styles not to include the parent elements - this is also worthwhile in case you ever want to move an object to a different part of the html!
It's also, in general, advisable not to use id's (#name) to attach css styles - if possible, just use classes. Unless you're doing javascript, you shouldn't have much need for id's.
Obviously there exceptions to the above, and for all I know you may have a perfectly good reason for doing things the way you have - in which case SASS (as suggested in a few other answers) is a good solution for you.
If not useful for you, I hope at least this answer might be useful for someone who might come along later - I've noticed that a lot of people newer to css don't realize how specificity of selectors works and end up making their styles a lot more complicated than necessary as a result! :)
Old question, but this should be relevant for somebody who needs this.
Pseudo-class released by the end of 2020
You can use :is() pseudo-class like so :
#mainPage #content div.group:is(:hover, :active) {
}
Here is a little snippet to picture it :
a:is(:hover, :focus) {
color: red;
outline: #5bc8ea dotted 4px;
outline-offset: 4px;
font-weight: 600;
}
Hover/Focus me
More informations about :is() pseudo class here: https://developer.mozilla.org/en-US/docs/Web/CSS/:is and here: https://css-tricks.com/almanac/selectors/i/is/.
Works with most of the popular browsers (incompatible with IE, Opera and Safari < 14) https://caniuse.com/css-matches-pseudo.
It surely is more often used to select elements than pseudo-classes like :hover or :focus but it will do the trick as I can't see any other solution for now.
Why you use #mainPage #content? #content should be enough to find the div your looking for without the #mainPage.
Also id's are only allowed to be used once and not in multiple places like classes are. Id's are usually reserved for script assignments and not CSS. I would do
#content .group:hover{}
#content .group:active{}
if i understood correctly, you want a group of elements to act a certain way? manipulate the parent class then.
.parent-class:hover {
.child-class {
…desired styles go here
}
}

How do I make CSS styles dependant on its parent element

I was wondering if it is possible to define the styles of an element depending on the value of the body ID.
It is difficult to explain but something like this would be ideal:
HTML:
<body id="home">
CSS:
body#home {
a { /* code here */ }
p { /* code here */ }
}
body#profile {
a { /* different code here */ }
p { /* different code here */ }
}
I know I can do this:
body#home a { /* code here */ }
but that becomes very repetitive.
I will be looking forward to your responses,
Peter
You can do this if you use a CSS framework like SASS or LESS
Here's the documentation on how to do this with LESS. Hope this helps.
IDs are supposed to be unique, so #home { ... } is acceptable.
Then and child elements would be:
#home .myClass { ... }
This technique if often used to re-skin pages be simply changing the ID or class on a body.
Be aware that while nesting styles like this can be supported using CSS frameworks, it should be well thought-out to maintain modularity and clean inheritance in your CSS. You can end up doing more harm than good. In particular, watch out for something know as the inception rule, described here:
http://thesassway.com/beginner/the-inception-rule
The Inception Rule: don’t go more than four levels deep.
Any change you make to your markup will need to be reflected into your
Sass and vice versa. It also means that the styles are bounded for
life to the those elements and that HTML structure which completely
defeats the purpose of the "Cascade" part of "Cascading Style Sheets."
If you follow this path, you might as well go back to writing your CSS
inline in your HTML (please don't).
The best way to do what you are talking about is to have a base stylesheet the site.
They have either:
A <style> element in the header overriding anything you choose
or
Have a different stylesheet for each page

Hide with css all elements that doesn't contains {selector}

I have example (js-fiddle)
I want hide all tbody elements, that doesn't contains elements tr elements without class "day_label" and "hide"
In this exmaple i have stats for day, and i need to hide all day if there is no any record for day.
What you want is basically a CSS parent selector (tr.hide < tbody { display: none; }​), this doesn't exist yet. (soon!) However, this can be done quite easily with a library like jQuery:
$("tbody").each(function() {
if ($(this).children("tr:not(.hide):not(.day_label)").length) { //Not 0
$(this).addClass("show");
}
});​
CSS:
tbody { display: none; }
tbody.show { display: block; }​
Demo: http://jsfiddle.net/SO_AMK/RqBCY/
To effectively select a parent based on it's children - what you are asking - is not possible with CSS (at this particular frozen moment in time).
You have two three ;) options:
When generating your HTML (either with a server side language or in JS) generate your parents with classes that describe the state of the children. This way you can target the parent directly.
Use JavaScript to target your parent and then calculate whether or not it has the right kind of children. If it does, then apply a className that adds the styles you require.
For other situations you can also do as Abe Petrillo states - which is to inverse your logic and only enable when a particular selector is found. However I believe this wont work for what you are trying to do as it involves more complcated 'conditional logic' than can be implemented.
Not sure what you mean, but you could hide all rows, and then show the rows that are relevant:
tbody tr { display:none; }
tbody tr.day_label { display: block; }

CSS selector when :target empty

I need a css3 selector to target an element when the :target equals the id of the element (easy) or when the :target is empty (impossible?). It’s hard to explain, so let me give you a simple example.
div {
background: blue;
}
div:target, div:no-target {
background: red;
}
But of course the :no-target pseudo class doesn’t exist ;). Is there a way around this without using Javascript? Thanks in advance!
Sigh. I feel like I'm resurrecting a dead topic, but it needs a real answer.
It's possible to do this with CSS alone, just by using :last-child and a general sibling combinator, in the form of :target ~ :last-child:
.pages > .page:target ~ .page:last-child,
.pages > .page {
display: none;
}
/* :last-child works, but .page:last-child will not */
.pages > :last-child,
.pages > .page:target {
display: block;
}
The rules applies in the following steps:
hide all pages
show both targeted page and the last page
if a page is targeted, hide the last page (.page:target ~ .page:last-child)
(live example)
Edit: Apparently this is very similar to the accepted answer in an older, previously mentioned, related post.
There is a great answer for this over at default-target-with-css
It revolves around this trick that seems to have problems in iOS. It's been fixed in Safari, so maybe it'll be in iOS 5?
All I can think of is that you have some javascript that checks to see if the hash is empty. If so, it adds a class to the body tag called "noHash". Then, you can use the fact that there is the noHash class available in your CSS rules.
if (window.location.hash.length <= 1) {
document.body.className += " noHash";
}
Then, your CSS could be like this:
div {
background: blue;
}
div:target, body.noHash div {
background: red;
}
If there's any circumstance where a user might add a hash value after the fact, then you may have to watch for that to make sure the noHash class gets removed appropriately.
Note: you don't have to add the class name to the body tag. You can add it to any parent object that covers all the objects you wish to affect.
Why don't you use div:not(:target) or div:target:empty?

Resources