Fill whole line of LI using CSS
Asked Answered
W

18

18

I have these nested ul and li . When i fill background color, nested li leaves indented portion white. I have a number of li like this that gets filled from database so i cannot give margin left to individual text in li . How can i do this so that background fills whole line along with the indentation?

Right now it looks like this

enter image description here

I want it like this

enter image description here

Any suggestions how can do this? Thanks in advance. I cannot change the html markup as i'll have to change a lot of code. Is there a way to do this using this markup. these li are coming from db query so i dont have exact number of li in this case.

Demo http://jsbin.com/uReBEVe/1/

Wilkins answered 14/12, 2013 at 21:5 Comment(5)
the image you wanted to put under "right now it looks like this" and "I want it like this" is not showing.Sheehan
Hello, HTML structure should be first of all fixed, <ul> can only have <li> as childs , your <ul> should be nested in <li> :)Lelandleler
When you say "I cannot change the HTML markup", does that mean you can't even fix the nested <ul> errors? You have to leave it as invalid HTML?Hallett
@Hallett the invalid markup is in 16+ files & don't know how many lines. Correcting it will mean starting from zero againWilkins
@Wilkins , well trying to style invalid markup, gives you chances that CSS breaks in one or many browser. Browser try themselves to fix html markup, they do not succeed always the same. You should fixe your 16 lines if you do not want to take a chance on how CSS will be applied.Lelandleler
D
4

Best thing to do is to use a structure which makes it easy for database management , html and styling(CSS) .

HTML:

<body>
<ul class="main">
    <li>1.</li>
    <li><ul>2</ul></li>
    <li><ul><li><ul>3.</ul></li></ul></li>
</ul>
</body>

CSS:

.main{
    position:relative;
    right:40px;
}
li{
    list-style:none;
    background:red;
    margin-top:1px;
}

Fiddle 1.

I dont know if ul not containing li is valid or invalid.If its invalid then you can use:

<body>
<ul class="main">
    <li>1.</li>
    <li><ul><li>2</li></ul></li>
    <li><ul><li><ul><li>3.</li></ul></li></ul></li>
</ul>
</body>

Fiddle 2

Drought answered 3/1, 2014 at 9:18 Comment(5)
This works assuming there is not a true, nested relationship desired for each line of listing (i.e. if one does not care that 3 is not nested in 2, and 2 is not nested in 1). However, you should still have another li element surrounding the text content of 2 and 3 for valid html.Drescher
@Drescher the user has asked for the output to match with the image he posted.He didnt mention that output should be acquired strictly using nesting.Drought
I partly agree, he may be open to a non-nested solution, however, he did state in the very first sentence: "I have these nested ul and li" (emphasis added), and his example was nested (though ill formed). So obviously the structure he intended to work with was a nested structure.Drescher
Yes he is using nested ul and li but he didnt ask for a nested solution.He simply is asking for the output he displayed in the question. He seems to be using it to get that output which he didnt and is the reason why he asked question in SO.Drought
Actually, he stated "I cannot change the html markup as i'll have to change a lot of code," which means even keeping his invalid (though nested) html code. So technically, he did ask for a nested solution. However, everyone answering has encouraged him to change the code to at least make it valid, and if changing the code anyway, then if nesting is not critical for him, your solution is also a valid one. I made my first comment simply to point out that html structure can matter in accurately describing the page content, and therefore it may not always be feasible to eliminate the nesting.Drescher
T
7

By default, <ul> has padding-left to accomodate the bullet point.

If you add this to your CSS:

ul {padding-left:0}
ul>li {padding-left:40px}

You should get the effect you want.

EDIT: Also you need to correct your HTML :p <ul> can ONLY have <li> as children.

Toughen answered 14/12, 2013 at 21:9 Comment(2)
tnx hey . All li are in straight line . There in no indentation jsbin.com/uReBEVe/4 . I wanted the indentation thats why put ul in ulWilkins
+1 for correct html. @Wilkins you can't put a ul inside of a ul only li are allowed in a ul. What you need to do instead is this, <li><ul>stuff goes here</ul></li>. Best of luck.Anglaangle
D
4

Flexible, Multi-Level Nesting Solution

This is very similar to another question I answered here, and I've composed a similar solution for you below. You will want valid html by having all nested li elements inside their own ul (as others have noted here), and it would be best to control all this by some class on the outermost ul (though that is not required, but makes targeting this list a whole lot easier).

The key here is supplying the background through the :before pseudo-element, which is made to span the whole width of the outermost ul.

Here is my demo jsbin.

HTML

  <ul class="full-width-list">
    <li>A</li>
    <li>
      <ul>
        <li>B</li>
        <li>
          <ul>
            <li>B</li>
          </ul>
        </li>  
      </ul>
    </li>
  </ul>

CSS

.full-width-list {
  position: relative;
  padding: 0 0 0 4px;
}

.full-width-list ul {
  margin: 0;
  padding: 0
}

.full-width-list li {
  list-style:none;
  padding: 0;
  margin: 0;
  height: 1.2em;
  line-height: 1.2em;
}

.full-width-list ul > li {
  margin-top: 4px;
  padding: 0 0 0 36px;  
}

.full-width-list li:first-child:before {
      content: '';
      height: 1.2em;
      position: absolute;
      left: 0;
      right: 0;
      z-index: -1;
      background:red;  
}

.full-width-list li:first-child:hover:before {
  background:green
}

Limitations

This solution has two main limitations:

  1. None of the ul or li elements can have a position other than the default static set on them, as the :before pseudo-element of the li elements needs to have its only positioned parent be the .full-width-list element.
  2. There has to be a set height on the li items. In my example I use 1.2em, but whatever height you set, it means that the li elements cannot go to two or more lines of text (so this solution only works with a single line of text).
Drescher answered 29/12, 2013 at 18:35 Comment(0)
D
4

Best thing to do is to use a structure which makes it easy for database management , html and styling(CSS) .

HTML:

<body>
<ul class="main">
    <li>1.</li>
    <li><ul>2</ul></li>
    <li><ul><li><ul>3.</ul></li></ul></li>
</ul>
</body>

CSS:

.main{
    position:relative;
    right:40px;
}
li{
    list-style:none;
    background:red;
    margin-top:1px;
}

Fiddle 1.

I dont know if ul not containing li is valid or invalid.If its invalid then you can use:

<body>
<ul class="main">
    <li>1.</li>
    <li><ul><li>2</li></ul></li>
    <li><ul><li><ul><li>3.</li></ul></li></ul></li>
</ul>
</body>

Fiddle 2

Drought answered 3/1, 2014 at 9:18 Comment(5)
This works assuming there is not a true, nested relationship desired for each line of listing (i.e. if one does not care that 3 is not nested in 2, and 2 is not nested in 1). However, you should still have another li element surrounding the text content of 2 and 3 for valid html.Drescher
@Drescher the user has asked for the output to match with the image he posted.He didnt mention that output should be acquired strictly using nesting.Drought
I partly agree, he may be open to a non-nested solution, however, he did state in the very first sentence: "I have these nested ul and li" (emphasis added), and his example was nested (though ill formed). So obviously the structure he intended to work with was a nested structure.Drescher
Yes he is using nested ul and li but he didnt ask for a nested solution.He simply is asking for the output he displayed in the question. He seems to be using it to get that output which he didnt and is the reason why he asked question in SO.Drought
Actually, he stated "I cannot change the html markup as i'll have to change a lot of code," which means even keeping his invalid (though nested) html code. So technically, he did ask for a nested solution. However, everyone answering has encouraged him to change the code to at least make it valid, and if changing the code anyway, then if nesting is not critical for him, your solution is also a valid one. I made my first comment simply to point out that html structure can matter in accurately describing the page content, and therefore it may not always be feasible to eliminate the nesting.Drescher
A
4

You can do this with :before hack as you have no access to the code

Working jsBin Demo

CSS

li{list-style:none;background:red;margin-top:4px; }
li:hover{background:green}
li:hover:before {background:green}
li:before {background:red; width:100%; content:'.'; position:absolute; left:0; z-index: -1;}
Alien answered 3/1, 2014 at 10:42 Comment(0)
J
3

This works at arbitrary depths without hacks or nonsense.

The people saying "can't" and "impossible" in this thread really need to learn what those words mean with respect to CSS (generally, "haven't figured out how yet.") :)

The idea is simple: set a :before selector which fits the left and right edges by absolute positioning and paints a background color. You need to set a z-index: to put it behind its content, a content: '\0020' to force it to paint (that's a non-breaking space,) and you're good.

You can bound this by setting it inside a position: relative container.

<!doctype html>
<html>

  <head>

    <style>

      li { 
          list-style-type : none; 
          margin-bottom   : 0.25em;
      }

      li:before { 
          position         : absolute; 
          left             : 0;
          right            : 0;
          background-color : #eef;
          content          : "\00a0";
          z-index          : -1;
      }

    </style>

  </head>

  <body>

    <ul>
      <li>Test</li>
      <li><ul>
        <li>Test</li>
        <li><ul>
          <li>Test</li>
        </ul></li>
      </ul></li>
    </ul>

  </body>

</html>
Johm answered 2/1, 2014 at 22:14 Comment(2)
This is the only solution that solved my case. Thank you very much :DPostage
Actually not, since it doesn't work if you need to scrollPostage
M
2

Your markup is broken, you should nest li in a single ul like this:

<ul>
   <li>Text</li>
   <li>Text 1</li>
</ul>

This was your markup

<ul>
  <li>A</li>
  <ul>
    <li>B</li>
    <ul>
      <li>B</li>
    </ul>
  </ul>
<ul>

I assume you see why this is wrong.

I've fixed the JSBin for you and it has the correct effect.

EDIT: You could of course add the padding-left by looping over all lis using javascript.

Mcmillon answered 14/12, 2013 at 21:11 Comment(5)
i want the indentation. How can i do it?Wilkins
Use padding-left on the lis. You'll need different padding for each though.Mcmillon
there a lot of li which i'm fetching from database. Not possible to assign PL to every LIWilkins
You could add the offset based on the row in the database. A formula like rowIndex * 20 could give you this behaviourMcmillon
It's also possible to nest ols to achieve this behaviour, but it's much easier to use padding-left. Demo here jsfiddle.net/bJxs5/1Mcmillon
T
2

You could not be sure enough about browser consistency until markup cleanup and consistency, sad but true. All the suggestions from above looks good, there is bit of alternative from my practical view.

The markup:

  <ul>
    <li>A</li>
    <li><p>B</li>
    <li><p><p>B</li>
    <li><p><p><p>B</li>
    ....
  </ul>

And CSS:

li p {
  padding-left: 1em;
  display: inline;
}

JSbin

p tag is optional to close in HTML subset, and generally should works in every browser anyway no matter of doctype. In case you are on xHTML and worry about validation an option could be using closing tags like:

  <ul>
    <li>A</li>
    <li><p></p>B</li>
    <li><p></p><p></p>B</li>
    ....
  </ul>
Tricycle answered 4/1, 2014 at 1:14 Comment(0)
P
1

Try this:

<ul class="lvl1">
  <li>A</li>
  <ul class="lvl2"><li>B</li>
   <ul class="lvl3"><li>B</li></ul>
    </ul>
</ul>

li {
  background: none repeat scroll 0 0 #FF0000;
  list-style: none outside none;
  margin-top: 4px;
}
ul { padding:0px;}
ul.lvl1>li {padding-left:30px;}
ul.lvl2>li {padding-left:60px;}
ul.lvl3>li {padding-left:90px;}

See here: http://jsfiddle.net/x5K4a/

Pyretic answered 14/12, 2013 at 21:21 Comment(0)
O
1

1) Your HTML is invalid (missing <li> around <ul>)

2) The only way to make indentation work as you expected is a CSS rule for each level.

ul ul li.line { padding-left: 20px !important }
ul ul ul li.line { padding-left: 40px !important; }
...

http://jsbin.com/uReBEVe/12/edit

Osteotomy answered 28/12, 2013 at 22:21 Comment(0)
L
1

if it is just a matter of background-color, you can use a shadow of same color. http://codepen.io/gc-nomade/pen/fxBAl (html structure fixed)

<ul class="ulparent">
  <li>
    <p>A</p>
    <ul>
      <li>
        <p>B</p>
        <ul>
          <li>
            <p>B</p></li>
        </ul>
      </li>
    </ul>
  </li>
</ul>
.ulparent {overflow:hidden;}
li p {background:green;box-shadow:-200px 0 0 green;/* -200px for instance or whatever suits your need */margin:4px 0;}
li p:hover {background:red;box-shadow:-200px 0 0 red;}

Else, if it is a background-image, i would use pseudo-element and background-attachment:fixed;(demo included in codepen , using a linear-gradient as image )

Lelandleler answered 1/1, 2014 at 17:4 Comment(0)
A
1

I am going to give you the proper idea how to apply css rules over the HTML contents.Below the css rules I have created just copy it and see the answer.It is the child combinator which I used!I inspect whole the answers provided by the different users which is not followed the css rules at all. Just let me know! Hope the answer!

<!DOCTYPE html>
<html>
<head>
<title>Test</title>

<style type="text/css">
li{
  list-style:none;
  background:red;
  margin-top:4px;

}
body>ul>ul>li{
  margin: 4px 0 0 -40px;
  }
body>ul>ul>ul>li{
  margin: 4px 0 0 -80px;
  }
body>ul>ul>li {
   padding:0px 0px 0px 40px;
}
body>ul>ul>ul>li{
  padding:0px 0px 0px 80px;
}
li:hover{
        background:green;
        }
</style>
</head>
<body>
  <ul>
    <li>A</li>
    <li>
      <ul>
      <li>B</li>
      <li>
        <ul>
            <li>C</li>
        </ul>
      </li>
      </ul>
    </li>
  </ul>
</body>
</html>

Save the image at first to your local drive or drag and drop this image into the new tab browser to see more visible.

enter image description here

Asceticism answered 1/1, 2014 at 21:21 Comment(2)
I don't have only 3 ul , i have many. By this way i'll have to change css of evry ul. I dont know how many there will beWilkins
@AsrafulHaque you can't request the op to upvote you based on how long you have spent on the answer (shouldn't have took that long anyway). If it's useful to him he will upvote itDebut
B
1

You can add this CSS in your code to get your desired results:

li {
    list-style: none;
    background: red;
    margin-top: 4px;
}
ul {
    padding: initial !important;
}

ul ul li {
    padding-left: 40px;
}
ul ul ul li {
    padding-left: 80px;
}
li:hover {
    background: green;
}

Result on jsbin is here: http://jsbin.com/uReBEVe/33/edit

Berkley answered 2/1, 2014 at 8:0 Comment(1)
I don't have only 3 ul , i have many. By this way i'll have to change css of evry ul. I dont know how many there will beWilkins
T
1

Here is the proper HTML structure that you should follow, with each UL element having two LI elements. One for the value of each line and one as the parent for the next indented value.

<ul>
    <li>A</li>
    <li>
        <ul>
          <li>B</li>
          <li>
              <ul>
                <li>C</li>
              </ul>
          </li>
        </ul>
     <li>  
</ul>

For the CSS, this solution requires you to have a max number of 'levels' in your list hierarchy (see code comment)

li {
    list-style:none;
    padding-left:0px;
    box-sizing:border-box;
}

ul {
    padding-left:0
}

ul > li:nth-of-type(1):hover {
    background:green
}

ul li:nth-of-type(1) {
    padding-left:50px;
    background:red;
    margin-top:4px
}

ul li li:nth-of-type(1) {
    padding-left:100px;
}

ul li li li:nth-of-type(1) {
    padding-left:150px;
}

/* 
   Continue incrementing the padding for the li 
   children for however many levels you want
*/

Make note, the nth-of-type selector is supported by all browsers EXCEPT for IE8 and below.

See JSBin for working example: http://jsbin.com/uReBEVe/51

Good luck!

Trilemma answered 2/1, 2014 at 18:51 Comment(0)
P
1

Both UL and OL inherit margins. Your fix would be to zero out the margin:

ul, ol    
{   
   margin:0;
}
Pettit answered 3/1, 2014 at 1:6 Comment(0)
S
1

A very very fiddly jsfiddle but it works with a little nudge in the right direction from jQuery. Not a great resolve but a resolve none the less.

HTML

<ul>
    <li>A</li>
        <ul>
            <li>B</li>
                <ul>
                    <li>B</li>
               </ul>
        </ul>
</ul>

CSS

ul {
    list-style-type:none;
    margin-top:5px;
    padding-left:40px;
    float:left;
    width:400px;
    overflow:hidden;
    background:#ff0000;
}
li {
    padding-top:5px;
}
ul div {
    position:absolute;
    left:0;
    width:100%;
    border-top:3px solid #fff;
}

jQuery

$(document).ready(function(){
    $('ul').prepend('<div></div>');
});

jsFiddle here. Hopefully this works for you!

Spermatozoon answered 3/1, 2014 at 23:44 Comment(0)
M
1

@AsrafulHaque has the correct idea about using padding to extend the background width without changing nesting indents.

However, because you don't know how many < li> there will be, you can't expect this to be a pure CSS solution.

You're attempting to do a pretty awkward thing but it would be possible to loop over them and inject dynamic padding using javascript/jquery or something:

i = 40;
$('img.yourImageClass').each(function() {
    $(this).css('padding-left', i+'px');
    i = i + 40;
});

You could also do this type of injection with pre-processing on the server side I am sure, but definitely not with CSS alone. You need a dynamic solution (i.e. the ability to use variables) to support your dynamic output.

Malik answered 4/1, 2014 at 0:7 Comment(0)
B
1

You can do like this

HTML

 <!DOCTYPE html>
<html>
<head>
<meta charset=utf-8 />
<title>JS Bin</title>
</head>
<body>
  <ul class="mainUL">
  <li>A</li>
  <ul><li>B</li>
   <ul><li>C</li></ul>
    </ul>
  </ul>
</body>
</html>

CSS Code

li{list-style:none;background:red;margin-top:4px; }
li:hover{background:green}
li:hover:before {background:green}
li:before {background:red; width:100%; content:'.'; position:absolute;left:0; z-index: -1;color:red;}
.mainUL {padding-left: 0px;}

You can see the working demo : http://jsbin.com/uReBEVe/71/edit

Berkley answered 4/1, 2014 at 11:35 Comment(0)
W
0

from your demo:

if you apply

ul{ padding:0; margin:0; }

everything sits flush to the wall like you want.

if you want text indents

ul ul li{ text-ident:20px; }

which is nesting. will only targets li's that are in ul's that are nested in ul's. then what you want works and you don't need to change your code

you can also keep nesting that code

add more ul's and li's depending on the depth of your structure, but this should give you a very good base

Wastage answered 4/1, 2014 at 17:55 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.