I have a requirement to display a hierarchy of projects. The obvious solution is a series of nested unordered lists. However, the problem I need to overcome is that the node value needs to be left aligned across the entire tree with the project name being indented as expected in a tree. Here is a sample
Project Root Node
1 Task 1
1.1 Travel
1.2 Do Work
2 Task 2
2.1 Perform Testing
2.1.1 UI Testing
2.1.2 Connection Testing
The markup is fairly simple...
<ul>
<li><span></span>Project Root Node
<ul>
<li><span>1</span>Task 1
<ul>
<li><span>1.1</span>Travel</li>
<li><span>1.2</span>Do Work</li>
</ul>
</li>
...and so on...
Turning the bullets off is easy. Left aligning every li is easy. But the problem is getting the span to stay to the left while the text after the span is properly indented and aligned for that level.
The closest I could get it was that since the span for each level has the same number of characters I could just add a right margin and that would push the following text over. The problem is that since the characters in the span vary slightly in width, the text could be one or two pixels off in vertical alignment with the row above or below.
The other solution I had was to include a "level number" class when rendering the li element along with an appropriate style that set inline-block and width. My problem with that is making sure I defined enough levels to cover any tree depth.
an ordered list with a bit of counters magic, no IE7 and below, though it degrades to an indented numbered list.
CSS
ol {
counter-reset: item;
padding: 0;
margin: 0;
margin-left: 20px !ie7;
}
ul {margin: 0; padding: 0; list-style: none;}
li {
display: block;
}
ol li:before {
display: inline-block;
content: counters(item, ".") " ";
counter-increment: item;
width: 50px;
}
ol li li:before {width: 70px;}
ol li li li:before {width: 90px;}
ol li li li li:before {width: 110px;}
and the HTML:
<ul>
<li>Project Root Node
<ol>
<li>Task 1
<ol>
<li>Travel (1.1)
<ol>
<li>Travel (1.1.1)</li>
<li>Do Work (1.1.2)</li>
</ol>
</li>
<li>Do Work (1.2)</li>
</ol>
</li>
<li>Task 2
<ol>
<li>Travel (2.1)</li>
<li>Do Work (2.2)</li>
</ol>
</li>
<li>Task 3
<ol>
<li>Travel (3.1)</li>
<li>Do Work (3.2)</li>
</ol>
</li>
</ol>
</li>
</ul>
adjust the widths of the :before psuedo elements to create the indented text
updated to make project node not numbered and include IE7 remargin
UPDATE
link to JSFiddle containing a samle of code using dls (definition lists) instead bearing in mind the need for IE7 support
JSFiddle using DL
This might be a little "hackish," but what I would do is use the nested unordered lists, as you have them, and place the spans in there as well with classes like list-level-1, list-level-2, and so on. For JavaScript-disabled browsers, it'll display as a normal nested list. Using jQuery or another JavaScript library, convert the lists into series of <div>s (with two classes like list-item-number and list-item-level-1, list-item-level-2). Set the margin-left for the latter to appropriate widths.
<div class="row"><div class="list-item-number">1</div><div class="list-item-level-1">Fruits</div></div>
<div class="row"><div class="list-item-number">1.1</div><div class="list-item-level-2">Apples</div>
<div class="row"><div class="list-item-number">1.1.1</div><div class="list-item-level-3">Red Delicious</div>
<div class="row"><div class="list-item-number">1.1.2</div><div class="list-item-level-3">Fuji</div>
You could even use a table to a similar effect (and superior semantic meaning, in my opinion), but I have had bad luck with tables and jQuery.
For a pure HTML/CSS solution, your best option is to use a table. Remember that tables aren't inherently bad -- they're just bad for layout.
To keep everything aligned correctly, I would take the spans out of normal flow by floating them and give them a negative margin. This will cause them not to affect the layout of the text unless they actually run into it. You'll need a rule for each level of the list, but that's just kind of endemic to nested lists in CSS*.
ul {
padding: 0;
margin: 0;
list-style-type: none;
}
li {
margin-left:1em;
padding-left: 0;
}
li li span {
display: block;
float: left;
margin-left: -2em;
}
li li li span { margin-left: -3em; }
I just tested it in the horribly broken IE 5 for Mac and it worked perfectly, so I assume newer versions should be OK, unlike solutions using pseudo-elements and generated content (which are stylistically superior but break in Explorer <8).
* Repetitive CSS like this can be trivially generated — a quick Ruby one-liner would be (2..10).each {|n| puts("#{'li '*n}span {margin-left: -#{n}em}")}, with 10 replaced by the number of levels
Related
So I have some code that looks like:
<ul>
<li>
<ul>
<li> ... </li>
</ul>
</li>
</ul>
This has indented itself. I have no styling to indent this. According to the computed styling there is no margin-left, yet everything is actually indented, I guess this is the default behaviour of nested ul elements?
Regardless, on every nested ul, I have a class that is called comment-children I need to say only 5 down can indent (so .comment-children .comment-children .comment-children .comment-children .comment-children done, great) but at a width of 640px, all nesting must be turned off.
The part I am having the trouble with is that the ul elements are nested by default http://jsfiddle.net/d7az0jv3/
What do you want to do
Remove all default nesting and let me nest it my self via the class comment-children
At 640px remove all nesting.
Your example is insufficient to demonstrate what you want to do involving the class comment-children, but generally, to remove the indentation on lists across browsers, you should implement the rules
ul, li { margin-left: 0; padding-left: 0; }
Here's an updated jsfiddle
If you want to only nest elements up to a certain level, my recommendation would be to apply a class to the base ul that sets the indentation, and then add a rule that stops the indentation at a certain depth below that base class. Here is an updated version of your code with the nesting stopping at level 5.
HTML:
<ul class="comment">
<li>level one</li>
<li>
<ul>
<li>level two</li>
<li>
<ul>
<li>level three</li>
(etc., up to level seven)
CSS:
ul {
list-style:none;
}
ul, li { /* reset the margin and padding */
margin: 0;
padding: 0;
}
.comment ul {
/* 1 em margin for the UL elements under .comment */
margin-left: 1em;
}
.comment ul ul ul ul ul {
/* stop the nesting! */
margin-left: 0;
}
jsfiddle for this
Is there a way to print target page numbers with hyperlinks which linked to various places within the same document?
<h1>Table of Contents</h1>
<ul>
<li>Introduction</li>
</ul>
...
<section id="introduction"> <!-- Appears, for example, on page 3 when printed -->
<h1>Introduction</h1>
...
</section>
So that the output is like:
Table of Contents (page 0)
Introduction.........................3
...
Introduction (page 3)
I only need this to work with the Google Chrome browser when printing to PDF (on OS X).
Is there some CSS or JavaScript trickery which would allow me to achieve this?
It looks like this is part of a new working draft of the CSS specification:
http://www.w3.org/TR/2014/WD-css-gcpm-3-20140513/#cross-references
I doubt that there is any browser support yet...
I have no idea if this will work in a PDF or not, but to answer the question of how this can be done in CSS:
You can generate the numbers using counter-increment on a pseudo element in css:
note that I changed your <ul> to an <ol> as this is an ordered list, whether you use the list-style or not.
ol {
counter-reset: list-counter;
}
li:after {
counter-increment: list-counter;
content: counter(list-counter);
float: right;
}
Making the little dotted line in between the text and the number takes a little more work, but you can achieve that by adding in some extra span elements and using css display: table; and display: table-cell; to lay them out properly:
<ol>
<li><span>Test</span><span class="line"></span></li>
<li><span>Test2</span><span class="line"></span></li>
<li><span>Test3</span><span class="line"></span></li>
</ol>
li {
display: table;
}
li span, li:after {
display: table-cell;
vertical-align: bottom;
}
li span.line {
border-bottom: 1px dotted #000;
width: 100%;
}
Setting the width to 100% on the span.line element, while not setting any width at all forces it to fill all of the remaining space (this is due to table-cell display elements not being allowed to break to new lines, and preventing overflow of content)
See full demo
It's not the cleanest approach to have to add the extra span elements, but it is a bit of a tricky task. Perhaps someone else will be able to take the time to think of a more efficient way to accomplish it? You could always just put an underline under the entire <li>, and skip the extra markup, at the cost of being a little less cool.
This question already has answers here:
How to remove the space between inline/inline-block elements?
(41 answers)
Closed 7 years ago.
How to you get rid of the white space between list items? I am trying to make it so that the images are right next to each other. Even though I have set the styling to margins: 0;, they are still separated.
CSS
ul.frames{
margin: 20px;
width: 410px;
height: 320px;
background-color: grey;
float: left;
list-style-type: none;
}
ul.frames li {
display:inline;
margin: 0;
display: inline;
list-style: none;
}
ul.frames li img {
margin: 0 0 0 0;
}
HTML
<li>
<img id="myImg" src="img.jpg" width="102.5px" height="80px"/>
</li>
<li>
<img id="myImg2" src="img.jpg" width="102.5px" height="80px"/>
</li>
<li>
<img id="myImg3" src="img.jpg" width="102.5px" height="80px"/>
</li>
<li>
<img id="myImg4" src="img.jpg" width="102.5px" height="80px"/>
</li>
Updated Sept. 1st, 2014
In modern browsers, flex-box is the preferred method of doing this. It's as simple as:
ul {
display: flex;
}
See a JSFiddle here.
For legacy browser support refer to the other options below, which are still just fine, albeit slightly more complex.
Though each of the other answers gives at least one good solution, none seem to provide all of the possibilities. And that's what I'll try to do here.
Firstly, to answer your implicit question of why there's spacing, it's there because you've set your LIs to display as inline elements.
inline is the default display value for text and images in all of the browsers that I know of. Inline elements are rendered with spacing between them whenever there's whitespace in your code. This is a good thing when it comes to text: these words that I've typed are spaced apart because of the space I've included in the code. And there's also space between each line. It's this very behavior of inline elements is what makes text on the web readable at all.
But sometimes we want non-text elements to be inline to take advantage of other properties of this display style. And this typically includes a desire for our elements to fit snugly together, quite unlike text. And that seems to be your problem here.
Without further ado, here are all the ways I know of to get rid of the spacing:
Keeping them inline
(Not recommended) Apply negative margin to the LIs to move them over.
li { margin: -4px; }
Note that you'll need to 'guess' the size of a space. This isn't recommended because, as Arthur excellently points out in the comments below, users can change the Zoom of their browser, which would more than likely mess up the rendering of your code. Further, this code requires too much guesswork and calculation. There are better solutions that work under all conditions.
Get rid of the whitespace
<li>One</li><li>Two</li>
Use comments to make the whitespace a comment JSFiddle
<li>One</li><!--
--><li>Two</li>
Skip the closing tag (HTML4 valid / HTML5 Valid) JSFiddle
<li>One
<li>Two
Put the whitespace in the tag itself (Note: Early Internet Explorers will not like this)
<li>One</li
><li>Two</li
>
Take advantage of the fact that the spacing between the elements is calculated as a percentage of the font size of the parent. Consequently, setting the parent's font size to 0 results in no space. Just remember to set a non-zero font-size on the li so that the text itself has a nonzero font size. View on JSFiddle.
Floating them
Float them instead. You'll probably want to clearfix the parent if you do this.
li { float: left; display: block; }
Incredible but no one here has provided the proper solution for this problem.
Just do this:
ul.frames {
font-size: 0;
}
ul.frames li {
font-size: 14px; font-size:1.4rem;
display: inline;
}
Keep in mind that we won't always have access to modify the markup. And trying to remove the spaces from the <li>s with JavaScript would be totally unnecessary when the solution is simply two font-size properties.
Also, floating the <li>s introduces another potential problem: You wouldn't be able center and right align the list items.
If you try to do float:right; on the <li>s then their order will be swapped, meaning: the first item in the list would be last, the second item is the one before the last, and so on.
Check out this other post here in SO: A Space between Inline-Block List Items
You should just remove all the spaces in the ul tags just like this: http://jsfiddle.net/dFRYL/3/
Since the <li> elements are inline, in you write spaces in or between them you will have spaces displayed.
The reason you get the spaces is because you have spaces between the elements (line break)
<ul>
<li>One</li><li>
Two</li><li>
Three</li>
</ul>
You can use negative margins like this:
margin-right: -4px;
margin-bottom: -4px;
Take a look here.
It also works up and down, I added another one to show that here.
Using display:inline; causes whitespace in your HTML to create whitespace when displaying the HTML.
There are two solutions to this:
1) Change how you make them appear inline, I would recommend using floats on all of the list items, then using a clearfix of sorts.
2) Remove all whitespace between your list items, e.g.
<li><img id="myImg" src="http://stephboreldesign.com/wp-content/uploads/2012/03/lorem-ipsum-logo.jpg" width="102.5px" height="80px"/></li><li><img id="myImg2" src="http://stephboreldesign.com/wp-content/uploads/2012/03/lorem-ipsum-logo.jpg" width="102.5px" height="80px"/></li><li><img id="myImg3" src="http://stephboreldesign.com/wp-content/uploads/2012/03/lorem-ipsum-logo.jpg" width="102.5px" height="80px"/></li><li><img id="myImg4" src="http://stephboreldesign.com/wp-content/uploads/2012/03/lorem-ipsum-logo.jpg" width="102.5px" height="80px"/></li>
Personally I would recommend option 1 (I hate display: inline)
here is my attempt at it. Hope it helps. As Sean Dunwoody mentioned, white space in your html can be a cause of the space, but I've floated the li and made the image to display:block;. Left comment on where I made changes. Hope it helps: http://jsfiddle.net/FJ3nV/
Here my small but main changes:
/*
* Added float left
*/
ul.frames li {
margin: 0;
list-style: none;
float:left;
}
/*
* Moved inline sizing here just to clear up obtrusive html.
* Added display block.
*/
ul.frames li img{width:102px; height:80px; display:block;}
I would change your li elements to inline-block.
One person did not recommend
li { margin: -4px; }
But making a slight change to it will cause it to work even when the font size changes or when the browser zooms in
li{ margin-right: -0.25em; }
That should fix that white space problem completely. However, if you are using a poorly designed font-face that doesn't follow correct letter-height standards then it may cause a problem. However those are harder to find and most of the fonts google hosts don't have that issue.
I'm using the following list:
<ol id="footnotes">
<a name="footnote1"><li></a>This is the first footnote...</li>
<a name="footnote2"><li></a>This is the second footnote...</li>
</ol>
With the following .css:
#footnotes {list-style-type: decimal;
list-style-color: #f90;
}
#footnotes li
{color: #000;
}
#footnotes a li,
#footnotes li a
{color: #f90;
}
The aim is to have the li/footer text itself black (#000), and the number styled to orange (#f90).
I've tried using the list-style-color property but this does nothing except upset the Web developer toolbar (in FF3.0.8/Ubuntu 8.04), Midori similarly doesn't display the number in orange (I thought I'd try it in the Webkit engine, just in case...).
Any ideas?
Edited the HTML (since I remembered that the tag doesn't necessarily need to enclose anything to function as an anchor):
<ol id="footnotes">
<li><a name="footnote1"></a>This is the first footnote...</li>
<li><a name="footnote2"></a>This is the second footnote...</li>
</ol>
In response to those that suggest using a <span> inside the <li>...yeah. That occurred, though I thank you for the suggestions and the time taken, but I was looking (li'l standardista that I am... ;) ) for a more...semantic option.
As it is, I think I'll probably use that approach. Though I accepted a different, Pete Michaud's, answer due to its sheer informative nature. Thanks!
There is a way in CSS3, using the Generated and Replaced Content Module. With this technique you don't have do add any extra mark-up to your HTML. Something like this should do the trick:
ol li {
list-style-type: none;
counter-increment: list;
position: relative;
}
ol li:after {
content: counter(list) ".";
position: absolute;
left: -2.5em;
width: 2em;
text-align: right;
color: red;
}
This should work:
<ol id="footnotes">
<li><span>This is the first footnote...</span></li>
<li><span>This is the second footnote...</span></li>
</ol>
#footnotes li { color: #f90; }
#footnotes li span { color: #000; }
Well, the kicker is that the numbers are technically generated inside the <li>, so anything you do to the <li> will affect the number. From the spec:
"Most block-level elements in CSS generate one principal block box.
In this section, we discuss two CSS mechanisms that cause an element
to generate two boxes: one principal block box (for the element's
content) and one separate marker box (for decoration such as a
bullet, image, or number)."
Notice that both the marker box and the principal box belong to the
same element - in this case, the list item. Accordingly, we should
expect all <li> styling to apply to both the marker and the content.
This is also not surprising if you think about it as though the list
item itself is generating the numbering content (which effectively it
is doing in CSS terms). This is confirmed later on when the spec
continues:
"The list properties allow basic visual formatting of lists. As with
more general markers, a element with 'display: list-item' generates a
principal box for the element's content and an optional marker box.
The other list properties allow authors to specify the marker type
(image, glyph, or number) and its position with respect to the
principal box (outside it or within it before content). They do not
allow authors to specify distinct style (colors, fonts, alignment,
etc.) for the list marker or adjust its position with respect to the
principal box."
So because the marker belongs to the list, it is affected by the <li> styling and isn't adjustable directly. The only way to achieve a different styling for the marker is to insert a <span> inside the list item, and style the span with the properties you want to be different from the marker.
This simple CSS3 solution works in most browsers (IE8 and up):
ul {
padding-left: 14px;
list-style: none;
}
ul li:before {
color: #f90;
content: "•";
position: relative;
left: -7px;
font-size: 18px;
margin-left: -7px;
}
You may have to adjust the padding and margin values depending on your situation.
I recently had a similar problem and found an article, Styling ordered list numbers, that describes a smart way of achieving styling of the list markers without using additional tags. The article basically says that for an ordered list:
The key is using CSS generated content to create and insert the
counter numbers after removing the default numbering from the list.
For more details please see the article.
These days you can just use ::marker;
Example:
li::marker {
color: #f90;
}
More here, including the browser compat table: https://developer.mozilla.org/en-US/docs/Web/CSS/::marker#Browser_compatibility
How about this?
<head>
<style>
#footnotes li { color: #f90; }
#footnotes li a { color: #000; }
</style>
</head>
<body>
<ol id="footnotes">
<li><a name="footnote1">This is the first footnote...</a></li>
<li><a name="footnote2">This is the second footnote...</a></li>
</ol>
</body>
Combining some of the other answers, which I found to be incomplete, I find this most complete. It considers sub style-types for different levels in the hierarchy and considers that an li may be more than one line (:after places at bottom line, so we use :before).
Note customizing of side character as well: 1. 1).Tested in Chrome.
ol { counter-reset:li; }
ol li {
list-style-type:none;
counter-increment:li;
position:relative;
}
ol li:before {
content:counter(li) ")";
position:absolute;
left: -2.6em;
width: 2em;
text-align: right;
color: #f00;
}
ol ol li:before { content:counter(li,lower-alpha) ")"; }
ol ol ol li:before { content:counter(li,lower-roman) "."; }
You can also use "outside" list-style attribute.
See here
I have an html file with an unordered list. I want to show the list items horizontally but still keep the bullets. No matter what I try, whenever I set the style to inline to meet the horizontal requirement I can't get the bullets to display.
The best option I saw in other answers was to use float:left;. Unfortunately, it doesn't work in IE7 which is a requirement here* — you still lose the bullet. I'm not really keen on using a background image either.
What I'm gonna do instead (that no one else suggested, hence the self-answer) is go with manually adding • to the my html, rather than styling this. It's less than ideal, but it's the most compatible option I found.
edit: *Current readers take note of the original post date. IE7 is unlikely to be a concern anymore.
I had the same problem, but only in Internet Explorer (I tested version 7) - not in Firefox 3 or Safari 3. Using the :before selector works for me:
ul.tabs li {
list-style: none;
float: left;
}
ul.tabs li:before {
content: '\ffed';
margin-right: 0.5em;
}
I'm using a square bullet here, but a normal bullet \2022 would work the same.
You could also use a background image on the <li> elements, with a padding to keep the text from overlapping it.
li {
background-image: url(i/bullet.gif) no-repeat center left;
padding-left: 20px;
display: inline;
}
The browser displays the bullets because the style property "display" is initially set to "list-item". Changing the display property to "inline" cancels all the special styles that list items get. You should be able to simulate it with the :before selector and the content property, but IE (at least through version 7) doesn't support them. Simulating it with a background image is probably the best cross-browser way to do it.
Keep them display blocked, give them a width and float left.
That will make them sit by side, which is like inline, and should maintain the list style.
It's actually a very simple fix. Add the following to the ul:
display:list-item;
Adding this CSS line will add the bullet points.
I was just messing around and I ran into the same issue with the same browser constraints; when I searched for an answer your post came up without the answer. This is probably too late to help you, but I thought for posterity's sake I should post it.
All I did to solve my problem was to embed another list with one item within each list item of the first list; like so...
HTML:
<div class="block-list">
<ul>
<li><ul><li>a</li></ul></li>
<li><ul><li>b</li></ul></li>
<li><ul><li>c</li></ul></li>
</ul>
</div>
CSS:
.block-list > ul > li { display: inline; float: left; }
IE7 Page:
o a o b o c
...it is a dumb solution, but it seems to work.
Did you try float: left on your <li/>? Something like this:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<head>
<style type="text/css">
ul li {
float: left;
margin-left: 2em;
}
</style>
</head>
<body>
<ul>
<li>test</li>
<li>test2</li>
</ul>
</body>
</html>
I only tested Firefox 3.0.1, works there. The margin is set because else your bullet overlaps the previous item.
addition:
Be wary that when you float the items you remove them from the normal flow, which in turn causes the <ul/> to have no height. If you want to add a border or something, you'll get weird results.
One way to fix that is to add the following to your styles:
ul {
overflow: auto;
background: #f0f;
}
You may set <ul> as a CSS grid and <li> as cells to get similar layout to inline <li> and keep bullets easily:
ul {
display: grid;
grid-template-columns: 100px 100px 100px; /* or a smarter width setting */
}
<ul>
<li>item 1</li>
<li>item 2</li>
<li>item 3</li>
</ul>
You could use Character entities, see reference : http://dev.w3.org/html5/html-author/charref
<ul class="inline-list>
<li> • Your list item </li>
</ul>
In HTML, I added a break after each li like this:
<li>Water is Sacred</li><br>
<li>Water is Sacred</li><br>
<li>Water is Sacred</li><br>
<li>Water is Sacred</li><br>
<li>Water is Sacred</li><br>
<li>Water is Sacred</li><br>
And CSS:
li { float:left; }
Using float: left didn't work very well for me because it made the content box of the ul element 0 pixels high. Flexboxes worked better:
ul {
display: flex;
flex-wrap: wrap;
}
li {
margin-right: 24px;
}
You can use following code
li {
background-image: url(img.gif) no-repeat center left;
padding-left: 20px;
display: inline;
}