Simon
Simon

Reputation: 361

select <li> that does not have <a>

Bonjour,

I would like to make sure to always have the same padding in <li>, but when it's a link that the padding is in the <a> (for large selection area).

li a {
  padding: 1rem;
}

li:not(a) {
  padding: 1rem;
}
<ul>
  <li><a href='#'>Text</a></li>
  <li>Text</li>
  <li><a href='#'>Text</a></li>
</ul>

Upvotes: 5

Views: 99

Answers (3)

Andrew Bone
Andrew Bone

Reputation: 7291

There are few ways to do this, Mr Lister's answer is sufficient but I'm opposed to using negative margins so thought I'd offer another couple of options.

CSS Only (works in all browsers):

In this example, I've added a span around all li contents that are not <a>'s. I use calc to work out a height we want each <li>.

There is also a CSS variable, this is just so you can change the padding in one place and can be left out if need be.

:root {
  --li-padding: 1em;
}

li {
  height: calc(100% + (var(--li-padding) * 2));
  line-height: calc(100% + (var(--li-padding) * 2));
  background: tomato;
}

li>* {
  padding: 0 var(--li-padding);
}

li a {
  display: inline-block;
  background: rgba(255, 255, 255, 0.6);
}
<ul>
  <li><a href="#">Line 1</a></li>
  <li><span>Line 2</span></li>
  <li><a href="#">Line 3</a></li>
</ul>

CSS Only (works in no browsers, yet):

This is a proposed standard for CSS Level 4, currently, it's not in any browsers but I thought it worth mentioning just for future proofing.

Mozilla Documentation

li:not(::has(> a)) {
  padding: 1em;
}

li>a {
  padding: 1em;
}
<ul>
  <li><a href="#">Line 1</a></li>
  <li>Line 2</li>
  <li><a href="#">Line 3</a></li>
</ul>

Use Javascript:

Using javascript we can look through all the <li> tags and decide what we want to do depending on what they contain, here's a quick example (again I used colour to show where the <a> tags start).

let liSelector = document.querySelectorAll('li');

for (let i = 0; i < liSelector.length; i++) {
  let str = liSelector[i].innerHTML;
  if (str.includes("</a>")) {
    liSelector[i].querySelector('a').style.padding = "1em";
    liSelector[i].querySelector('a').style.display = "inline-block";
  } else {
    liSelector[i].style.padding = "1em";
  }
}
li {
  background: tomato;
}

li a {
  background: rgba(255, 255, 255, 0.6);
}
<ul>
  <li><a href="#">Line 1</a></li>
  <li>Line 2</li>
  <li><a href="#">Line 3</a></li>
</ul>

Summary: Mr Lister's answer should be all you need but I think it's good to have all your options as it helps understand the problem and solve other problems in the future, I hope you find this helpful 🙂

Upvotes: 2

Mr Lister
Mr Lister

Reputation: 46549

The solution is to use negative margins on the a, and then the a's padding will be in the same position as the li's.

li {
  padding: 1rem;
}

li a {
  margin: -1rem;
  padding: 1rem;
}
<ul>
  <li><a href='#'>Text</a></li>
  <li>Text</li>
  <li><a href='#'>Text</a></li>
</ul>

Upvotes: 6

Corentin Branquet
Corentin Branquet

Reputation: 241

Here you go in jQUery :

$('li').each(function() {
    if($(this).find('a').length) {
       $(this).addClass('extrapadding');
    }
});
.extrapadding a {
  padding: 1rem;
}

li:not(.extrapadding) {
  padding: 1rem;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul>
<li><a href='#'>Text</a></li>
<li>Text</li>
<li><a href='#'>Text</a></li>
</ul>

Upvotes: 0

Related Questions