Precedence of "concatenated classes" vs "separated classes" in CSS selectors [duplicate] - css

This question already has answers here:
Specificity of inherited CSS properties
(4 answers)
Closed 3 months ago.
Can someone please point me to the CSS precedence rules regarding "concatenated classes" vs "separated classes"?
Also, what are the correct terms for "concatenated classes" vs "separated classes" (I suspect that's why I can't find the documentation I'm looking for.)
For example, in the CSS below, .row .second (with a space) appears to take precedence over .row.second (no space), even though they both match 2 class attributes.
.row {
width: 150px;
background-color: lightgray;
margin: 15px;
}
section {
margin-left: 15px;
}
.row .second {
color: purple;
}
.row.second {
color: orange;
}
When applied to the HTML below, the CSS above produces this result:
Why is "Stuff 2b" in purple instead of orange? (In other words, why does .row .second take precedence over .row.second in this case?)
<div id='outerBox'>
<div class="row">
<div class="title">
Row 1 Title
</div>
<section>
Stuff 1a
</section>
<section class='second'>
Stuff 1b
</section>
<section>
Stuff 1c
</section>
</div>
<div class="row second">
<div class="title">
Row 2 Title
</div>
<section>
Stuff 2a
</section>
<section class='second'>
Stuff 2b
</section>
<section>
Stuff 2c
</section>
</div>
<div class="row">
<div class="title">
Row 3 Title
</div>
<section>
Stuff 3a
</section>
<section class='second'>
Stuff 3b
</section>
<section>
Stuff 3c
</section>
</div>
</div>
(I'm applying the CSS above to the HTML below in JSFiddle in Chrome on MacOS.)

separated classes is using for Childs in css.
Example :
.row .red # Means red Childs in Row
{
color:red;
}
<tr class="row">
<td class="red">
<p>Hey!</p> ### Color of this P will be red.
</td>
</tr>
The color of the classnamed as "red" elements in ".row" will be red.
But concatenated classes using for like "with".
Lem me show a example;
.row.red # Means class="row red"
{
color:red;
}
<tr class="row">
<td class="red">
<p>Hey!</p> # Color of this P will not be red.
</td>
</tr>
<tr class="row red">
<td class="">
<p>Hey!</p> # But this one will be red.
</td>
</tr>

While most commonly used, classes have nothing to do with Object Orientation. This means that there is no OO mechanism to 'concatenate/separate' anything. It's pure a syntax for creating different kinds of CSS selectors. I always consider CSS definitions as an eleborate list of if-statements.
without space, .row.second: all .row elements that are also .second
with space, .row .second: all .row elements that have .second child elements in their list of child elements. Any nesting deep.
This also means that there is no specific precedence at play in your case.
You either select any second row element or any second child element of any row element.
I get the feeling that your confusion originates from the difference in notation in CSS and HTML tags:
<tag class="row second"> with space is not equal to.row .second { ... } also with space, but equal .row.second { ... } without space.
It literally means a <tag> that is both a .row and a .second.
With space in CSS litterally means select all parent tags that are .row and select all .second child tags of those parents.
Update
I forgot to mention (like #TemaniAfif did) that color is inherited from the parent, I assumed it to be known by OP.
snippet showing the various possibilities:
div>* {
background-color: lightgray;
margin: 15px;
}
/* the default for all */
.row, .default1 { color: purple }
.second, .default2 { color: orange }
/* exceptions in special cases */
.row.second, .exception1 { color: green }
.row .second, .exception2 { color: red }
<p><b>Legend:</b> explanation per parent class used and (rule that applies)</p>
<h3>no parent class</h3>
<div>
<div>no class, will be document default</div>
<div class="row">row, will be purple (default1)</div>
<div class="second">second, will be orange (default2)</div>
<div class="row second">row second, will be green (exception1)</div>
</div>
<h3>.row parent</h3>
<div class="row">
<div>no class, will be purple from parent (default1)</div>
<div class="row">row, will be purple, like parent (default1)</div>
<div class="second">second, will be red, because child of row (exception2)</div>
<div class="row second">row second, will be red, overrides parent (exception2)</div>
</div>
<h3>.second parent</h3>
<div class="second">
<div>no class, will be orange from parent (default2)</div>
<div class="row">row, will be purple, overrides parent (default1)</div>
<div class="second">second, will be orange, like parent (default2)</div>
<div class="row second">row second, will be green, overrides parent (exception1)</div>
</div>
<h3>.row .second parent</h3>
<div class="row second">
<div>no class, will be green from parent (exception1)</div>
<div class="row">row, will be purple, overrides parent (default1)</div>
<div class="second">second, will be red, because child of row (exception2)</div>
<div class="row second">row second, will be red, overrides parent (exception2)</div>
</div>

Related

css not select the first class between other container

css doesn't select the first class
:not(:first) doesn't work because .callout is wrapped by other container
.callout:not(:first) {
color: red;
}
<div class="d-flex">
<div class="flex-fill">
<div class="callout">
Text A
</div>
</div>
<div class="flex-fill">
<div class="callout">
Text B - only this set color red
</div>
</div>
</div>
Select the .callout element whose parent is not the :first-child of its parent element
.flex-fill:not(:first-child) .callout {
color: red
}
Or just revert the logic and target the :last-child
.flex-fill:last-child .callout {
color: red
}
Or target the .callout inside the second parent element, no matter how many .flex-fill siblings you have
.flex-fill:nth-child(2) .callout {
color: red
}
Codepen example
Anyway, I don't recommend to use this kind of selectors or to rely on a specific markup structure because this approach can easily cause maintainability problems as the code grows and, if possible, I'd suggest to place instead a specific class for this purpose on the right element.

single identifier for multiple css classes

I have frequent bundling together of css classes like this:
<div class="row z-depth-2 gradient-background">
... Blah
</div>
I have these three classes: row z-depth-2 gradient-background used together in more than 200 places. How can I introduce a single class for these three taken together?
I don't mind CSS or SASS. One other problem is that row and z-depth-2 are defined in materialize.css which I don't wanna touch. So I can't simply extend these classes in SASS like so:
.input-group {
#extend .row, .z-depth-2, .gradient-background
}
So I want to be able to do something like this:
<div class="input-group">
... Blah
</div>
Why not simply use the three classes as one selector like this .row.z-depth-2.gradient-background. It will allow you to select elements that have these 3 classes (it can have more of course) :
div {
margin:10px;
height: 20px;
background: blue;
}
.row.z-depth-2.gradient-background {/* pay attention as there is no spaces between the classes*/
background: red;
}
<div class="row z-depth-2 gradient-background">
<!-- Select this one -->
</div>
<div class="row gradient-background">
</div>
<div class="row z-depth-2">
</div>
<div class="row gradient-background z-depth-2 more-class">
<!-- Select this one -->
</div>
Usefull links to get more details :
https://css-tricks.com/multiple-class-id-selectors/
Using two CSS classes on one element
UPDATE
If you want to use a new class that will later be replaced with these 3 ones, you can use a small jQuery script in order to do what you need, like this :
//select all element with class input-group
$('.input-group').each(function() {
$(this).removeClass('input-group'); //remove input-group
$(this).addClass('row z-depth-2 gradient-background'); //add the other classes
})
div {
margin: 10px;
height: 20px;
background: blue;
}
.row.z-depth-2.gradient-background {
/* pay attention as there is no spaces between the classes*/
background: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="input-group">
</div>
<div class="class">
</div>

Checking if data attribute is set at parent div css / less and using it for the child divs as well

I have div tag for which a data-type attribute is associated. I want to apply different styles depending on data-type is set or no.
<div data-type="type1">Hello, World!</div>
Can I check if this attribute data-type is set or no in css/less ? This question is solved with this.
But, if I apply this data-type attribute only to the parent div, can I use this attribute for all the child div tags as well.
For instance,
<div data-type=`type1`>
<div id="newDiv"> </div>
</div>
In my CSS, I want to apply different styles for #newDiv depending on whatever type (data-type) is set to its parent. I don't want to specify the data-type attribute to the child div as well. How do we do this in CSS ?
You can use :not([data-type]) to select any element that does not have the attribute data-type set regardless of the values used.
Basic working example:
div:not([data-type]) {
color: red;
}
<div data-type="type1">Hello, World!</div>
<div>Hello, World!</div>
Alternatively, you can do the opposite and use [data-type] to select anything with the data-type attribute set regardless of the value
Working example:
div[data-type] {
color: red;
}
<div data-type="type1">Hello, World!</div>
<div>Hello, World!</div>
If you want to target a child div whose parent div has the data-type attribute set the you can use something like this:
div[data-type]>h1 {
color: red;
}
<div data-type="type1">Hello, World!
<h1> How are you?!</h1>
</div>
<hr>
<div>Hello, World!
<h1> How are you?!</h1>
</div>
This also can be reveresed based on your selector preference to target the child elements of parent elements which do not have the data-type attribute set.
div:not([data-type])>h1 {
color: red;
}
<div data-type="type1">Hello, World!
<h1> How are you?!</h1>
</div>
<hr>
<div>Hello, World!
<h1> How are you?!</h1>
</div>
If you have more complex structures you can make use of the wildcard * selector to build selectors that match very broad patterns. The letters represent the depth of the tree on which the element resides with aaa being a direct child and bbb being a grandchild...etc
Basic Example:
[data-type] * h1,
[data-type] h1 {
color: red;
}
<div data-type="type1">
<h1> aaa</h1>
</div>
<hr>
<div>
<h1> aaa</h1>
</div>
<hr>
<div id="test" data-type="type1">
<div>
<h1> bbb</h1>
<div>
<h1> ccc</h1>
</div>
</div>
<h1 class="wow"> aaa</h1>
<div>
<h1 class="wow"> bbb</h1>
</div>
</div>
<hr>
<div id="test">
<h1 class="wow"> aaa</h1>
<div>
<div>
<h1> ddd</h1>
</div>
<h1 class="wow"> ccc</h1>
</div>
</div>
If you find a pattern in your data-type value, yes, you can:
/* 1. Attribute value starts with "type" */
div[data-type^="type"] {
/* Styles */
}
/* 2. Attribute value contains "type" */
div[data-type*="type"] {
/* Styles */
}
Works for: type1, typex, typeaskdasd, etc...
Works for: abctypexyz, typexyz, etc...

Benefits of [class="classname"] over .classname for emails

Why would class selection by attribute [class="classname"] be used in place of selection by class .classname? Are there any benefits for this when considering cross email-client compatible emails?
Edit: I am fully aware of how each selector works, however, I am trying to figure out if there is a reason selection by attribute would be used over selection by class for compatibility reasons (specifically in the case of a class attribute consisting of one class) due to the issues with css and email clients. This question arose after reviewing a responsive email template that explicitly used class selection by attribute over selction by class.
e.g.
.red-text { color: red }
[class="red-text"] { color: red }
<td class="red-text">This text is red</td>
These are not equivalent.
[class="a"] will match <div class="a">, but not <div class="a b">.
.a will match both <div class="a"> and <div class="a b">.
For example:
div.green {
color: #0f0;
}
div[class="red"] {
color: #f00
}
<div class="green"> green </div>
<div class="green bold"> green with other classes </div>
--
<div class="red"> red </div>
<div class="red bold"> red with other classes <-- I'm broken </div>
.classname will match this element, but [class="classname"] will not.
<div class="foo classname other">
hello world
</div>

CSS change an element content on hover from different element

Is it possible in CSS to change an element's content when hovered from a different element? Let's say for example, I have this divs A, B, C, D, E, F. I want to show some text in A when I hover in B. a different text will appear in A if I hover over in C. and the same goes for the rest. All the changes takes place in A when hovered in divs B to F.
Currently this is not possible with CSS only. You can adjust the styles of children or upcoming siblings. But you can't set the styles of previous siblings or parent elements.
So regarding your case you could do:
<div class="a"></div>
<div class="b"></div>
<div class="c"></div>
CSS
/* next sibling only */
div.a:hover + div.b { /* styles for b when hovering a */ }
/* general sibling selector */
div.a:hover ~ div.c { /* styles for c when hovering a */ }
div.b:hover ~ div.c { /* styles for c when hovering b */ }
You can't go the other way, from b to a for example.
Demo
Try before buy
This is possible using the general sibling selector ~ and by having a matching div to go with each of the hovered divs. This works in the latest version of all browsers. http://jsfiddle.net/s8uwu/
HTML
<div id="a">Hello A</div>
<div id="b">Hello B</div>
<div id="c">Hello C</div>
<div id="d">Hello D</div>
<div id="e">Hello E</div>
<div id="text">
<div class="a">From A</div>
<div class="b">From B</div>
<div class="c">From C</div>
<div class="d">From D</div>
<div class="e">From E</div>
</div>
CSS
#a:hover~#text .a,
#b:hover~#text .b,
#c:hover~#text .c,
#d:hover~#text .d,
#e:hover~#text .e{
display: block;
}
#text div{
display: none;
}
Simply from its name, CSS(Cascading Style Sheet) is only for applying style/appearance in a convenient way.
Hence it does not at all deal with the content of an web-page.
However You definitely can do it with the help of JavaScript as follows-
<div id="a" onmouseover="document.getElementById('b').innerHTML='ijkl';">abcd</div>
<div id="b">efgh</div>

Resources