Use CSS selectors like :first-child inside shadow dom - css

Is there any way to use css selectors like :first-child, :not(:last-child) inside of the shadow dom?
The example is like this
CustomElement.html
<div id="parent-div>
<slot></slot>
</div>
App.html
<div>
<custom-element>
<div class="heading">Main Heading</div>
<div class="item">item 1</div>
<div class="item">item 1</div>
<div class="item">item 1</div>
<div class="heading">Second Heading</div>
<div class="item">item 1</div>
<div class="item">item 1</div>
<div class="item">item 1</div>
</custom-element>
</div>
what i want to do is find out the first .heading element and add custom styles to it. Since <div class=heading"> is actually a component, i can't add custom styling to it thinking only as the first heading.
P.S.:- I'm using angular-elements, if it helps

The same answer as I gave in your question yesterday
Slotted content is not moved to shadowDOM,
it remains (invisible) in lightDOM
and is REFLECTED in the shadowDOM <SLOT>
So SLOTTED content styling is done in the CSS scope where <custom-element> resides.
or with ::slotted( x )
From the docs:
::slotted can only take a compound selector (in the parenthesis). The reason of this > restriction is to make a selector style-engine friendly, in terms of performance.
So with your structure you can do:
::slotted(.heading) { }
or
::slotted(:first-child) { }
but not:
::slotted(.heading:first-child)
Because it is a complex selector, not a (simple) compound selector
So your headings can be styled in global CSS, and will REFLECT to slotted content:
my-element div.heading{
background:blue;
color:white;
}
If you want to encapsulate this styling you have to wrap everything in (another) component
You can target all UNnamed slotted content with:
::slotted(:not([slot])){
font-weight:bold;
}
Here is another JSFiddle to play with slotted styling:
https://jsfiddle.net/WebComponents/108ey7b2/

I found a workaround for this in JS way.
For each slot, we have a eventHandler called (slotchange). By using that we can get the DOM event for the slot whenever the slot changes. Like this (HTML)
<custom-element (slotchange)="onSlotChanged($event)"></custom-element>
JS
onSlotChanged($event) {
console.log($event) // Go and research yourself about this event, you'll find many things usefull.
$event.target.assignedNodes() // This will give you the array of every elements, that are in side of the shadow dom
// Example usage, adding the margin-bottom to only first time (css :firsh-child)
$event.target.assignedNodes()[0].shadowRoot.getElementById('some-id').style.marginBottom = '10px'
}
If you only need to add a property to the element, you don't have to query shadowDom like "node.shadowRoot". But, if you want to access the element inside the shadowRoot of that element, you have to use that

Related

Using CSS :hover to change style but only when adjacent to particular class

I'm experimenting with Bootstrap.js panels that can collapse. I'd like to see if it's possible to change styling of a panel-heading element but only when it's adjacent to a panel-collapse element. The selector below will change all headings obviously.
.panel-heading:hover {}
Because I'm trying to look ahead to see if the target element is followed by a particular class I'm not sure I see if CSS can support this.
<!-- This should change style of panel-heading when hovering over the panel-heading element -->
<div class="panel">
<div class="panel-heading">
</div>
<div class="panel-collapse">
</div>
</div>
<!-- This should NOT change the style of the panel-heading when hovering over the panel-heading element -->
<div class="panel">
<div class="panel-heading">
</div>
<div class="panel-body">
</div>
</div>
There is no way to currently do this in CSS3, however there is something being proposed in CSS Selectors Level 4. This feature has been widely requested.
Relational Pseudo-class: :has()
Such that you could do something like:
.panel:has(.panel-collapse) .panel-heading {
}
Meaning, apply styles to all .panel-heading classes that are a child of .panel classes containing .panel-collapse
This is a great article on upcoming CSS Selectors Level 4: https://www.sitepoint.com/future-generation-css-selectors-level-4/
In the meantime, you'll have to use something like jQuery. You could add a class like .panel-hoverable to all .panel elements that contain elements with the class .panel-collapse

CSS Select Sibling of An Element with A Specific Sub-Element?

The snippet below is a part of a much larger structure with many .step elements.
I need to match all .stepText elements that are next to .stepTitleAndImages ul.standard
In other words, match all .stepText elements that have .step parent that has .stepTitleAndImages child that has .stepImages.standard child
<div class="step">
<div class="stepTitleAndImages">
<h3 class="stepTitle"></h3>
<ul class="stepImages standard"></ul>
<div class="clearer"></div>
</div>
<div class="stepText "></div> **HOW TO SELECT ALL ELEMENTS LIKE THIS ONE?**
<div class="clearer"></div>
</div>
<div class="step">
<div class="stepTitleAndImages">
<h3 class="stepTitle"></h3>
<ul class="stepImages medium"></ul>
<div class="clearer"></div>
</div>
<div class="stepText "></div>
<div class="clearer"></div>
</div>
PS: I cannot modify the HTML. Cannot use anything other than pure CSS.
Just use this for selecting first case
.step:nth-child(1) .stepText {
... Your CSS here
}
For second one use
.step:nth-child(2) .stepText {
... Your CSS here
}
For selecting both use
.step .stepText {
... Your CSS here
}
Then you should require jquery for that
Selecting Parents sibling is not possible only with pure CSS yet, You can achieve this by a single line of jquery:
$('ul.standard').parent().siblings(".stepText").css(...your CSS here);
This cannot be done with your HTML structure and with pure CSS. The closest solution to your problem, changing the HTML structure and with pure CSS, would be to move the standard class to its parent tag:
<div class="stepTitleAndImages standard">
<h3 class="stepTitle"></h3>
<ul class="stepImages"></ul>
<div class="clearer"></div>
</div>
This would allow you to use the adjacent sibling selector (+), which matches the second selector if it's the direct next sibling of the first, like this:
.stepTitleAndImages.standard + .stepText {
/* Styles */
}
A more flexible approach would be to use the general sibling selector which would match any sibling preceded by the first selector, not only the direct next one:
.stepTitleAndImages.standard ~ .stepText {
/* Styles */
}
The :has pseudo-class is in development by Mozilla, but it hasn't hit any stable browsers yet. With it, and with your HTML structure, you could go:
.stepTitleAndImages:has(.standard) + .stepText {
/* Styles */
}
Unfortunately, currently you can't solve this in any other way with CSS (and with your HTML structure) only.

How to get different class selectors using nth-child in css

I have these codes
<div class="test">
<div class="tag1"></div>
<div class="tag1"></div>
<div class="tag1"></div>
<div class="tag2"></div>
<div class="tag2"></div>
<div class="tag2"></div>
</div>
Now I want to get second child of .tag2 selector.
I try this code and it's not working, but when I use .tag1 it's working.
.test .tag2:nth-child(2) {
background-color: #000;
}
How can i fix this?
:nth-child works on elements, not on other selectors. Here your .tag2 element is the 4th element in the list.
When browsers begin to implement the Selectors Level 4 standards we'll be able to achieve this using the :nth-match structural pseudo-class selector, but unfortunately that's quite a way off yet.
A Potential CSS Solution (Markup-dependant)
If your markup will always be that the first .tag2 will only ever follow .tag1 and the second .tag2 will only ever follow .tag2, you can fake it with this:
.tag1 + .tag2 + .tag2 {
background-color: #000;
}
This selects the .tag2 element which immediately follows a .tag2 element which immediately follows a .tag1 element.
A JavaScript Solution
If you can't do that then you'll have to go for a JavaScript solution instead (or implement something on the back-end which generates the content).
The below example pulls all .tag2 elements within your .test container, then grabs the 2nd one ([1] here, remember the 0 index: [1] = 2nd), then applies the style to that element.
You'll need to add in some checks to ensure this element exists before applying the style.
document.querySelector('.test').querySelectorAll('.tag2')[1].style.background = '#000'
<div class="test">
<div class="tag1">tag1</div>
<div class="tag1">tag1</div>
<div class="tag1">tag1</div>
<div class="tag2">tag2</div>
<div class="tag2">tag2</div>
<div class="tag2">tag2</div>
</div>
I know your question isn't tagged with JavaScript, but a good solution with JS is as follows:
var alltagtwos = document.getElementsByClassName("tag2");
alltagtwos[1].className += " secondel";
.tag2.secondel {
background-color: #000;
color: #fff;
}
<div class="test">
<div class="tag1">tag1 - 1</div>
<div class="tag1">tag1 - 2</div>
<div class="tag1">tag1 - 3</div>
<div class="tag2">tag2 - 1</div>
<div class="tag2">tag2 - 2</div>
<div class="tag2">tag2 - 3</div>
</div>
What I've done here is add all elements with the class .tag2 into an array-like object using getElementsByClassName. I then select the second element which has the class .tag2 (index starts at zero, so I've select [1]) and appended another class to it (.secondel) which I've then styled with CSS.

How to apply different CSS styles to 2 elements with the same class name?

I created a website that has different navigation menus. In 2 menus, I use the same HTML class element.
I have a .css file that styles that class element in 1 menu. However, in another menu, I would like to style the elements differently.
Yes, I know I can rename the class name, but to be consistent with what I have right now in the structure of my markup, and also the fact that the class name is used to style multiple other elements, how would I be able to apply different styles to 2 different elements with the same class name?
Can this be done using some kind of if statement condition in CSS?
For example, in 1.html:
<div class="classname"> Some code </div>
In 2.html:
<div class="classname"> Some different code </div>
Since I just want to style this "one" element differently in 2.html, can I just add an id attribute along with the class attribute, and use both the id and class and somehow as the selector?
Once again, I would not like to remove the class name at all, if possible.
Thanks!
I'll just add that typically when there are multiple menus you might have them wrapped in a different structure. Take for instance:
<nav class='mainnav'><div class="classname one"> Some code </div></nav>
<div class='wrapper'><div class="classname"> Some different code </div></div>
You can easily target these:
.mainnav>.classone {}
.wrapper>.classone {}
Or if the parent html has a class:
<div class='ancestor1'><div><div class="classname one"> Some code </div></div></div>
<div class='ancestor2'><div><div class="classname one"> Some code </div></div></div>
.ancestor1 .classname {}
.ancestor2 .classname {}
Obviously this depends on where in the html they might be.
You can add another class name to each element.
<div class="classname one"> Some code </div>
<div class="classname two"> Some different code </div>
And then aplpy different rules to them:
.classname.one {
border: 1px solid #00f;
}
.classname.two {
border: 1px solid #f00;
}
Edit:
Updated Demo link: http://jsfiddle.net/8C76m/2/
If you must keep only one class for each element, you may try the nth-child or nth-of-type pseudo-class:
.classname:first-child {
font-size: 2em;
}
.classname:nth-of-type(2) {
color: #f00;
}
Ref:
http://www.w3schools.com/cssref/sel_firstchild.asp and http://www.w3schools.com/cssref/sel_nth-of-type.asp
Just give each one a different id
#firsthtml .classname {
}
#sechtml .classname {
}
Be sure to use the space, as #firsthtml.classname is something totally different.
<div class="classname" id="firsthtml"></div>
<div class="classname" id="sechtml"></div>
You could also use two different class names
<div class="classname secondclassname"></div>
Define secondclassname in your css with the additional css
.classname.secondclassname{
}
You can also do something like this:
<div class="classname"> Some code </div>
<div class="classname second"> Some different code </div>
And the CSS for the first .classname would be something like that:
.classname:not(.second) {}
For the second element it goes easily:
.classname.second {}
I know this is a poor way of doing it, the suggestions from previous answers are helpful, but try this maybe:
First menu:
<div class="classname"> Some code </div>
Second menu:
<div class="classname" style="margin-bottom:0;color:Black;width:100px;height:100px"> Some other code </div>

css :target on children

Suppose we have this html
<div class="a">
<div>...</div>
...
<div id="b">xyz</div>
</div>
<div class="a">
<div>...</div>
...
<div id="c">abc</div>
</div>
Applying some style on #b upon targeting it in url is easy to do with the css :target selector.
Is it possible to apply some some style on the parent div with class="a" as well?
No, since you would need a CSS parent selector for that. Nothing in CSS2 and CSS3 has been specified for that. CSS4 does have (a somewhat) parent selector (called the subject selector) using the ! symbol, but no browser supports it (yet).
You can add an extra id to your <div class="a"> and make it:
<div class="a" id="abc">
...and still use the :target.
No, CSS cascades (CSS = Cascading Style Sheets), it doesn't go up.
You will need to explicitly apply styling to the parent element.
You would be better doing something like #otinanai suggested and adding a class to your child divs. e.g.
HTML
<div class="a">
<div>...</div>
...
<div class="aItem" id="b">xyz</div>
</div>
<div class="a">
<div>...</div>
...
<div class="aItem" id="c">abc</div>
</div>
CSS
.a {
border: 1px solid #000;
}
.aItem {
color: #999;
}
So you will use classes to consistently style your elements. Otherwise you will have to write CSS for D, E, F G through to Z, and only use the ID's for bookingmarking/URL purposes.

Resources