The selector works similarly to /deep/ - css

I need a selector that will select everything in the X class, except for the Y class objects. Maybe my problem would solve the selector /deep/ but it is not supported.
I have a page structure:
<div class="x">
<div class="y"></div>
<div>
<div>
<div>
<span class="y"></span>
<div>1</div>
<label class="y"></label>
<div>
<span class="y"></span>
<p>2</p>
</div>
</div>
</div>
</div>
<div>
<span class="y"></span>
<div>3</div>
</div>
<div>
<div>4</div>
<div>
<div>5</div>
</div>
</div>
<div>6</div>
</div>
I need a selector or xpath that will select:
<div>1</div>
<p>2</p>
<div>3</div>
<div>
<div>4</div>
<div>
<div>5</div>
</div>
</div>
<div>6</div>
I need a general solution.

This XPath,
//div[#class="x"]//*[not(#class="y") and not(.//*[#class="y"])]
will select all div[#class="x"] descendants that do not have a #class="y" attribute and do not have any descendants that have #class="y" elements,
<div>1</div>
<p>2</p>
<div>3</div>
<div>
<div>4</div>
<div>
<div>5</div>
</div>
</div>
<div>4</div>
<div>
<div>5</div>
</div>
<div>5</div>
<div>6</div>
which matches your example if we assume that your example was incomplete.

There is the :has(...) pseudo-class but it cannot be used in stylesheets for performance reasons. This limitation is baked into CSS engines for all browsers because every time they render web pages, they traverse through the entire DOM and apply selectors that match the existing element (and hence haven't yet looked at their children). Instead this pseudo-class is typically used for dedicated selector engines such as Sizzle (known by its development/use for jQuery).
If you wanted to use that pseudo-class, then you could try :not(.y):not(:has(.y)). Then in order to get the topmost results, I select children only of elements that did not match (ie. :has(.y) > :not(:has(.y))). The one caveat comes if an element with class "y" has children. The only way to handle that is to repeat the pseudo-class specifying :not(.y) for as many levels deep that you want to go (I didn't do this). Here's a live example:
// The selector
var elements = $('.x > :not(.y):not(:has(.y)), .x :has(.y) > :not(.y):not(:has(.y))');
// Format the HTML
var html = elements.map(function(){
var dirty = this.outerHTML;
// Get leading whitespace to remove
var leading = (dirty.match(/\r?\n *(?= {4})/) || ['\r\n'])[0];
// Create regex to replace whitespace
var leading = new RegExp(leading.replace(/\r/,'\\r?').replace(/\n/,'\\n'), 'g');
// Show newlines, whitespace in HTML
var cleaned = $('<div>').text(dirty).html().replace(leading, '<br/>').replace(/ /g, ' ');
return cleaned;
}).toArray();
// Add the HTML to the page
var results = $('#results');
for(var i=0; i<html.length; i++) {
results.append($('<li>').html(html[i]));
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<!-- Sample HTML -->
<div class="x">
<div class="y"></div>
<div>
<div>
<div>
<span class="y"></span>
<div>1</div>
<label class="y"></label>
<div>
<span class="y"></span>
<p>2</p>
</div>
</div>
</div>
</div>
<div>
<span class="y"></span>
<div>3</div>
</div>
<div>
<div>4</div>
<div>
<div>5</div>
</div>
</div>
<div>6</div>
</div>
<h3>Results</h3>
<ol id="results" class="y"></ol>

Related

:last-child of nested list using shadow dom

To style the last element of a nested list...
<div>
<div>
<div>1</div>
<div>2</div>
</div>
<div>
<div>1</div>
<div>2</div> <!-- style this -->
</div>
</div>
...we can use this selector:
div>div:last-of-type>div:last-of-type
But if these <div> were web components using shadow dom - how does one style this last element (without JS)?
A global selector wouldn't work because it'd have no influence on the children. And a child itself wouldn't know if it's really the last child because it can't look "outside" itself.
Any ideas?
You are not saying where does really your shadow starts. But I guess that the only problem would be when it starts mid-level.
In this case, setting a css variable in this should work:
I am crossing the shadow boundary using the --mycolor property
.element:last-child {
--mycolor: red;
}
.inner:last-child {
background-color: var(--mycolor);
}
<div>
<div class="element">
<div class="inner">1</div>
<div class="inner">2</div>
</div>
<div class="element"> <!-- shadow starts here -->
<div class="inner">1</div>
<div class="inner">2</div> <!-- style this -->
</div>
</div>

Complex css selectors

Hello I need to get CSS selector after active class, for example:
if I have 7 div and one of them have active class I need to get the fourth element after active class.
<div>1</div>
<div class="active">2</div>
<div>3</div>
<div>4</div>
<div>5</div>
<div>6</div> <!-- I need to get this selector -->
<div>7</div>
You could use + selector
.active + div + div + div + div {
background:red;
}
<div>1</div>
<div class="active">2</div>
<div>3</div>
<div>4</div>
<div>5</div>
<div>6</div> <!-- I need to get this selector -->
<div>7</div>

Nested first-of-type and first-letter

I'm trying to add a drop-cap feature using css selectors first-of-type and first-letter.
This is for a WordPress site and the issue I'm having is that some posts could be build using visual composer while others could be built using the standard editor.
That means that the inner html structure of the content changes (divs are added) and my css rule .post_content > p:first-of-type:first-letter { font-size: 24px } doesn't work any more.
<div class="post_content">
<p>Hello world</p>
<p>Another line</p>
<p>Another line</p>
<p>This shouldn't be dropcaped</p>
<p>Another line</p>
<p>Another line</p>
</div>
becomes
<div class="post_content">
<div class="vc_row wpb_row vc_row-fluid">
<div class="wpb_column vc_column_container vc_col-sm-12">
<div class="vc_column-inner">
<div class="wpb_wrapper">
<div class="wpb_text_column wpb_content_element ">
<div class="wpb_wrapper">
<p>Hello world</p>
<p>Another line</p>
<p>Another line</p>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="vc_row wpb_row vc_row-fluid">
<div class="wpb_column vc_column_container vc_col-sm-12">
<div class="vc_column-inner">
<div class="wpb_wrapper">
<div class="wpb_text_column wpb_content_element ">
<div class="wpb_wrapper">
<p>This shouldn't be dropcapped</p>
<p>Another line</p>
<p>Another line</p>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
If i remove the immediate children selector (>) all paragraphs get the style applied.
Is there something I'm missing ? Is there any way I could achieve the desired effect ?
Thanks!
PS: Actually, the simplified version works, I just tested it in a fiddle. But the real html is this:
https://jsfiddle.net/s8ajo1hw/
and you can see the issue with the <p> tag being selected multiple times.
PPS: After a bit of fiddling, I found out that the issue was from p nested in separate divs that are nested in the main post_content. Simplified version: https://jsfiddle.net/9v9j3amz/
As you can see from the fiddle, the behaviour is quite weird.
Any insight on why this happens is much appreciated!
Just use:
.post_content:first-letter{
font-size:34px;
color: red;
}
The complex query was not working because :first-letter applies the style on the first letter from the selector.
I hope it helps you to achieve desired effect. Add this CSS to your stylesheet..
div.post_content * > p:first-of-type:first-letter {
font-size: 24px;
}
It will select all nested elements no matter how many. This asterisk * is a wildcard here.
Update:
I have tinkered a bit with your code but actually there are way too many nested elements and they can grow. So if you don't mind javascript add this snippet to the end of your file. Will solve your problem pretty good for now. Work on your both fiddles.
<style>
.my-class:first-letter {
font-size: 60px;
}
</style>
<script>
var el = document.getElementsByClassName("wpb_wrapper")[0].getElementsByTagName("p")[0];
el.className = 'my-class';
</script>
Since ::first-letter applies to the "first letter of the first line of a block-level element" you can just target the .post_content:
.post_content:first-letter {
font-size: 48px;
}
https://developer.mozilla.org/en-US/docs/Web/CSS/::first-letter
demo: https://codepen.io/anon/pen/KqZYgy

CSS3 div and last-child - how aright?

CODE:
<div class="AllDiv">
<div class="LeftDiv">
<div class="LeftDiv2"> </div>
<div class="Photo"></div>
</div>
<div class="News">
.....
</div>
</div>
<div class="AllDiv">
<div class="LeftDiv">
<div class="LeftDiv2"> </div>
<div class="Photo"></div>
</div>
<div class="News">
.....
</div>
</div>
<div class="AllDiv">
<div class="LeftDiv">
<div class="LeftDiv2"> </div>
<div class="Photo"></div>
</div>
<div class="News">
.....
</div>
</div>
I would like make that last div, LeftDiv, get CSS display:none.
For it I use code: div.AllDiv .LeftDiv .LeftDiv2:last-child{display:none;}, but it is not working.
Also i try use i usediv.AllDiv:last-child div.LeftDiv .LeftDiv2{display:none;}, but it not work too.
Tell me please where error and how write it correctly?
LeftDiv2 is the first child if it's parent element, not the last child. However, you don't need the last child class at all. just remove :last-child. If you really wanted to select it using the pseudo class you would want :first-child in your current markup.

Selecting an element based on immediate follower

Is there any natively supported way of selecting an element based on what it is followed by?
I want to style all h2-tags that are immediately followed by a p-tag. Example:
<body>
<h2>Heading 1</h2>
<h2>Heading 2</h2>
<div>Text</div>
<h2>Heading 3</h2> <!-- Only this one -->
<p>Text</p>
<h2>Heading 4</h2>
<div>Text</div>
<h2>Heading 5</h2>
<div>Text</div>
</body>
Currently this is not possible in CSS, as there are no selectors that will select the previous element.
If you were to use jQuery, something like this would work. (example here)
$('p').prev('h2').css('color','red');
When CSS4 selectors are supported, I believe you will be able to achieve this.
I would simply use a class if I were you and I didn't want to use jQuery.
CSS
.h2-with-p{}
HTML
<body>
<h2>Heading 1</h2>
<h2>Heading 2</h2>
<div>Text</div>
<h2 class="h2-with-p">Heading 3</h2> <!-- Only this one -->
<p>Text</p>
<h2>Heading 4</h2>
<div>Text</div>
<h2>Heading 5</h2>
<div>Text</div>
</body>

Resources