Apply CSS style to parent only if there are child elements

I am making a menu using an ul, however I want to be able to reuse the CSS.

What I am trying to do is add some sort of visual indicator to a li that contains child elements, in the case:


<ul>
	<li id="haschild" >
		<ul>
			<li></li>
			<li></li>
		</ul>
	</li>
	<li></li>
	<li></li>
	<li></li>
	<li></li>
	<li id="haschild" >
		<ul>
			<li></li>
			<li></li>
		</ul>
	</li>
</ul>

On the previous code I cold just add some CSS properties to the id haschild however I want to know if there is a way to add the rules without the id, something like li:first-child but for parent, I already searched for that and I know it does not exist even in CSS3 but is there an alternative?

Firstly, you can only use an id once on a page, so you’d have to use a class there instead of an id.

But no, you can’t style a parent on the basis of a child in CSS. You can with JavaScript, but I’d say it’s better not to rely on that for something as simple as this. Add a special class to each LI that has a sub UL.

I added the id as an example just to be as clear as possible on what I am trying to do

Yes, it is “possible”. Put the visual information on an appropriate (pseudo) child element.

For instance:

ul ul {}
ul ul:before {}

I offered a similar solution in a previous thread and relies on absolutely placing an element from the child into position on the parent.

It does rely on a certain structure and can be quite tricky in a drop down because it is has its own positioning context.

I’m assuming this thread is a continuation of tlacaelelrl’s previous thread so I have used the code from there to provide a rough example.


<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<style type='text/css'  media='all'>
/*
Root elements START
*/
#menu {
    height:25px;
    margin:5px;
}
#menu ul {
    list-style:none;
    margin:0;padding:0;
}
#menu ul li {
    height:23px;
    width:50px;
    float:left;
    background-image:url('../images/menu_border.png');
    background-repeat:no-repeat;
    padding:2px 6px 0 16px;
    color:#33588a;
    font-weight:bold;
    position:relative;
        border:1px solid #000;
        background:#fcf;
}
#menu ul li:hover {
    background-image:url('../images/menu_border_hover.png');
}
/*
Root elements END
Child elements level 1 START
*/
#menu ul ul{
    position:absolute;
    left:0;
    top:25px;
    margin-left:-999em;
    z-index:1;
}
#menu ul ul li {
    color:#33588a;
    font-weight:bold;
    border:solid 2px brown;
    border-top:none;
    background-image:none;
    background:beige;
}
#menu ul ul li:first-child {
    border-top:solid 2px brown;
}
#menu ul li:hover ul {
    margin-left:0;
}
#menu ul li:hover ul li:hover {
    background-image:none;
}
.tlak_last_li li {
    border-top:solid 2px brown;
}
#menu ul li li {
    clear:left
}
/*
Child elements level 1 END
*/

[B]#menu ul ul:before{
    content:" ";
    border-top:5px dashed transparent;
    border-bottom:5px dashed transparent;
    border-left:5px solid #f00;
    height:0;
    width:0;
    display:block;
    overflow:hidden;
    position:absolute;
    margin-left:999em;
    top:-16px;
    left:80%;
}
#menu ul li:hover ul:before{
    border-left:5px dashed transparent;
    border-right:5px dashed transparent;
    border-top:5px solid red;
    margin-left:0;
    top:-14px;
    left:78%;
}[/B]

</style>
</head>
<body>
<div id="menu" >
    <ul>
        <li>one
            <ul>
                <li>one</li>
                <li>one</li>
                <li>one</li>
            </ul>
        </li>
        <li>two
            <ul>
                <li>two</li>
                <li>two</li>
                <li>two</li>
            </ul>
        </li>
        <li>three</li>
        <li>four</li>
        <li>five</li>
    </ul>
</div>
some text
</body>

That provides an arrow made with css borders that is positioned into the top level list and turns into a down pointing arrow on hover.

This will only work in IE8+ as IE7 has no support for :before.

I should clarify in case there’s some doubt that :before does not mean before the element concerned. It means before any content that the element concerned contains.

e.g.


<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Untitled Document</title>
<style type="text/css">
p:before{content:"test"}
</style>
</head>
<body>
<p>Start Paragraph</p>
</body>
</html>


The above would add the word test before any content in the paragraph.

e.g. The output would be this

testStart Paragraph