117

I'm trying to set custom SVG icons with CSS on a <ul>'s list items. Example:

<ul>
    <li style="list-style-image: url('first.svg')">This is my first item</li>
    <li style="list-style-image: url('second.svg')">And here's my second</li>
</ul>

The problem is that the the images are too large, and stretch the height of the lines. I don't want to change the image size, because the point of using SVG is to scale with the resolution. Is there a way to set the size of the image using CSS without some sort of background-image hack?

EDIT: Here's a preview (large image deliberately chosen for illustration and drama): http://jsfiddle.net/tWQ65/4/
And my current background-image workaround, using CSS3's background-size: http://jsfiddle.net/kP375/1/

BitLooter
  • 1,295
  • 2
  • 8
  • 7
  • 1
    icon fonts are a great trick http://stackoverflow.com/questions/13129995/how-to-use-icon-fonts/13130383#13130383 and may cover some cases – Yauhen Yakimovich Feb 18 '13 at 22:36
  • 1
    Possible duplicate of [How can I make a list-style-image scale with the list's font size, when we can't use glyph fonts?](https://stackoverflow.com/questions/29932657/how-can-i-make-a-list-style-image-scale-with-the-lists-font-size-when-we-cant) – Ruskin May 11 '18 at 03:07

12 Answers12

106

I'd use:

li {
  list-style: none;
}
li::before {
  content: '';
  display: inline-block;
  height: y;
  width: x;
  background-image: url();
}
Alexander van Oostenrijk
  • 4,644
  • 3
  • 23
  • 37
Chris
  • 3,833
  • 3
  • 14
  • 11
  • 3
    didnt work, I even tried `background-size:16px auto;` – BillyNair Feb 04 '14 at 16:29
  • 6
    `background-size:contain` is the better option, but I don't know why it wouldn't work for you. All of my SVG images I have set height and width to 100%, and some browsers are funny unless you set that in the SVG. – Chris Feb 04 '14 at 21:04
  • 14
    `.ladybug{ list-style:none; } .ladybug:before{ content:''; display:inline-block; height:1em; width:1em; background-image:url(http://www.openclipart.org/people/lemmling/lemmling_Ladybug.svg); background-size:contain; background-repeat:no-repeat; }` The advantage to this is that you can resize and even animate it independently. I know it's working for me in Firefox and Chrome. – Chris Feb 04 '14 at 21:12
  • 1
    Thanks for the follow up. There is a good chance that one of the other CSS files might be messing it up. I resorted to the old school resize the image in "PhotoShop" trick... – BillyNair Feb 06 '14 at 16:43
  • Worked for me. I used a custom SVG and found it worked with and without the width and height values given in percentage terms. Some extra notes given here - https://www.w3.org/wiki/CSS/Properties/list-style-image – Afrowave Feb 18 '16 at 16:42
  • best way to accomplish this! – supersan May 01 '20 at 20:24
  • You run into problems, when your content overflows onto a second line. You will need relative positioning with a negative left. – Simon Feb 23 '21 at 16:18
68

I'm using:

li {
 margin: 0;
 padding: 36px 0 36px 84px;
 list-style: none;
 background-image: url("../../images/checked_red.svg");
 background-repeat: no-repeat;
 background-position: left center;
 background-size: 40px;
}

where background-size set the background image size.

Franky
  • 681
  • 5
  • 2
28

You can see how layout engines determine list-image sizes here: http://www.w3.org/wiki/CSS/Properties/list-style-image

There are three ways to do get around this while maintaining the benefits of CSS:

  1. Resize the image.
  2. Use a background-image and padding instead (easiest method).
  3. Use an SVG without a defined size using viewBox that will then resize to 1em when used as a list-style-image (Kudos to Jeremy).
CourtDemone
  • 5,772
  • 6
  • 23
  • 25
  • 2
    From the rules in the linked W3C document, it seems like the best solution is actually to remove the `width` and `height` declaration from the SVG file. – Jeremy Oct 22 '13 at 21:52
  • That's what I was getting at with #3, though as I said, I'm not sure how that's done exactly, seeing how SVG documents generally require X and Y coordinates based off the declared height and width of the doc. – CourtDemone Oct 23 '13 at 01:49
  • 5
    Well, if you have an SVG image with no declared width and height, but a `viewBox`, I think you'll get the desired effect. Viewing the image alone in the browser will fill the window (preserving aspect ratio), so I imagine as a `list-style-image` it would fill the available space, i.e. `1em`. – Jeremy Oct 23 '13 at 01:58
  • That sounds about right! I'm not very fluent in SVG markup, but that sounds like the wanted solution. I'll edit my initial comment. – CourtDemone Oct 23 '13 at 18:05
  • @chris actually, if you look at the [first fiddle in the question](http://jsfiddle.net/tWQ65/4/), the [image at the URL specified](https://openclipart.org/download/17678/lemmling-Ladybug.svg) now uses `viewBox` and not `width` or `height`. I'd say it's changed since the question was first asked. Does that illustrate the point I was making? – Jeremy Mar 07 '16 at 00:02
  • 2
    With the SVG solution, is there some way to specify a size other than `1em`? – Chris Martin Feb 28 '17 at 03:22
  • 2
    In Firefox 52 ESR, deleting the height and width from the SVG causes it not to render. – Ben Stern Jun 08 '18 at 06:03
17

Try using a <img /> tag instead of setting the list-style-image property. Setting the width and height properties in CSS will crop the image, but if you use a <img /> tag, the image can be re-sized using the value specified by width and height (CSS) properties or (HTML) attributes for that <img /> element.

Malekai
  • 4,765
  • 5
  • 25
  • 60
asandeep
  • 358
  • 2
  • 8
  • 27
    The problem with an image tag is that it's harder to change later if I reuse some icons for different lines. It also mixes content and presentation, something I try to avoid when I can. I'll keep it in mind if nothing else works right, though. – BitLooter Oct 15 '11 at 17:37
9

Thanks to Chris for the starting point here is a improvement which addresses the resizing of the images used, the use of first-child is just to indicate you could use a variety of icons within the list to give you full control.

ul li:first-child:before {
  content: '';
  display: inline-block;
  height: 25px;
  width: 35px;
  background-image: url('../images/Money.png');
  background-size: contain;
  background-repeat: no-repeat;
  margin-left: -35px;
}

This seems to work well in all modern browsers, you will need to ensure that the width and the negative margin left have the same value, hope it helps

Alexander van Oostenrijk
  • 4,644
  • 3
  • 23
  • 37
Stedy67
  • 99
  • 1
  • 1
5

Almost like cheating, I just went into an image editor and resized the image by half. Works like a charm for me.

James John McGuire 'Jahmic'
  • 11,728
  • 11
  • 67
  • 78
3
.your_class li {
  list-style-image: url('../images/image.svg');
}

.your_class li::marker {
  font-size: 1.5rem; /* You can use px, but I think rem is more respecful */
}
Alexander van Oostenrijk
  • 4,644
  • 3
  • 23
  • 37
ProStudio
  • 31
  • 1
1

This is a late answer but I am putting it here for posterity

You can edit the svg and set its size. one of the reasons I like using svg's is because you can edit it in a text editor.

The following is a 3232 svg which I internally resized to initially display as a 1010 image. it worked perfectly to replace the list image

<?xml version="1.0" ?><svg width="10" height="10"  id="chevron-right" viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg"><path style="fill:#34a89b;" d="M12 1 L26 16 L12 31 L8 27 L18 16 L8 5 z"/></svg>

I then simply added the following to my css

* ul {
  list-style: none;
  list-style-image: url(../images/chevron-right.svg);
}

The list-style: none; is important as it prevents the default list image from displaying while the alternate image is being loaded.

Alexander van Oostenrijk
  • 4,644
  • 3
  • 23
  • 37
DeveloperChris
  • 3,412
  • 2
  • 24
  • 39
1

Here is an example to play with Inline SVG for a list bullet (2020 Browsers)

list-style-image: url("data:image/svg+xml,
                      <svg width='50' height='50'
                           xmlns='http://www.w3.org/2000/svg' 
                           viewBox='0 0 72 72'>
                        <rect width='100%' height='100%' fill='pink'/>
                        <path d='M70 42a3 3 90 0 1 3 3a3 3 90 0 1-3 3h-12l-3 3l-6 15l-3
                                 l-6-3v-21v-3l15-15a3 3 90 0 1 0 0c3 0 3 0 3 3l-6 12h30
                                 m-54 24v-24h9v24z'/></svg>")
  • Play with SVG width & height to set the size
  • Play with M70 42 to position the hand
  • different behaviour on FireFox or Chromium!
  • remove the rect

li{
  font-size:2em;
  list-style-image: url("data:image/svg+xml,<svg width='3em' height='3em'                          xmlns='http://www.w3.org/2000/svg' viewBox='0 0 72 72'><rect width='100%' height='100%' fill='pink'/><path d='M70 42a3 3 90 0 1 3 3a3 3 90 0 1-3 3h-12l-3 3l-6 15l-3 3h-12l-6-3v-21v-3l15-15a3 3 90 0 1 0 0c3 0 3 0 3 3l-6 12h30m-54 24v-24h9v24z'/></svg>");
}

span{
  display:inline-block;
  vertical-align:top;
  margin-top:-10px;
  margin-left:-5px;
}
<ul>
  <li><span>Apples</span></li>
  <li><span>Bananas</span></li>
  <li>Oranges</li>
</ul>
Danny '365CSI' Engelman
  • 16,526
  • 2
  • 32
  • 49
1

Try this

ul {
list-style: none;
}

li::before {
content: '';
display: inline-block;
height: 20px;
width: 20px;
background-size: contain;
background-image: url("icons_res/feature_star.svg");
margin-right: 5px;
}
0

I did a kind of terminal emulator with Bootstrap and Javascript because I needed some dynamic to add easily new items, and I put the prompt from Javascript.

HTML:

  <div class="panel panel-default">
      <div class="panel-heading">Comandos SQL ejecutados</div>
      <div class="panel-body panel-terminal-body">
          <ul id="ulCommand"></ul>
      </div>
 </div>

Javascript:

function addCommand(command){
    //Creating the li tag   
    var li = document.createElement('li');
    //Creating  the img tag
    var prompt = document.createElement('img');
    //Setting the image 
    prompt.setAttribute('src','./lib/custom/img/terminal-prompt-white.png');
    //Setting the width (like the font)
    prompt.setAttribute('width','15px');
    //Setting height as auto
    prompt.setAttribute('height','auto');
    //Adding the prompt to the list item
    li.appendChild(prompt);
    //Creating a span tag to add the command
    //li.appendChild('el comando');   por que no es un nodo
    var span = document.createElement('span');
    //Adding the text to the span tag
    span.innerHTML = command;
    //Adding the span to the list item
    li.appendChild(span);
    //At the end, adding the list item to the list (ul)
    document.getElementById('ulCommand').appendChild(li);
}

CSS:

.panel-terminal-body {
  background-color: #423F3F;
  color: #EDEDED;
  padding-left: 50px;
  padding-right: 50px;
  padding-top: 15px;
  padding-bottom: 15px;
  height: 300px;
}

.panel-terminal-body ul {
  list-style: none;
}

I hope this help you.

0

I achieved it by placing the image tag before the li's:


HTML

<img src="https://www.pinclipart.com/picdir/big/1-17498_plain-right-white-arrow-clip-art-at-clipart.png" class="listImage">

CSS

.listImage {
  float:left;
  margin:2px;
  width:25px
}
.li {
  margin-left:29px;
}
Alexander van Oostenrijk
  • 4,644
  • 3
  • 23
  • 37