Using pseudo-classes add class to parent li - css

Is there a way of using css pseudo-class to accomplish this: I need to add the class name of the child span (high) to the parent li?
thanks
<li class="emergency" style="background-color: #FE9D9D;">
<span class="high">250</span></li>

You cannot do this with CSS.
You can with JQuery however.
$(document).ready(function () {
$('li.emergency').each(function () {
var newClass = $(this).find('span').attr('class');
$(this).addClass(newClass);
});
});
Demo
Or you can set the background colour of the span instead. display: block; will make the span full width.
HTML
<ul>
<li class="emergency">
<span class="high">250</span>
</li>
<li class="emergency">
<span class="low">100</span>
</li>
</ul>
CSS
span {
display: block;
}
span.high {
background: red;
}
span.low {
background: green;
}
Demo

Related

How can I make an element visible on hovering an element from another section?

HTML
<nb-sidebar class="menu-sidebar>
<nb-menu class="sidebar-menu">
<ul class="menu-items">
<li class="menu-item ng-tns-c140-0 ng-star-inserted" >
<a class="ng-tns-c140-0 ng-star-inserted active" ng-reflect-router-link="/pages/dashboard" title="Dashboard" href="/pages/dashboard">
</li>
</ul>
</nb-menu>
</nb-sidebar>
<div class="content">
<router-outlet>
<div class="text">Message</div>
</router-outlet>
</div>
Make router-outlet visible when I hover on li.
I tried like this
router-outlet {
display: none;
}
nb-sidebar li:hover + .content router-outlet {
display: block;
}
I want to do it with css/scss only. I want router-outlet to be visible when I hover on li.
In your example because the .content router-outlet element isn't a direct sibling of the li element the Adjacent Sibling Combinator won't work (see MDN for details)
However there's a couple of ways of doing this. The first uses the :has() pseudo class which is neat as it doesn't need any javascript but isn't currently supported on all browsers. There's a nice introduction to this from Kevin Powell. Also caniuse.com is a good resource to check for browser compatibility.
Note: I've added some text on your html to give you something to hover over.
router-outlet {
display: none;
}
/* added this */
nb-sidebar:has(li:hover) + .content router-outlet {
display: block;
}
<nb-sidebar class="menu-sidebar>
<nb-menu class="sidebar-menu">
<ul class="menu-items">
<li class="menu-item ng-tns-c140-0 ng-star-inserted" >
<a class="ng-tns-c140-0 ng-star-inserted active" ng-reflect-router-link="/pages/dashboard" title="Dashboard" href="/pages/dashboard">This is the anchor inside the li</a>
</li>
</ul>
</nb-menu>
</nb-sidebar>
<div class="content">
<router-outlet>
<div class="text">Message</div>
</router-outlet>
</div>
The more generally supported way would be to use javascript which detects you mousing over the element then adding and removing a class to override the display: none rule as follows. The code below should be self-evident but if you have any questions just pop a comment below and I'll elaborate.
window.onload = () => {
const elem = document.querySelector('.menu-item');
elem.addEventListener('mouseover', (e) => {
document.querySelector('.content router-outlet').classList.add('display-block');
});
elem.addEventListener('mouseout', (e) => {
document.querySelector('.content router-outlet').classList.remove('display-block');
});
}
router-outlet {
display: none;
}
.display-block {
display: block;
}
<nb-sidebar class="menu-sidebar>
<nb-menu class=" sidebar-menu ">
<ul class="menu-items ">
<li class="menu-item ng-tns-c140-0 ng-star-inserted " >
<a class="ng-tns-c140-0 ng-star-inserted active " ng-reflect-router-link="/pages/dashboard " title="Dashboard " href="/pages/dashboard ">This is the anchor inside the li</a>
</li>
</ul>
</nb-menu>
</nb-sidebar>
<div class="content ">
<router-outlet>
<div class="text ">Message</div>
</router-outlet>
</div>
You can use jQuery hover() method:
p {
background: orange
}
<!DOCTYPE html>
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.1/jquery.min.js"></script>
<script>
$(document).ready(function(){
$("p").hover(function(){
$('h1').css("display", "block");
}, function(){
$('h1').css("display", "none");
});
});
</script>
</head>
<body>
<p>Hover the mouse pointer over this paragraph.</p>
<h1>Title</h1>
</body>
</html>
In your code it would be:
$(document).ready(function(){
$("li").hover(function(){
$('.router-outlet').css("display", "block");}, function(){
$('.router-outlet').css("display", "none");});
});

Select target="_blank" when img is not a child

I have the following styling setup to apply an icon to external links, but I'm having an issue where it's applying to images that are a child of the anchor tag, which I do not want.
a:not(.btn) {
&[target="_blank"] {
&:after {
// The styles I want to apply
}
}
}
I've attempted to use the following img:not(:first-child) selector to wrap the block, but it does not seem to do what I want it to.
a:not(.btn) {
&[target="_blank"] + img:not(:first-child) {
&:after {
// The styles I want to apply
}
}
}
What is the correct way to adjust this code where it will correctly apply to any anchor tags with target="_blank" but not to those when an img tag is a child.
If you are happy to add a dash of javascript, you can achieve the effect you're after relatively straightforwardly by:
adding a class to all anchor elements with target="_blank"
removing the same class (the one you just added) from all parent nodes of image elements
Working Example:
// GET ALL THE ANCHORS WITH target="_blank"
const anchorTargetBlanks = [...document.querySelectorAll('[target="_blank"]')];
// ADD A CLASS TO ALL SUCH ANCHORS
anchorTargetBlanks.forEach(anchor => anchor.classList.add('link-contains-no-image'));
// REMOVE THAT CLASS FROM THE PARENT NODE OF EACH IMAGE
[...document.images].forEach((image) => {
if (image.parentNode.getAttribute('target') === '_blank') {
image.parentNode.classList.remove('link-contains-no-image');
}
});
ul {
padding-left: 0;
}
li {
margin: 1px;
}
img {
display: inline-block;
width: 30px;
height: 30px;
margin-right: 6px;
background-color: rgb(0, 0, 191);
vertical-align: middle;
}
.link-contains-no-image {
display: block;
padding: 6px;
color: rgb(255, 255, 255);
background-color: rgb(255, 0, 0);
}
<ul>
<li>Link 1</li>
<li><img src="data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'/%3E" alt="Image for Link 2" />Link 2</li>
<li>Link 3</li>
<li>Link 4</li>
<li><img src="data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'/%3E" alt="Image for Link 5" />Link 5</li>
<li>Link 6</li>
</ul>
What you are trying to do is target a parent based on its child, and that is not possible with CSS. You need to use JS or JQuery. Check these answers for more detailed suggestions.
Set parent style via child or
Is there a CSS parent selector?

How can I combine jQuery sortable UI with static captions for the placeholders?

I have a sortable set of pictures, implemented with jQuery UI. I would like to have each of the pictures within a box and with a caption at the top. The boxes and their captions should not move when pictures are sorted. Is there an easy way to do this?
EDIT: I have been investigating a bit and I found an approach that could do the trick. It consists on locking down some items on their locations using
class: static
(see the second answer to this question) and this demo.
Unfortunately, when I insert images into the list, it does not work well anymore: demo.
It looks like what you need is a combination of draggable and droppables widgets rather than sortable. I'd call it "swappable" :P
You can achieve this by swapping the images on drop event as shown below:
$("#swappable img").draggable({
revert: "invalid",
zIndex: 1
});
$("#swappable .placeholder").droppable({
snap: true,
snapMode: "inner",
drop: function(event, ui) {
var $existing = $(this).find("img.ui-draggable");
if ($existing)
/* droppable already contain an image, append it to the parent of
dropped item. */
ui.draggable.parent().append($existing);
ui.draggable.css({ // reset the positioning applied by widget
top: 0,
left: 0
}).appendTo(this);
}
});
#swappable {
list-style-type: none;
margin: 0;
padding: 0;
}
#swappable li {
border: 1px solid black;
background-color: cream;
}
#swappable li span {
/*style anyway you want*/
}
#swappable li img {
width: 50px;
height: 50px;
}
#swappable li .placeholder {
display: inline-block;
width: 50px;
height: 50px;
margin: 5px;
background: #eee;
}
<link href="http://code.jquery.com/ui/1.9.2/themes/base/jquery-ui.css" rel="stylesheet" />
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="http://code.jquery.com/ui/1.9.2/jquery-ui.js"></script>
<ul id="swappable">
<li>
<div class="placeholder">
<img src="http://i46.tinypic.com/2epim8j.jpg" />
</div>
<span>
Item Description 1
</span>
</li>
<li>
<div class="placeholder">
<img src="http://i49.tinypic.com/28vepvr.jpg" />
</div>
<span>
Item Description 2
</span>
</li>
<li>
<div class="placeholder">
<img src="http://i50.tinypic.com/f0ud01.jpg" />
</div>
<span>
Item Description 3
</span>
</li>
</ul>
The following little code did the trick:
HTML
<div class="sortableDiv">
<ul id="sortable">
<li class="ui-state-default">
<span class="ui-icon ui-icon-arrowthick-2-n-s">
<image src="http://t1.gstatic.com/images?q=tbn:ANd9GcQ0wAliOPQ_saAtWhNhhPajglDjIZVrnO19MXaYS0Doum-yztJ_CA"/>
</span>
</li>
<li class="ui-state-default">
<span class="ui-icon ui-icon-arrowthick-2-n-s">
<image src="http://t1.gstatic.com/images?q=tbn:ANd9GcQ0wAliOPQ_saAtWhNhhPajglDjIZVrnO19MXaYS0Doum-yztJ_CA"/>
</span>
</li>
<li class="ui-state-default">
<span class="ui-icon ui-icon-arrowthick-2-n-s">
<image src="http://t1.gstatic.com/images?q=tbn:ANd9GcQ0wAliOPQ_saAtWhNhhPajglDjIZVrnO19MXaYS0Doum-yztJ_CA"/>
</span>
</li>
</ul>
</div>
<div class="contentDiv">
<ul id="content">
<li class="ui-state-default">
Item Description 1
</li>
<li class="ui-state-default">
Item Description 2
</li>
<li class="ui-state-default">
Item Description 3
</li>
</ul>
</div>
CSS
.sortableDiv,.contentDiv {
float:left;
}
#content {
list-style-type:none;
line-height:88px;
margin:0;
padding:0;
}
#sortable {
list-style-type:none;
margin:0;
padding:0;
}
#sortable li {
padding-left:2em;
width:65px;
margin:5px;
}
#sortable li span {
position:relative;
margin-left:-1.3em;
}
image {
height:100px;
width:100px;
}
JQuery
$(function() {
$( "#sortable" ).sortable();
});
And some CSS given in the demo link.
DEMO
Updated DEMO
Updated DEMO-1

Why does :first-child:before target all elements?

I have a list of items which I am trying to add dividers to right of each using the :before psuedo element.
Unfortunately, it seems like when I use it in combination with both last-child and first-child, it targets every element in the list.
Example - http://codepen.io/anon/pen/rupqi
Markup
<ul class="nav nav--inline nav--secondary">
<li><a class="nav--secondary__item" href="#">Site Map</a> </li>
<li><a class="nav--secondary__item" href="#" title="Search Terms">Search Terms</a> </li>
<li><a class="nav--secondary__item" href="#" title="Advanced Search">Advanced Search</a> </li>
<li><a class="nav--secondary__item" href="#" title="Contact Us">Contact Us</a> </li>
</ul>
CSS
.nav--inline, .nav--inline > li, .nav--inline > li > a { float: left; }
.nav--secondary__item {
color: #706782;
font-size: 1.2em;
padding: 0.8em;
position: relative;
#include transition (background-color 0.5s ease-in-out);
}
.nav--secondary__item:before {
content: "|";
color: #939EB7;
position: absolute;
left: 0;
}
.nav--secondary__item:first-child:before, .nav--secondary__item:last-child:before { content: "*"; }
Does anyone know why this happens, and if so, how to fix it?
Change your css to :
li:first-child .nav--secondary__item:before,
li:last-child .nav--secondary__item:before {
content:"*";
}
Because .nav--secondary__item is first-child as well as last-child of its parent li, following selector applies the content to all of them.
.nav--secondary__item:first-child:before,
.nav--secondary__item:last-child:before
{ content: "*"; }
Fiddle
:first-child pseudoclass selects the first child of its parent, similarly :last-child.
The :first-child CSS pseudo-class represents any element that is the first child element of its parent.
See doc
This is happening because you have a elements inside li elements and you are applying first-child to those a elements.
So .nav--secondary__item:first-child applies to every .nav--secondary__item, because the parents for each a are the surrounding li, not your ul.
Going by your class naming scheme, you can change your HTML to look like this:
<li class="nav--secondary__item">
<a class="nav--secondary__item__link" href="#" title="Site Map">Site Map</a>
</li>
And your CSS for the first-child/last-child will need a slight tweak:
.nav--secondary__item:first-child .nav--secondary__item__link:before,
.nav--secondary__item:last-child .nav--secondary__item__link:before {
content: "*";
}
You will also have to make the styles that apply to the a element use the .nav--secondary__item__link class instead.
Example forked from yours: http://codepen.io/anon/pen/rknmL

Controlling CSS based hover effects

To my knowledge, the answer to this is no, can't be done, but I need a second opinion:
If I have the following:
<li>
<a >#</a>
<div class="sub">
#
</div>
</li>
and have a background image that appears on li a:hover is it possible to have that background stay on when hovering on the .sub div? This also has to work pure CSS - no javascript cheats.
My understanding is because .sub isn't a child of the a we can't reference it in css to keep the hover.
Because the image is for only one section of the code, I can't move it to the li and reference li:hover a.
Not sure what all you are trying to achieve, but there are many hover effects that can be done.
SECOND UPDATE: If you don't need to interact (other a tags, etc) at all with anything in the div, then this way cheats to get the effect. Note how the anchor inside the div does not register because of the z-index.
UPDATE I think I understand your issue better now. Can you add a wrapper and do the following?:
Example HTML:
<ul>
<li>
<div>
<a>Some anchor text</a>
<div class="sub">Some div content <a>and anchor</a></div>
</div>
</li>
</ul>
Example CSS:
li:hover {
background-color: cyan;
}
li > div:hover > a {
background-color: green;
}
a:hover {
color: yellow;
display: block;
}
a:hover + .sub {
outline: 1px solid blue;
}
.sub:hover {
color: red;
outline: 1px solid red;
}
If you can't use a class on the li or modify the div.sub to be in the a, you're probably out of luck without Javascript:
Is there a CSS parent selector?
However, if you can, you could use:
<ul>
<li class="sub">
<a>Class #</a>
<div class="sub">#</div>
</li>
<li>
<a>Inner #
<div class="sub">#</div>
</a>
</li>
<li>
<a>None #</a>
<div class="sub">#</div>
</li>
</ul>
li.sub:hover,
li a:hover {
background: url(http://www.gravatar.com/avatar/e1122386990776c6c39a08e9f5fe5648?s=32&d=identicon&r=PG);
}
li a {
border: 1px solid blue;
display: block;
}
.sub {
border: 1px solid green;
}
http://jsfiddle.net/B7Au2/4/
I don't know if you can modify the html, but if you can, try swapping the div and the a:
<li>
<div class="sub">
#
</div>
<a >#</a>
</li>
Now you can use the adjacent sibling selector:
li a:hover, li .sub:hover + a {background:url('some-image.png')}
Unfortunately there's no way to select the previous element through CSS: that's why you need to swap your elements.

Resources