Exclude a class and all of its children - css

I am loading global CSS styles but I need them to not affect one part of the page and all of its subcomponents. There are some old information but is there a solution now when :not() is a Level 4 selector?
Codepen example that is not working: https://codepen.io/LaCertosus/pen/PoaYeRj
I have a HTML structure that is not predefined, I do not know how many and what elements are around and inside the "red" element.
Visual example
<div class="parent">
<div class="_filler">
<div class="_filler">
<div class="block">
Should be red
</div>
</div>
</div>
<div>
<div class="child-lime">
<div class="block">
Should be lime
</div>
<div class="_filler">
<div class="block">
Should be lime
</div>
</div>
</div>
</div>
</div>
.parent:not(.child-lime) {
.block {
background: red;
}
}
/* Block is an example, in reality we don't know the class name */
.block {
height: 100px;
width: 100px;
background: lime;
border: 1px solid #000;
display: flex;
align-items: center;
justify-content: center;
padding: 1rem;
}
I have tried different combinations with :not() selector but with no luck. It works when I don't need to include all children.

add this into CSS file
.parent > ._filler .block {
background: red;
}
.child-lime .block {
background: lime;
}
remove this from CSS file
.parent:not(.child-lime) {
.block {
background: red;
}
}

Your question seems to be missing some details, but here's what gets you close (assuming you can't touch the underlying HTML)
.parent {
div:not(.child-lime .block) {
background: red;
}
.block {...}
}
There's an un-classed div element that turns red...but since your comments seem to require not touching the underlying HTML and using the :not pseudo, that's probably as close as you can get.

Related

CSS selector to target element where sibling does not have a specific class

I'm working on a slider that has previous button, content and next button as sibling nodes. I'm hiding disabled buttons and I need to adjust the margin for the content
I'm having difficulties with the selectors. I want to target the container to adjust the margin based on if the button is disabled or not. My initial idea was to do this with flex but it's an old
I've been trying something like
.content {
&:not(+ .button-disabled) {
margin-left: 50px;
}
}
but it seems I'm not allowed to have a +inside :not(). Is there any other way I can target this?
You can define a class to the parent container of the three siblings, like
<div class="disabled-button">
<div class="prev"></div>
<div class="cont"></div>
<div class="next"></div>
</div>
And define CSS for them, like:
.wrapper {
width: 80%;
height: 30px;
display: inline-flex;
}
.wrapper > div {
width: 33%;
height: 100%;
border: 1px solid black;
background-color: green;
}
.wrapper.disabled-button .prev {
margin-left: 50px;
}
<div class="disabled-button wrapper">
<div class="prev"></div>
<div class="cont"></div>
<div class="next"></div>
</div>
<div class="wrapper">
<div class="prev"></div>
<div class="cont"></div>
<div class="next"></div>
</div>

Multiple siblings, place some in same row & fill extra space

I have no control of the html. I have a parent with multiple children.Only some of them must be in the same row, while the rest of them stay unaffected and one of them must take up all the extra space. Content is auto generated and % is not an option.
Other options except inline to place on the same row to avoid the problem are welcome as well.
.parent {
background: red;
}
.same-row-child {
background: green;
display: inline-flex;
}
<div class="parent">
<div class="other-child">A</div>
<div class="same-row-child">B</div>
<div class="same-row-child">C</div>
</div>
To sum up: Α in the first line unaffected.
B+C in the same line with B taking up all the extra space.
If the idea is to use flex, then it should be the parent the flex box:
https://css-tricks.com/snippets/css/a-guide-to-flexbox/
display:flex; display:inline-flex; It enables a flex context for all its direct children.
.parent {
background: red;
display: flex;
flex-wrap: wrap;
}
.other-child {
width: 100%;
}
.same-row-child {
background: green;
}
.parent :last-child {
flex: 1;
margin-left:2px;
}
<div class="parent">
<div class="other-child">A</div>
<div class="same-row-child">B</div>
<div class="same-row-child">C</div>
</div>
looks like not the option you would use See next option
The oldish way is float and overflow, and the one to float is the one that comes first and is supposed to shrink on itself.
see https://css-tricks.com/all-about-floats/
Aside from the simple example of wrapping text around images, floats can be used to create entire web layouts.
.parent {
background: red;
}
.other-child {}
.same-row-child {
float: left;
background: green;
margin-right: 2px;
}
.parent :last-child {
float: none;
overflow: hidden;
margin: 0;
}
<div class="parent">
<div class="other-child">A</div>
<div class="same-row-child">B</div>
<div class="same-row-child">C</div>
</div>

Target :last-child with mixed class siblings?

How do I target the last child of a class when there are siblings with another class after it? It would be nice to have a :last-sibling and :last-sibling-of-type.
FIDDLE
<div class="grid">
<div class="grid-item"></div>
<div class="grid-item"></div>
<div class="grid-item"></div>
<div class="grid-item"></div> /* How do I target this if its nth position is unknowable? */
<div class="grid-orphan"></div>
<div class="grid-orphan"></div>
<div class="grid-orphan"></div>
</div>
If you need to get the last .grid-item element out of the document, regardless of what it's inside, then you can't do that in CSS. In CSS, you can only select the first, last, or nth element at one particular level of the hierarchy, you can't select the last element of some type regardless of what it's nested in.
Here is one way to get the last div inside of .grid
.grid div:last-of-type
Here's another way to get the last child of some outer div:
div :last-child
BUT The thing you probably need is some js:
You could do this the jquery approach (like below), or just do getElementsByClassNameand then set the last element in the list in the same manner.
function getlastchild() {
var items = $(".grid-item");
items.last().css("background-color", "red");
//OR even as one-liner: $(".grid-item").last().css("background-color", "red");
}
.grid {
width: 200px;
}
.grid div:last-of-type {
color: white;
}
div:last-child {
background-color: grey;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="grid">
<div class="grid-item">1</div>
<div class="grid-item">2</div>
<div class="grid-item">3</div>
<div class="grid-item">4</div>
<div class="grid-orphan">5</div>
<div class="grid-orphan">6</div>
<div class="grid-orphan">7</div>
</div>
<button onclick="getlastchild()">Press me to get last grid-item</button>
I see 4 possibilities here:
Case 1:
You already know the number of grid-orphan items, so you can use nth-last-child.
.grid-item:nth-last-child(4) {
background: blue;
}
Case 2:
You are an adventurer and this is not for production: use the newest version of nth-child and nth-last-child:
.grid-item:nth-last-child(1 of .grid-item) {
background: blue;
}
However, it only works on Safari for now (12.99%).
See specs
Case 3:
Use JavaScript.
const items = document.querySelectorAll('.grid-item')
const selectedItem = [].slice.call(items).pop();
selectedItem.style.background = 'blue';
Case 4:
Just add an extra class.
<div class="grid-item grid-item--special"></div>
.grid-item.grid-item--special {
background: blue;
}
You can use either :nth-last-child or :nth-last-of-type if you are able to put all your .grid-orphan elements inside another div.
HTML
<div class="grid">
<div class="grid-item"></div>
<div class="grid-item"></div>
<div class="grid-item"></div>
<div class="grid-item"></div>
<div class="grid-orphans">
<div class="grid-orphan"></div>
<div class="grid-orphan"></div>
<div class="grid-orphan"></div>
</div>
</div>
SCSS
.grid {
display: flex;
flex-wrap: wrap;
justify-content: flex-end;
.grid-item {
background: gray;
border: 1px solid white;
position: relative;
display: flex;
flex-direction: column;
height: 100px;
width: calc(25% - 20px);
min-width: 360px;
flex-grow: 2;
justify-content: flex-start;
cursor: pointer;
&:nth-last-child(2) {
background: navy;
}
}
.grid-orphan {
height: 0;
border: 0;
display: flex;
flex-direction: column;
width: calc(25% - 20px);
min-width: 360px;
flex-grow: 2;
justify-content: flex-start;
cursor: pointer;
}
}
Jsfiddle available here.
Otherwise, a CSS-only approach would be limited to only Apple's browsers, that is Safari desktop and on iOS, since they are the only ones that implement the selector list argument, which allows you to narrow down the elements by a class selector. For seeing this just change &:nth-last-child(2) with &:nth-last-child(1 of .grid-item)
All those answers are great. Thank you. I ended up just making the orphans <span>'s and then .grid-item:last-child worked fine. I knew I could do that but was wondering if it could be done (easily) when the orphans were the same element type as the grid items.

Parent:Flex vs Child:inline-block or inline (Benefit of using CSS3 flex?)

I was trying to understand the usage of CSS3 new entry of display:"flex". What great benefits it has brougt along with it. However, I could not find any great benefit of this new property, except putting a virtual horizontal line (1 per flex box container) to have all the inside items. Wasn't this same achieved with inner items using display:inline or display:inline-block? What new magic has this property brought or what value does it bring in to CSS designign?
Case 1: (using flex in parent)
<html>
<head>
<style>
div{background:blue;display:flex;}
p{background:yellow;}
</style>
</head>
<body>
<div>
<p>This is para1.</p>
<p>This is para2.</p>
<p>This is para3.</p>
</div>
</body>
</html>
Case 2: (Using display inline to childs)
<html>
<head>
<style>
div{background:blue;}
p{background:yellow;display:inline;}
</style>
</head>
<body>
<div>
<p>This is para1.</p>
<p>This is para2.</p>
<p>This is para3.</p>
</div>
</body>
</html>
Case 3: (Using inline-block in childs)
<html>
<head>
<style>
div{background:blue;}
p{background:yellow;display:inline-block;}
</style>
</head>
<body>
<div>
<p>This is para1.</p>
<p>This is para2.</p>
<p>This is para3.</p>
</div>
</body>
</html>
Please, help me out understanding the use-case of flex and what new can it achieve!
This question is somewhat off-topic and very broad, I still decided to answer though, as I think it could have an initial value for users who are new to Flexbox
Below is some samples, based on the questions code, that show some of the things Flexbox can do that standard block/inline-block/inline can't (some might with a lot of hacks/tricks).
To dig deeper, here is a good article: A Complete Guide to Flexbox
Properties for the flex container (has the display: flex;)
The justify-content property, defaults to flex-start
div {
background: blue;
display: flex;
justify-content: space-around; /* distribute the remaining space around each item */
}
p {
background: yellow;
margin: 5px;
padding: 5px;
}
<div>
<p>This is P1</p>
<p>This is P2</p>
<p>This is P3</p>
</div>
The align-items property, defaults to stretch
div {
background: blue;
display: flex;
justify-content: center; /* hor. center */
align-items: center; /* ver. center */
/* gave a height so the vertical centering can be seen */
height: 150px;
}
p {
background: yellow;
margin: 5px;
padding: 5px;
}
<div>
<p>This is P1</p>
<p>This is P2</p>
<p>This is P3</p>
</div>
Properties for the flex items, the (immediate) children of the flex container
The order property, defaults to 0
div {
background: blue;
display: flex;
}
p {
background: yellow;
margin: 5px;
padding: 5px;
}
p:nth-child(2) {
order: 1; /* move 2nd item last */
}
<div>
<p>This is P1</p>
<p>This is P2</p>
<p>This is P3</p>
</div>
The flex-grow property, defaults to 0
div {
background: blue;
display: flex;
}
p {
background: yellow;
margin: 5px;
padding: 5px;
}
p:nth-child(2) {
flex-grow: 1; /* make 2nd item fill the remaining space */
}
<div>
<p>This is P1</p>
<p>This is P2</p>
<p>This is P3</p>
</div>
The margin property, defaults to 0
div {
background: blue;
display: flex;
}
p {
background: yellow;
margin: 5px;
padding: 5px;
}
p:nth-child(2) {
margin-left: auto; /* push the 2nd/3rd item to the right */
}
<div>
<p>This is P1</p>
<p>This is P2</p>
<p>This is P3</p>
</div>
I am not sure if this is the answer you are looking for but here it goes -
display: flex; is more advanced than display: inline; or display: inline-block; but it is only supported from IE11 but other most of the browsers support it very well. display: flex; is much easy to manage once you learn them that's why the new Bootstrap 4 is based on them.
If you want a good explanation of the advantages of all these display properties you better read this blog, this helped me very much when I started my study on them.
If you want to know the best way of implementing them and their tricks you better read this blog, this also has a playground demo where you can check all the differents.
This is the most common use of display: flex; -
div {
background: blue;
height: 100px;
margin-bottom: 10px;
width: 100%;
}
div.flex {
display: flex;
}
p {
background: yellow;
display: inline-block;
width: 30%;
margin-left: 1%
}
<div>
<p>This is para1.This is para1.This is para1.</p>
<p>This is para2.This is para2.</p>
<p>This is para3.</p>
</div>
<div class="flex">
<p>This is para1.This is para1.This is para1.</p>
<p>This is para2.This is para2.</p>
<p>This is para3.</p>
</div>
<span>In here you can see than when i used the <strong>display: flex;</strong></span> the height of the child is same irespetive of its content. Hope you got the point.

Using CSS, how to add a pseudo element before every odd child element that is "outside" of that child element?

I want to create a grid with two columns whose width will be equal. My base HTML code looks like this:
<div class="linkgrid">
<div class="gridentry">
Loooooooooooooong
</div>
<div class="gridentry">
Short
</div>
<div class="gridentry">
Meeeedium
</div>
</div>
In this example, the first and the second gridentry should lie in the the first row. The thrid gridentry should lie in the second row. All gridentrys should have the same width.
~~~
I came up with a solution that uses a CSS table. However, to make sure the row "breaks" after every second cell, it currently requires non-semantic elements to force these "row breaks":
.linkgrid {
display: table;
border-spacing: 2px;
table-layout: fixed;
width: 50%;
}
.gridentry {
display: table-cell;
background-color: red;
padding: 5px;
text-align: center;
}
.gridentry a {
color: white;
}
.THIS-SHOULD-BE-A-PSEUDO-ELEMENT-BEFORE-EVERY-ODD-CHILD {
/* I imagine a selector that looks somewhat like this:
.linkgrid .gridentry:nth-child(odd):outsidebefore {
*/
display: table-row;
}
<div class="linkgrid">
<span class="THIS-SHOULD-BE-A-PSEUDO-ELEMENT-BEFORE-EVERY-ODD-CHILD"></span>
<div class="gridentry">
Loooooooooooooong
</div>
<div class="gridentry">
Short
</div>
<span class="THIS-SHOULD-BE-A-PSEUDO-ELEMENT-BEFORE-EVERY-ODD-CHILD"></span>
<div class="gridentry">
Meeeedium
</div>
</div>
Is there a way to remove my <span>s from my HTML (because they do not have any semantics) and use a clever CSS selector that adds them as pseudo elements at the right positions instead?
I do know that :before will "create" a pseudo-element within the selected element. Is there a non-JavaScript, CSS-only way to add a pseudo-element outside of the selected element like required in this example?
Another edit: For all those familiar with the Chrome developer tools, I want my result to look somewhat like this in the DOM tree:
<div class="linkgrid">
::outsidebefore
<div class="gridentry">
Loooooooooooooong
</div>
<div class="gridentry">
Short
</div>
::outsidebefore
<div class="gridentry">
Meeeedium
</div>
</div>
...where the ::outsidebefore pseudo-elements should have the CSS property display: table-row;.
Update 2016-01-04: While this specific question remains unanswered, my original problem was solved another way: https://stackoverflow.com/a/34588007/1560865
So please only post replies to this question that answer precisely the given question.
Display Level 3 introduces display: contents:
The element itself does not generate any boxes, but its children and
pseudo-elements still generate boxes as normal. For the purposes of
box generation and layout, the element must be treated as if it had
been replaced with its children and pseudo-elements in the document
tree.
Then, you can:
Wrap each cell in a container element
Set display: contents to those containers
Add ::before or ::after pseudo-elements to those containers
The result will look like as if the pseudo-elements were added to the cell, but outside it.
.wrapper {
display: contents;
}
.wrapper:nth-child(odd)::before {
content: '';
display: table-row;
}
.linkgrid {
display: table;
border-spacing: 2px;
table-layout: fixed;
width: 50%;
}
.wrapper {
display: contents;
}
.wrapper:nth-child(odd)::before {
content: '';
display: table-row;
}
.gridentry {
display: table-cell;
background-color: red;
padding: 5px;
text-align: center;
}
.gridentry a {
color: white;
}
<div class="linkgrid">
<div class="wrapper">
<div class="gridentry">
Loooooooooooooong
</div>
</div>
<div class="wrapper">
<div class="gridentry">
Short
</div>
</div>
<div class="wrapper">
<div class="gridentry">
Meeeedium
</div>
</div>
</div>
Note display: contents is not widely supported yet, but works on Firefox.
The most straightforward way is using an actual table structure. That is, one table divided into rows, in which the entries sit.
Also, you had width:50% on the table, but I believe from the question text that you meant every table cell to be 50% wide, rather than the table taking up 50% of the window width; so I corrected that.
.linkgrid {
display: table;
border-spacing: 2px;
}
.gridrow { /* new */
display: table-row;
}
.gridentry {
display: table-cell;
background-color: red;
padding: 5px;
text-align: center;
width: 50%; /* moved */
}
.gridentry a {
color: white;
}
<div class="linkgrid">
<div class="gridrow">
<div class="gridentry">
Loooooooooooooong
</div>
<div class="gridentry">
Short
</div>
</div>
<div class="gridrow">
<div class="gridentry">
Meeeedium
</div>
</div>
</div>

Resources